blob: 7e861a05f24d6d3dfb3bcafddbc97deb76dbdddb [file] [log] [blame]
#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