| #include "mctp_endpoint_discovery.hpp" |
| |
| #include "common/types.hpp" |
| #include "common/utils.hpp" |
| |
| #include <algorithm> |
| #include <map> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| namespace pldm |
| { |
| MctpDiscovery::MctpDiscovery(sdbusplus::bus_t& bus, sdeventplus::Event& event, |
| fw_update::Manager* fwManager, |
| terminus::Manager* devManager) : |
| bus(bus), fwManager(fwManager), devManager(devManager), |
| discoveryTimer(event, std::bind(&MctpDiscovery::addRemoveEndpoints, this)), |
| mctpEndpointAddedSignal( |
| bus, |
| sdbusplus::bus::match::rules::interfacesAdded( |
| "/au/com/codeconstruct/mctp1"), |
| std::bind_front(&MctpDiscovery::discoverEndpoints, this)), |
| mctpEndpointRemovedSignal( |
| bus, |
| sdbusplus::bus::match::rules::interfacesRemoved( |
| "/au/com/codeconstruct/mctp1"), |
| std::bind_front(&MctpDiscovery::removeEndpoints, this)) |
| { |
| addRemoveEndpoints(); |
| } |
| |
| void MctpDiscovery::addRemoveEndpoints() |
| { |
| std::set<mctp_eid_t> freshEids = discoveryPldmMctpEndpoints(); |
| |
| std::vector<mctp_eid_t> added; |
| for (mctp_eid_t eid : freshEids) |
| { |
| if (!pldmEids.contains(eid)) |
| added.push_back(eid); |
| } |
| |
| std::vector<mctp_eid_t> removed; |
| for (mctp_eid_t eid : pldmEids) |
| { |
| if (!freshEids.contains(eid)) |
| removed.push_back(eid); |
| } |
| |
| if ((added.size() || removed.size()) && devManager) |
| { |
| // Reload mapping when EID changed |
| devManager->parseEIDToInventoryMapping(); |
| } |
| |
| // Handle removed EID |
| if (removed.size()) |
| { |
| if (devManager) |
| { |
| devManager->removeDevices(removed); |
| } |
| |
| // It seems that fwManager doesn't support remove? |
| } |
| |
| // Handle added EID |
| if (added.size()) |
| { |
| if (fwManager) |
| { |
| fwManager->handleMCTPEndpoints(added); |
| } |
| |
| if (devManager) |
| { |
| devManager->addDevices(added); |
| } |
| } |
| |
| // Assign freshEids to pldmEids |
| pldmEids = freshEids; |
| } |
| |
| std::set<mctp_eid_t> MctpDiscovery::discoveryPldmMctpEndpoints() |
| { |
| dbus::ObjectValueTree objects; |
| try |
| { |
| auto method = bus.new_method_call( |
| "au.com.codeconstruct.MCTP1", "/au/com/codeconstruct/mctp1", |
| "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); |
| auto reply = bus.call(method, dbusTimeout); |
| reply.read(objects); |
| } |
| catch (const std::exception& e) |
| { |
| std::cerr << "Error in queryEndpointsBySupportedMsg: " << e.what() |
| << std::endl; |
| return {}; |
| } |
| |
| std::set<mctp_eid_t> eids; |
| for (const auto& [objectPath, interfaces] : objects) |
| { |
| for (const auto& [intfName, properties] : interfaces) |
| { |
| if (intfName != mctpEndpointIntfName) |
| continue; |
| |
| if (properties.contains("EID") && |
| properties.contains("NetworkId") && |
| properties.contains("SupportedMessageTypes")) |
| { |
| uint8_t eid = std::get<uint8_t>(properties.at("EID")); |
| uint32_t networkId = |
| std::get<uint32_t>(properties.at("NetworkId")); |
| auto types = std::get<std::vector<uint8_t>>( |
| properties.at("SupportedMessageTypes")); |
| |
| #if 0 |
| // Keep debug code below in case we need debug this piece of |
| // code in future |
| std::cerr << std::format( |
| "NetworkId:{}, EID:{}, SupportedMessageTypes: ", networkId, |
| eid); |
| for (unsigned x : types) |
| { |
| std::cerr << x << ", "; |
| } |
| std::cerr << std::endl; |
| #endif |
| |
| // libpldm only supports one network ID for af_mctp binding |
| // for now. |
| if (networkId != 1) |
| { |
| continue; |
| } |
| |
| if (std::find(types.begin(), types.end(), mctpTypePLDM) != |
| types.end()) |
| { |
| eids.insert(eid); |
| } |
| } |
| } |
| } |
| return eids; |
| } |
| |
| void MctpDiscovery::discoverEndpoints( |
| [[maybe_unused]] sdbusplus::message_t& msg) |
| { |
| sdbusplus::message::object_path objPath; |
| pldm::dbus::InterfaceMap interfaces; |
| try |
| { |
| msg.read(objPath, interfaces); |
| } |
| catch (const sdbusplus::exception_t& e) |
| { |
| std::cerr |
| << "Error reading MCTP Endpoint added interface message, error:" |
| << e.what(); |
| return; |
| } |
| |
| for (const auto& [intfName, properties] : interfaces) |
| { |
| if (intfName == mctpEndpointIntfName) |
| { |
| if (properties.contains("NetworkId") && properties.contains("EID")) |
| { |
| uint32_t networkId = |
| std::get<uint32_t>(properties.at("NetworkId")); |
| mctp_eid_t eid = std::get<mctp_eid_t>(properties.at("EID")); |
| if (networkId == 1) |
| { |
| // Forcely remove the eid from MctpDiscovery cache so the |
| // eid can be detected as newly added endpoint later |
| pldmEids.erase(eid); |
| } |
| } |
| } |
| } |
| // One second delay in case bulk of MCTP endpoints added |
| discoveryTimer.restartOnce(std::chrono::seconds(1)); |
| } |
| |
| void MctpDiscovery::removeEndpoints([[maybe_unused]] sdbusplus::message_t& msg) |
| { |
| // interfaceRemoved signal does not include the removed path in the response |
| // message. Check the remained EID in the MCTP D-Bus interface and compare |
| // with the previous list to find the removed EIDs |
| |
| // One second delay in case bulk of MCTP endpoints removed |
| discoveryTimer.restartOnce(std::chrono::seconds(1)); |
| } |
| |
| } // namespace pldm |