def test_Ethernet_unpack(self): """Test pack method of Ethernet class without VLAN tag.""" raw = b'\x00\x15\xaf\xd58\x98\x00\x1f:>\x9a\xcf\x08\x00testdata' expected = Ethernet(destination='00:15:af:d5:38:98', source='00:1f:3a:3e:9a:cf', ether_type=0x800, data=b'testdata') expected.pack() unpacked = Ethernet() unpacked.unpack(raw) self.assertEqual(unpacked, expected)
def test_Tagged_Ethernet_unpack(self): """Test pack method of Ethernet class including VLAN tag.""" raw = b'\x00\x15\xaf\xd58\x98\x00\x1f:>' raw += b'\x9a\xcf\x81\x00!^\x08\x00testdata' expected = Ethernet(destination='00:15:af:d5:38:98', source='00:1f:3a:3e:9a:cf', vlans=[VLAN(pcp=1, vid=350)], ether_type=0x800, data=b'testdata') expected.pack() unpacked = Ethernet() unpacked.unpack(raw) self.assertEqual(unpacked, expected)
def break_packet(pkt): ethernet = Ethernet() ethernet.unpack(pkt) ether_type = ethernet.ether_type offset = 0 if ethernet.ether_type == constants.VLAN: vlan = VLAN() vlan.unpack(ethernet.data.value) ether_type = vlan.ether_type offset += constants.VLAN_LEN else: vlan = None ip = None if ether_type == constants.IPv4: ip = IPv4() ip.unpack(ethernet.data.value, offset) offset += ip.length elif ether_type == 'IPv6': #TODO pass tp = None if ether_type == constants.IPv4: #TODO: add IPv6 with an or if ip.protocol == constants.TCP: tp = TCP() tp.parse(ethernet.data.alue, offset) offset += tp.length elif ip.protocol == constants.UDP: tp = UDP() tp.parse(ethernet.data.alue, offset) offset += tp.length return ethernet, vlan, ip, tp
def handle_packet_in(self, event): """Handle PacketIn Event. Install flows allowing communication between switch ports. Args: event (KytosPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] ethernet = Ethernet() ethernet.unpack(packet_in.data.value) # Ignore LLDP packets or packets not generated by table-miss flows if (ethernet.destination in settings.lldp_macs or packet_in.reason != PacketInReason.OFPR_NO_MATCH): return # Learn the port where the sender is connected in_port = packet_in.in_port.value switch = event.source.switch switch.update_mac_table(ethernet.source, in_port) ports = switch.where_is_mac(ethernet.destination) # Add a flow to the switch if the destination is known if ports: flow_mod = FlowMod() flow_mod.command = FlowModCommand.OFPFC_ADD flow_mod.match = Match() flow_mod.match.dl_src = ethernet.source.value flow_mod.match.dl_dst = ethernet.destination.value flow_mod.match.dl_type = ethernet.ether_type flow_mod.actions.append(ActionOutput(port=ports[0])) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_flow_mod'), content={ 'destination': event.source, 'message': flow_mod }) self.controller.buffers.msg_out.put(event_out) # Send the packet to correct destination or flood it packet_out = PacketOut() packet_out.buffer_id = packet_in.buffer_id packet_out.in_port = packet_in.in_port packet_out.data = packet_in.data port = ports[0] if ports else Port.OFPP_FLOOD packet_out.actions.append(ActionOutput(port=port)) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_packet_out'), content={ 'destination': event.source, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out)
def packet_in(event, packet_in_msg): """ Process OpenFlow 1.0 PacketIn messages Args: event: PacketIN event packet_in_msg: PacketIn msg Return: ethernet: PacketIn data in_port: in_port switch: OpenFlow datapath 0, 0, 0 if it is not a trace probe """ ethernet = Ethernet() ethernet.unpack(packet_in_msg.data.value) if settings.COLOR_VALUE in ethernet.source.value: log.debug("OpenFlow 1.0 PacketIn Trace Msg Received") in_port = packet_in_msg.in_port.value switch = event.source.switch return ethernet, in_port, switch log.debug("PacketIn is not a Data Trace Probe") return 0, 0, 0
def update_links(self, event): """Dispatch 'reacheable.mac' event. Listen: `kytos/of_core.v0x0[14].messages.in.ofpt_packet_in` Dispatch: `reachable.mac`: { switch : <switch.id>, port: <port.port_no> reachable_mac: <mac_address> } """ ethernet = Ethernet() ethernet.unpack(event.message.data.value) name = 'kytos/of_topology.reachable.mac' content = { 'switch': event.source.switch.id, 'port': event.message.in_port, 'reachable_mac': ethernet.source } event = KytosEvent(name, content) self.controller.buffers.app.put(event) msg = 'The MAC %s is reachable from switch/port %s/%s.' log.debug(msg, ethernet.source, event.source.switch.id, event.message.in_port)
def test_Tagged_Ethernet_pack(self): """Test pack method of Ethernet class including VLAN tag.""" ethernet = Ethernet(destination='00:1f:3a:3e:9a:cf', source='00:15:af:d5:38:98', vlans=[VLAN(vid=200)], ether_type=0x800, data=b'testdata') packed = ethernet.pack() expected = b'\x00\x1f:>\x9a\xcf\x00\x15\xaf\xd58' expected += b'\x98\x81\x00\x00\xc8\x08\x00testdata' self.assertEqual(packed, expected)
def get_vlan_from_pkt(data): ethernet = Ethernet() ethernet.unpack(data) vlan = VLAN() vlan.unpack(ethernet.data.value) return vlan.vid
def handle_packet_in(self, event): """Handle PacketIn Event. Install flows allowing communication between switch ports. Args: event (KytosPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] ethernet = Ethernet() ethernet.unpack(packet_in.data.value) # Ignore LLDP packets or packets not generated by table-miss flows if (ethernet.destination in settings.LLDP_MACS or packet_in.reason != PacketInReason.OFPR_NO_MATCH): return switch = event.source.switch version = switch.ofp_version # Learn the port where the sender is connected if version == '0x01': in_port = packet_in.in_port.value else: in_port = packet_in.in_port switch.update_mac_table(ethernet.source, in_port) ports = switch.where_is_mac(ethernet.destination) # Add a flow to the switch if the destination is known if ports: flow_mod = self._create_flow_mod(version, ethernet, ports[0]) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_flow_mod'), content={ 'destination': event.source, 'message': flow_mod }) self.controller.buffers.msg_out.put(event_out) # Send the packet to correct destination or flood it packet_out = self._create_packet_out(version, packet_in, ports) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_packet_out'), content={ 'destination': event.source, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out)
def _get_vlan_from_pkt(data): """ Get VLAN ID from frame. Used for VLAN Translation Args: data: Ethernet Frame Returns: VLAN VID """ ethernet = Ethernet() ethernet.unpack(data) vlan = ethernet.vlans[0] return vlan.vid
def test(self, event): from pyof.v0x04.asynchronous.packet_in import PacketIn msg = event.content['message'] assert isinstance(msg, PacketIn) eth = Ethernet() eth.unpack(msg.data.value) log.debug('ethernet type=%s'%str(eth.ether_type)) if eth.ether_type == EtherType.IPV4: ipv4 = IPv4() ipv4.unpack(eth.data.value) log.debug(ipv4.source) log.debug(ipv4.destination)
def handle_packet_in(self, event): """Handle PacketIn Event. Install flows allowing communication between switch ports. Args: event (KytosPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] ethernet = Ethernet() ethernet.unpack(packet_in.data.value) # Ignore LLDP packets or packets not generated by table-miss flows if (ethernet.destination in settings.LLDP_MACS or packet_in.reason != PacketInReason.OFPR_NO_MATCH): return switch = event.source.switch version = switch.ofp_version # Learn the port where the sender is connected in_port = getattr(packet_in.in_port, 'value', packet_in.in_port) switch.update_mac_table(ethernet.source, in_port) ports = switch.where_is_mac(ethernet.destination) # Add a flow to the switch if the destination is known if ports: flow = self._create_flow(ethernet, ports[0]) destination = switch.id endpoint = f'{settings.FLOW_MANAGER_URL}/flows/{destination}' data = {'flows': [flow]} requests.post(endpoint, json=data) # Send the packet to correct destination or flood it packet_out = self._create_packet_out(version, packet_in, ports, switch) if packet_out is None: return event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_packet_out'), content={ 'destination': event.source, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out)
def handle_packet_in(self, event): """ Receives PacketIn msgs and search from trace packets. Args: event (KycoPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] in_port = packet_in.in_port.value switch = event.source.switch ethernet = Ethernet() ethernet.unpack(packet_in.data.value) if settings.COLOR_VALUE in ethernet.source.value: self.tracing.process_probe_packet(event, ethernet, in_port, switch)
def execute(self): """Send LLDP Packets every 'POLLING_TIME' seconds to all switches.""" switches = list(self.controller.switches.values()) for switch in switches: try: of_version = switch.connection.protocol.version except AttributeError: of_version = None if not (switch.is_connected() and of_version in [0x01, 0x04]): continue for interface in switch.interfaces.values(): # Avoid ports with speed == 0 if interface.port_number == 65534: continue lldp = LLDP() lldp.chassis_id.sub_value = DPID(switch.dpid) port_type = UBInt16 if of_version == 0x01 else UBInt32 lldp.port_id.sub_value = port_type(interface.port_number) ethernet = Ethernet() ethernet.ether_type = EtherType.LLDP ethernet.source = interface.address ethernet.destination = constants.LLDP_MULTICAST_MAC ethernet.data = lldp.pack() packet_out = self.build_lldp_packet_out( of_version, interface.port_number, ethernet.pack()) if packet_out is not None: name = 'kytos/of_lldp.messages.out.ofpt_packet_out' content = { 'destination': switch.connection, 'message': packet_out } event_out = KytosEvent(name=name, content=content) self.controller.buffers.msg_out.put(event_out) log.debug("Sending a LLDP PacketOut to the switch %s", switch.dpid)
def _create_ethernet_frame(trace_entries, color): """ Create an Ethernet frame using TraceEntries and color (dl_src) Args: trace_entries: TraceEntries provided by user or collected from PacketIn color: field and value that indicate the color Returns: ethernet frame """ ethernet = Ethernet() ethernet.ether_type = trace_entries.dl_type ethernet.source = color['color_value'] ethernet.destination = trace_entries.dl_dst vlan = VLAN(vid=trace_entries.dl_vlan, pcp=trace_entries.dl_vlan_pcp) ethernet.vlans.append(vlan) return ethernet
def update_links(event): """Receive a kytos event and update links interface. Get the event kytos/of_core.messages.in.ofpt_packet_in and update the interface endpoints, ignoring the LLDP packages. Parameters: event (KytosEvent): event with Ethernet packet. """ ethernet = Ethernet() ethernet.unpack(event.message.data.value) if ethernet.ether_type != constants.LLDP_ETHERTYPE: port_no = event.message.in_port hw_address = ethernet.source switch = event.source.switch interface = switch.get_interface_by_port_no(port_no.value) if interface is not None and \ not interface.is_link_between_switches(): interface.update_endpoint(hw_address)
def execute(self): """Implement a loop to check switches liveness.""" switches = list(self.controller.switches.values()) for switch in switches: if not (switch.is_connected() and switch.connection.protocol.version == 0x01): continue # Gerar lldp para cada uma das portas do switch # Gerar o hash de cada um dos pacotes e armazenar for port in switch.features.ports: output_action = ActionOutput() output_action.port = port.port_no # Avoid ports with speed == 0 if port.port_no.value == 65534: continue ethernet = Ethernet() ethernet.ether_type = constants.LLDP_ETHERTYPE ethernet.source = port.hw_addr ethernet.destination = constants.LLDP_MULTICAST_MAC lldp = LLDP() lldp.chassis_id.sub_value = DPID(switch.dpid) lldp.port_id.sub_value = port.port_no ethernet.data = lldp.pack() packet_out = PacketOut() packet_out.actions.append(output_action) packet_out.data = ethernet.pack() event_out = KytosEvent() event_out.name = 'kytos/of_lldp.messages.out.ofpt_packet_out' event_out.content = {'destination': switch.connection, 'message': packet_out} self.controller.buffers.msg_out.put(event_out) log.debug("Sending a LLDP PacketOut to the switch %s", switch.dpid)
def update_links(self, message, source): """Dispatch 'reacheable.mac' event. Args: message: python openflow (pyof) PacketIn object. source: kytos.core.switch.Connection instance. Dispatch: `reachable.mac`: { switch : <switch.id>, port: <port.port_no> reachable_mac: <mac_address> } """ ethernet = Ethernet() ethernet.unpack(message.data.value) if ethernet.ether_type in (EtherType.LLDP, EtherType.IPV6): return try: port = source.switch.get_interface_by_port_no( message.in_port.value) except AttributeError: port = source.switch.get_interface_by_port_no(message.in_port) name = 'kytos/of_core.reachable.mac' content = { 'switch': source.switch, 'port': port, 'reachable_mac': ethernet.source.value } event = KytosEvent(name, content) self.controller.buffers.app.put(event) msg = 'The MAC %s is reachable from switch/port %s/%s.' log.debug(msg, ethernet.source, source.switch.id, message.in_port)
def get_vlan_from_pkt(data): ethernet = Ethernet() ethernet.unpack(data) return ethernet.vlan.vid
def execute(self): """Send LLDP Packets every 'POLLING_TIME' seconds to all switches.""" switches = list(self.controller.switches.values()) for switch in switches: try: of_version = switch.connection.protocol.version except AttributeError: of_version = None if not switch.is_connected(): continue if of_version == 0x01: port_type = UBInt16 local_port = Port10.OFPP_LOCAL elif of_version == 0x04: port_type = UBInt32 local_port = Port13.OFPP_LOCAL else: # skip the current switch with unsupported OF version continue interfaces = list(switch.interfaces.values()) for interface in interfaces: # Avoid the interface that connects to the controller. if interface.port_number == local_port: continue lldp = LLDP() lldp.chassis_id.sub_value = DPID(switch.dpid) lldp.port_id.sub_value = port_type(interface.port_number) ethernet = Ethernet() ethernet.ether_type = EtherType.LLDP ethernet.source = interface.address ethernet.destination = constants.LLDP_MULTICAST_MAC ethernet.data = lldp.pack() # self.vlan_id == None will result in a packet with no VLAN. ethernet.vlans.append(VLAN(vid=self.vlan_id)) packet_out = self._build_lldp_packet_out( of_version, interface.port_number, ethernet.pack()) if packet_out is not None: event_out = KytosEvent( name='kytos/of_lldp.messages.out.ofpt_packet_out', content={ 'destination': switch.connection, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out) log.debug("Sending a LLDP PacketOut to the switch %s", switch.dpid) msg = '\n' msg += 'Switch: %s (%s)\n' msg += ' Interfaces: %s\n' msg += ' -- LLDP PacketOut --\n' msg += ' Ethernet: eth_type (%s) | src (%s) | dst (%s)\n' msg += ' LLDP: Switch (%s) | port (%s)' log.debug(msg, switch.connection.address, switch.dpid, switch.interfaces, ethernet.ether_type, ethernet.source, ethernet.destination, switch.dpid, interface.port_number)
def packet_in(self, event): self.lock.acquire() from pyof.v0x04.asynchronous.packet_in import PacketIn msg = event.content['message'] assert isinstance(msg, PacketIn) eth = Ethernet() eth.unpack(msg.data.value) #log.info('ethernet type=%s'%str(eth.ether_type)) switch = event.source.switch in_port = msg.in_port # if eth.ether_type != 35020: # log.info('ethernet type=%s'%str(eth.ether_type)) if eth.ether_type == EtherType.IPV4: ipv4 = IPv4() ipv4.unpack(eth.data.value) if ipv4.destination == '10.0.0.254': pass #only for host locate # role = HOST_ROLE[ipv4.source] # self.nodes[ipv4.source] = {'role': role} # # h_id = ipv4.source # s_id = str(switch.dpid) + ":" + str(in_port) # # h2s_id = h_id + "+" + s_id # s2h_id = s_id + "+" + h_id # self.edges[h2s_id] = {'src': h_id, 'dst': s_id} # self.edges[s2h_id] = {'src': s_id, 'dst': h_id} # #TODO: need to handle host mobility # print(self.nodes) # print(self.edges) # if not self.debug: # pass # self.trident.set_topology(self.nodes, self.edges) else: sip = ipv4.source dip = ipv4.destination ipproto = ipv4.protocol sport = None dport = None # allow_ip = ["10.0.0.1","10.0.0.2","10.0.0.3"] # if sip not in allow_ip: # return # if dip not in allow_ip: # return allow_pair = [("10.0.0.2", "10.0.0.3"), ("10.0.0.2", "10.0.0.1")] if (sip, dip) not in allow_pair: self.lock.release() return if ipproto == 6: ipproto = "tcp" elif ipproto == 17: ipproto = "udp" else: ipproto = "unknown" if ipproto == "tcp": tcph = unpack('!HHLLBBHHH', eth.data.value[20:40]) sport = tcph[0] dport = tcph[1] elif ipproto == "udp": udph = unpack('!HHHH', eth.data.value[20:28]) sport = udph[0] dport = udph[1] else: self.lock.release() return log.info("sip:" + str(sip) + "dip:" + str(dip) + str(ipproto) + "sport" + str(sport) + "dport" + str(dport)) pkt = TridentPacket(sip, dip, sport, dport, ipproto) if not self.debug: log.info('start to call trident new_pkt') self.trident.new_pkt(pkt) self.lock.release()
def generate_trace_pkt(entries, color, r_id, my_domain): """ Receives the REST/PUT to generate a PacketOut data needs to be serialized. Args: entries: color: result from Coloring Napp for a specific DPID r_id: my_domain: Returns: in_port: pkt: """ trace = {} switch = {} eth = {} ip = {} tp = {} # TODO Validate for dl_vlan. If empty, return error. # Default values dpid, in_port = 0, 65532 if color['color_field'] == 'dl_src': dl_src = color['color_value'] else: dl_src = '0e:55:05:0e:55:05' dl_dst = "ca:fe:ca:fe:ca:fe" dl_vlan, dl_type, dl_vlan_pcp = 100, 2048, 0 nw_src, nw_dst, nw_tos = '127.0.0.1', '127.0.0.1', 0 tp_src, tp_dst = 1, 1 try: trace = entries['trace'] switch = trace['switch'] eth = trace['eth'] except: pass try: ip = trace['ip'] except: pass try: tp = trace['tp'] except: pass if len(switch) > 0: dpid, in_port = prepare_switch(switch, dpid, in_port) if len(eth) > 0: dl_src, dl_dst, dl_vlan, dl_type, dl_vlan_pcp = prepare_ethernet(eth, dl_src, dl_dst, dl_vlan, dl_type, dl_vlan_pcp) # if len(ip) > 0: nw_src, nw_dst, nw_tos = prepare_ip(ip, nw_src, nw_dst, nw_tos) # if len(tp) > 0: tp_src, tp_dst = prepare_tp(tp, tp_src, tp_dst) kethernet = Ethernet() kethernet.ether_type = constants.VLAN kethernet.source = dl_src kethernet.destination = dl_dst kvlan = VLAN(vid=int(dl_vlan), pcp=dl_vlan_pcp, ether_type=int(dl_type)) msg = TraceMsg(r_id, my_domain) if int(dl_type) == constants.IPv4: kip = IPv4() kip.destination = nw_dst kip.source = nw_src # ip.protocol = 6 kip.data = dill.dumps(msg) kvlan.data = kip.pack() else: kvlan.data = dill.dumps(msg) kethernet.data = kvlan.pack() pkt = kethernet.pack() return in_port, pkt
def handle_packet_in(self, event): """Handle PacketIn Event. Install flows allowing communication between switch ports. Args: event (KytosPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] ethernet = Ethernet() ethernet.unpack(packet_in.data.value) # Ignore LLDP packets or packets not generated by table-miss flows if (ethernet.destination in settings.lldp_macs or packet_in.reason != PacketInReason.OFPR_NO_MATCH): return # Learn the port where the sender is connected in_port = packet_in.in_port switch = event.source.switch switch.update_mac_table(ethernet.source, in_port) ports = switch.where_is_mac(ethernet.destination) # Add a flow to the switch if the destination is known if ports: flow_mod = FlowMod() flow_mod.command = FlowModCommand.OFPFC_ADD flow_mod.priority = settings.flow_priority match_dl_type = OxmTLV() match_dl_type.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE match_dl_type.oxm_value = ethernet.ether_type.value.to_bytes( 2, 'big') flow_mod.match.oxm_match_fields.append(match_dl_type) match_dl_src = OxmTLV() match_dl_src.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_SRC match_dl_src.oxm_value = ethernet.source.pack() flow_mod.match.oxm_match_fields.append(match_dl_src) match_dl_dst = OxmTLV() match_dl_dst.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_DST match_dl_dst.oxm_value = ethernet.destination.pack() flow_mod.match.oxm_match_fields.append(match_dl_dst) action = ActionOutput(port=ports[0]) instruction = InstructionApplyAction() instruction.actions.append(action) flow_mod.instructions.append(instruction) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_flow_mod'), content={ 'destination': event.source, 'message': flow_mod }) self.controller.buffers.msg_out.put(event_out) # Send the packet to correct destination or flood it packet_out = PacketOut() packet_out.buffer_id = packet_in.buffer_id packet_out.in_port = in_port packet_out.data = packet_in.data port = ports[0] if ports else PortNo.OFPP_FLOOD out_action = ActionOutput(port=port) packet_out.actions.append(out_action) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_packet_out'), content={ 'destination': event.source, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out)