blob: 1b6cd305b0e183bbbece8d1506a1b2bcae1e01e8 [file] [log] [blame]
#include "config.h"
#include "mctp_endpoint_discovery.hpp"
#include "common/types.hpp"
#include "common/utils.hpp"
#include <linux/mctp.h>
#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;
const MctpEndpointProps& epProps =
getMctpEndpointProps(service, path);
const UUID& uuid = getEndpointUUIDProp(service, path);
auto types = std::get<MCTPMsgTypes>(epProps);
if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
types.end())
{
mctpInfos.emplace_back(
MctpInfo(std::get<eid>(epProps), uuid, "",
std::get<NetworkId>(epProps)));
}
}
}
}
MctpEndpointProps MctpDiscovery::getMctpEndpointProps(
const std::string& service, const std::string& path)
{
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"));
return MctpEndpointProps(networkId, eid, types);
}
}
catch (const sdbusplus::exception_t& e)
{
error(
"Error reading MCTP Endpoint property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
"SERVICE", service, "PATH", path, "ERROR", e);
return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
}
return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
}
UUID MctpDiscovery::getEndpointUUIDProp(const std::string& service,
const std::string& path)
{
try
{
auto properties = pldm::utils::DBusHandler().getDbusPropertiesVariant(
service.c_str(), path.c_str(), EndpointUUID);
if (properties.contains("UUID"))
{
return std::get<UUID>(properties.at("UUID"));
}
}
catch (const sdbusplus::exception_t& e)
{
error(
"Error reading Endpoint UUID property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
"SERVICE", service, "PATH", path, "ERROR", e);
return static_cast<UUID>(emptyUUID);
}
return static_cast<UUID>(emptyUUID);
}
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;
std::string uuid = emptyUUID;
try
{
msg.read(objPath, interfaces);
}
catch (const sdbusplus::exception_t& e)
{
error(
"Error reading MCTP Endpoint added interface message, error - {ERROR}",
"ERROR", e);
return;
}
/* Get UUID */
try
{
auto service = pldm::utils::DBusHandler().getService(
objPath.str.c_str(), EndpointUUID);
uuid = getEndpointUUIDProp(service, objPath.str);
}
catch (const sdbusplus::exception_t& e)
{
error("Error getting Endpoint UUID D-Bus interface, error - {ERROR}",
"ERROR", e);
}
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}' UUID '{UUID}'",
"NETWORK", networkId, "EID", eid, "UUID", uuid);
mctpInfos.emplace_back(MctpInfo(eid, uuid, "", 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", 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