void SimpleForwardingModule::handlePacketIn(const zmf::data::ZmfMessage& packetInMsg) { Device* destinationDevice = nullptr; // Unpack ZmfMessage which contains OpenFlow packet of_packet_in_t* ofPacketIn = zsdn::of_object_new_from_data_string_copy(packetInMsg.getData()); of_octets_t ofPayload; of_packet_in_data_get(ofPacketIn, &ofPayload); // extracted message data uint8_t* payloadData = ofPayload.data; uint16_t payloadLength = ofPayload.bytes; // get the ethernet message frame Tins::EthernetII ethPacket(payloadData, payloadLength); of_version_t ofVersion = ofPacketIn->version; // some ethertype may be excluded from beeing handled by this module. we check if the received packet is one of them. bool ignoreEtherType = false; for (uint16_t ignoredType : ignoreEthertypes_) { if (ethPacket.payload_type() == ignoredType) { ignoreEtherType = true; break; } } if (ignoreEtherType) { getLogger().trace("Ignoring packet due to ethertype"); } else { Tins::EthernetII::address_type dstAdress = ethPacket.dst_addr(); // extract the destination address uint64_t destinationMac = zsdn::NetUtils::mac_address_tins_to_uint64(dstAdress); // check for broadcast if == TRUE -> skip the message if (dstAdress.is_broadcast()) { this->getLogger().trace("Received Broadcast -> Message ignored"); } else { this->getLogger().trace("Received Packet in"); // check if the device is known if == FALSE -> request the device by a DeviceManager module if ((this->devices_.count(destinationMac) > 0)) { destinationDevice = &this->devices_.find(destinationMac)->second; // get the device out of the map } else { destinationDevice = this->requestDevice(destinationMac); // request the device by DeviceManager module } if (destinationDevice != nullptr) { // send the initial message payload to the destination switch port if (ofVersion == OF_VERSION_UNKNOWN) { getLogger().warning("Received Packet with OF_VERSION_UNKNOWN. Ignoring Packet."); return; } of_port_no_t port_no = destinationDevice->switchPort; of_object_t* resultObject = nullptr; switch (ofVersion) { case OF_VERSION_UNKNOWN: break; case OF_VERSION_1_0: of_packet_out_data_set(tempPacketOut_OF_1_0, &ofPayload); of_action_output_port_set(tempOutPut_OF_1_0, port_no); of_packet_out_actions_set(tempPacketOut_OF_1_0, tempActionList_OF_1_0); resultObject = tempPacketOut_OF_1_0; break; case OF_VERSION_1_1: break; case OF_VERSION_1_2: break; case OF_VERSION_1_3: of_packet_out_data_set(tempPacketOut_OF_1_3, &ofPayload); of_action_output_port_set(tempOutPut_OF_1_3, port_no); of_packet_out_actions_set(tempPacketOut_OF_1_3, tempActionList_OF_1_3); resultObject = tempPacketOut_OF_1_3; break; case OF_VERSION_1_4: break; } if (resultObject != nullptr) { std::string messageBytes = zsdn::of_object_serialize_to_data_string(resultObject); std::map<uint64_t, zmf::data::MessageType>::iterator msgType = this->linkDevicePacketOutMessageTypeMap_.find( destinationDevice->macAddress); this->getZmf()->publish(zmf::data::ZmfMessage( msgType->second, messageBytes)); if (this->getLogger().trace()) { this->getLogger().trace( "Forwarded packet to " + std::to_string(unsigned(destinationDevice->switchDpid)) + ":" + std::to_string(unsigned(destinationDevice->switchPort))); } } } else { this->getLogger().trace( "Not able to forwared packet, host " + dstAdress.to_string() + " unknown"); } } } of_packet_in_delete(ofPacketIn); };
/* * icmp_packet_in_handler * * API for handling incoming packets */ indigo_core_listener_result_t icmpa_packet_in_handler (of_packet_in_t *packet_in) { of_octets_t octets; of_port_no_t port_no; of_match_t match; ppe_packet_t ppep; indigo_core_listener_result_t result = INDIGO_CORE_LISTENER_RESULT_PASS; uint32_t type, code; debug_counter_inc(&pkt_counters.icmp_total_in_packets); if (!packet_in) return INDIGO_CORE_LISTENER_RESULT_PASS; of_packet_in_data_get(packet_in, &octets); /* * Identify the recv port */ if (packet_in->version <= OF_VERSION_1_1) { return INDIGO_CORE_LISTENER_RESULT_PASS; } else { if (of_packet_in_match_get(packet_in, &match) < 0) { AIM_LOG_ERROR("ICMPA: match get failed"); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } port_no = match.fields.in_port; } if (port_no == OF_PORT_DEST_CONTROLLER) { debug_counter_inc(&pkt_counters.icmp_total_passed_packets); return INDIGO_CORE_LISTENER_RESULT_PASS; } if (port_no > MAX_PORTS) { AIM_LOG_ERROR("ICMPA: Port No: %d Out of Range %d", port_no, MAX_PORTS); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } /* * Check the packet-in reasons in metadata * * Icmp agent should not consume packets coming in due to L2 Src miss * and Station Move. */ if ((match.fields.metadata & OFP_BSN_PKTIN_FLAG_STATION_MOVE) || (match.fields.metadata & OFP_BSN_PKTIN_FLAG_NEW_HOST)) { debug_counter_inc(&pkt_counters.icmp_total_passed_packets); return INDIGO_CORE_LISTENER_RESULT_PASS; } ppe_packet_init(&ppep, octets.data, octets.bytes); if (ppe_parse(&ppep) < 0) { AIM_LOG_RL_ERROR(&icmp_pktin_log_limiter, os_time_monotonic(), "ICMPA: Packet_in parsing failed."); debug_counter_inc(&pkt_counters.icmp_internal_errors); return INDIGO_CORE_LISTENER_RESULT_PASS; } /* * Identify if this is an Echo Request, destined to one of VRouter */ if (ppe_header_get(&ppep, PPE_HEADER_ICMP)) { if (icmpa_reply(&ppep, port_no, &result)) { ++port_pkt_counters[port_no].icmp_echo_packets; return result; } } /* * To handle traceroute, we need to check for * a) UDP Packet * b) dest IP is Vrouter IP * c) UDP src and dest ports are ephemeral */ if (ppe_header_get(&ppep, PPE_HEADER_UDP) && ppe_header_get(&ppep, PPE_HEADER_IP4)) { uint32_t dest_ip, src_port, dest_port; ppe_field_get(&ppep, PPE_FIELD_IP4_DST_ADDR, &dest_ip); ppe_field_get(&ppep, PPE_FIELD_UDP_SRC_PORT, &src_port); ppe_field_get(&ppep, PPE_FIELD_UDP_DST_PORT, &dest_port); if (router_ip_check(dest_ip) && is_ephemeral(src_port) && is_ephemeral(dest_port)) { AIM_LOG_TRACE("ICMP Port Unreachable received on port: %d", port_no); type = ICMP_DEST_UNREACHABLE; code = 3; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_port_unreachable_packets; return result; } } } /* * Identify if the reason is valid for ICMP Agent to consume the packet */ if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_L3_MISS) { AIM_LOG_TRACE("ICMP Dest Network Unreachable received on port: %d", port_no); type = ICMP_DEST_UNREACHABLE; code = 0; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_net_unreachable_packets; } } else if (match.fields.metadata & OFP_BSN_PKTIN_FLAG_TTL_EXPIRED) { AIM_LOG_TRACE("ICMP TTL Expired received on port: %d", port_no); type = ICMP_TIME_EXCEEDED; code = 0; result = INDIGO_CORE_LISTENER_RESULT_DROP; if (icmpa_send(&ppep, port_no, type, code)) { ++port_pkt_counters[port_no].icmp_time_exceeded_packets; } } return result; }