blob: 0d63ad41e72d199c0137bbd3b4284005d10b4924 [file] [log] [blame]
#include "config.h"
#include "mctp_endpoint_discovery.hpp"
#include "common/types.hpp"
#include "common/utils.hpp"
#include <phosphor-logging/lg2.hpp>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <string_view>
#include <vector>
using namespace sdbusplus::bus::match::rules;
PHOSPHOR_LOG2_USING;
namespace pldm
{
MctpDiscovery::MctpDiscovery(
sdbusplus::bus_t& bus,
std::initializer_list<MctpDiscoveryHandlerIntf*> list) :
bus(bus),
mctpEndpointAddedSignal(
bus, interfacesAdded(MCTPPath),
std::bind_front(&MctpDiscovery::discoverEndpoints, this)),
mctpEndpointRemovedSignal(
bus, interfacesRemoved(MCTPPath),
std::bind_front(&MctpDiscovery::removeEndpoints, this)),
handlers(list)
{
getMctpInfos(existingMctpInfos);
handleMctpEndpoints(existingMctpInfos);
}
void MctpDiscovery::getMctpInfos(MctpInfos& mctpInfos)
{
// Find all implementations of the MCTP Endpoint interface
pldm::utils::GetSubTreeResponse mapperResponse;
try
{
mapperResponse = pldm::utils::DBusHandler().getSubtree(
MCTPPath, 0, std::vector<std::string>({MCTPInterface}));
}
catch (const sdbusplus::exception_t& e)
{
error(
"Failed to getSubtree call at path '{PATH}' and interface '{INTERFACE}', error - {ERROR} ",
"ERROR", e, "PATH", MCTPPath, "INTERFACE", MCTPInterface);
return;
}
for (const auto& [path, services] : mapperResponse)
{
for (const auto& serviceIter : services)
{
const std::string& service = serviceIter.first;
try
{
auto properties =
pldm::utils::DBusHandler().getDbusPropertiesVariant(
service.c_str(), path.c_str(), MCTPInterface);
if (properties.contains("NetworkId") &&
properties.contains("EID") &&
properties.contains("SupportedMessageTypes"))
{
auto networkId =
std::get<NetworkId>(properties.at("NetworkId"));
auto eid = std::get<mctp_eid_t>(properties.at("EID"));
auto types = std::get<std::vector<uint8_t>>(
properties.at("SupportedMessageTypes"));
if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
types.end())
{
info(
"Adding Endpoint networkId '{NETWORK}' and EID '{EID}'",
"NETWORK", networkId, "EID", unsigned(eid));
mctpInfos.emplace_back(
MctpInfo(eid, emptyUUID, "", networkId));
}
}
}
catch (const sdbusplus::exception_t& e)
{
error(
"Error reading MCTP Endpoint property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
"ERROR", e, "SERVICE", service, "PATH", path);
return;
}
}
}
}
void MctpDiscovery::getAddedMctpInfos(sdbusplus::message_t& msg,
MctpInfos& mctpInfos)
{
using ObjectPath = sdbusplus::message::object_path;
ObjectPath objPath;
using Property = std::string;
using PropertyMap = std::map<Property, dbus::Value>;
std::map<std::string, PropertyMap> interfaces;
try
{
msg.read(objPath, interfaces);
}
catch (const sdbusplus::exception_t& e)
{
error(
"Error reading MCTP Endpoint added interface message, error - {ERROR}",
"ERROR", e);
return;
}
for (const auto& [intfName, properties] : interfaces)
{
if (intfName == MCTPInterface)
{
if (properties.contains("NetworkId") &&
properties.contains("EID") &&
properties.contains("SupportedMessageTypes"))
{
auto networkId =
std::get<NetworkId>(properties.at("NetworkId"));
auto eid = std::get<mctp_eid_t>(properties.at("EID"));
auto types = std::get<std::vector<uint8_t>>(
properties.at("SupportedMessageTypes"));
if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
types.end())
{
info(
"Adding Endpoint networkId '{NETWORK}' and EID '{EID}'",
"NETWORK", networkId, "EID", unsigned(eid));
mctpInfos.emplace_back(
MctpInfo(eid, emptyUUID, "", networkId));
}
}
}
}
}
void MctpDiscovery::addToExistingMctpInfos(const MctpInfos& addedInfos)
{
for (const auto& mctpInfo : addedInfos)
{
if (std::find(existingMctpInfos.begin(), existingMctpInfos.end(),
mctpInfo) == existingMctpInfos.end())
{
existingMctpInfos.emplace_back(mctpInfo);
}
}
}
void MctpDiscovery::removeFromExistingMctpInfos(MctpInfos& mctpInfos,
MctpInfos& removedInfos)
{
for (const auto& mctpInfo : existingMctpInfos)
{
if (std::find(mctpInfos.begin(), mctpInfos.end(), mctpInfo) ==
mctpInfos.end())
{
removedInfos.emplace_back(mctpInfo);
}
}
for (const auto& mctpInfo : removedInfos)
{
info("Removing Endpoint networkId '{NETWORK}' and EID '{EID}'",
"NETWORK", std::get<3>(mctpInfo), "EID",
unsigned(std::get<0>(mctpInfo)));
existingMctpInfos.erase(std::remove(existingMctpInfos.begin(),
existingMctpInfos.end(), mctpInfo),
existingMctpInfos.end());
}
}
void MctpDiscovery::discoverEndpoints(sdbusplus::message_t& msg)
{
MctpInfos addedInfos;
getAddedMctpInfos(msg, addedInfos);
addToExistingMctpInfos(addedInfos);
handleMctpEndpoints(addedInfos);
}
void MctpDiscovery::removeEndpoints(sdbusplus::message_t&)
{
MctpInfos mctpInfos;
MctpInfos removedInfos;
getMctpInfos(mctpInfos);
removeFromExistingMctpInfos(mctpInfos, removedInfos);
handleRemovedMctpEndpoints(removedInfos);
}
void MctpDiscovery::handleMctpEndpoints(const MctpInfos& mctpInfos)
{
for (const auto& handler : handlers)
{
if (handler)
{
handler->handleMctpEndpoints(mctpInfos);
}
}
}
void MctpDiscovery::handleRemovedMctpEndpoints(const MctpInfos& mctpInfos)
{
for (const auto& handler : handlers)
{
if (handler)
{
handler->handleRemovedMctpEndpoints(mctpInfos);
}
}
}
} // namespace pldm