blob: e9bd55db32104d520b36dc86e8b8176533a89f39 [file] [log] [blame]
#include "rde_match_handler.hpp"
#include "util/mctp_setup.hpp"
#include <sdbusplus/unpack_properties.hpp>
#include <stdplus/print.hpp>
#include <format>
using DbusVariant = std::variant<std::string, uint64_t, uint32_t, uint16_t,
uint8_t, sdbusplus::message::object_path>;
using ChangedPropertiesType = std::vector<std::pair<std::string, DbusVariant>>;
RdeMatchHandler::RdeMatchHandler(int socketFd) : fd(socketFd)
{}
RdeMatchHandler::~RdeMatchHandler()
{}
int RdeMatchHandler::initiateDiscovery(const int& fd, const std::string& udevId,
const int& netId)
{
int rc = 0;
// Begin Base Discovery
stdplus::print(stderr, "Initiating PLDM Discovery...\n");
// TODO(@harshtya): Add discovery calls
// TODO(@harshtya): Remove the log below after discovery calls
stdplus::print(stderr, "Call arguments: {}, {}, {}\n", fd, udevId, netId);
if (rc)
{
stdplus::print(stderr,
"Failure in Base Discovery with error code: {}\n", rc);
return rc;
}
return rc;
}
void RdeMatchHandler::scanForExistingDevices(
const int& fd, sdbusplus::asio::object_server& objectServer,
const std::string& prefixPath,
std::shared_ptr<sdbusplus::asio::connection>& systemBus)
{
using propertyMap =
std::vector<std::pair<std::string, std::vector<std::string>>>;
constexpr std::array<std::string_view, 1> interfaces = {
"xyz.openbmc_project.Configuration.RdeSatelliteController"};
using DBusProperties = std::vector<std::pair<std::string, DbusVariant>>;
systemBus->async_method_call_timed(
[this, &fd, &systemBus, &objectServer, &prefixPath](
const boost::system::error_code& ec,
const std::vector<std::pair<std::string, propertyMap>>& subtree) {
if (ec)
{
stdplus::print(
stderr,
"Failed to scan existing RDE object paths with error msg: {}\n",
ec.message());
return;
}
if (subtree.empty())
{
stdplus::print(
stderr,
"RDE Device scan empty. "
"No instances found while parsing Entity Manager tree\n");
return;
}
for (const auto& [objPath, services] : subtree)
{
for (const auto& service : services)
{
systemBus->async_method_call_timed(
[this, &fd, &objectServer, &prefixPath,
objPath](const boost::system::error_code& errorCode,
const DBusProperties& properties) {
if (errorCode)
{
stdplus::print(
stderr,
"Scanning RDE Devices failed."
" Error in DBus response ec: {} and msg: {}\n",
errorCode.value(), errorCode.message());
return;
}
std::string vendorId;
std::string udevId;
std::string port;
const bool success = sdbusplus::unpackPropertiesNoThrow(
[](const sdbusplus::UnpackErrorReason reason,
const std::string& property) {
stdplus::print(
stderr,
"Error unpacking the property: {} with error: {}\n",
property, static_cast<int>(reason));
},
properties, "VID", vendorId, "USBPORT", port, "UDEVID",
udevId);
if (success)
{
if (vendorId.empty() || port.empty() || udevId.empty())
{
stdplus::print(
stderr,
"RDE Device scan failed due to matcher not"
"having the required properties\n");
return;
}
// Do PLDM Setup
rdeSetup(fd, objectServer, std::string(objPath), port,
udevId, vendorId, prefixPath);
}
else
{
stdplus::print(
stderr,
"RDE device scan failed due to error in parsing"
"properties\n");
}
},
service.first, objPath, "org.freedesktop.DBus.Properties",
"GetAll", /*timeout in usec*/ 90000000,
"xyz.openbmc_project.Configuration.RdeSatelliteController");
}
}
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
"xyz.openbmc_project.ObjectMapper", "GetSubTree",
/*timeout in usec*/ 90000000, "/xyz/openbmc_project/inventory", 0,
interfaces);
}
std::unique_ptr<sdbusplus::bus::match_t> RdeMatchHandler::handleMatchAdd(
std::shared_ptr<sdbusplus::asio::connection>& systemBus,
sdbusplus::asio::object_server& objectServer, const std::string& prefixPath,
const int& fd)
{
return std::make_unique<sdbusplus::bus::match_t>(
*systemBus, sdbusplus::bus::match::rules::interfacesAdded(),
[this, &objectServer, &prefixPath, &systemBus,
&fd](sdbusplus::message_t& reply) {
sdbusplus::message::object_path changedObject;
reply.read(changedObject);
std::vector<std::pair<std::string, ChangedPropertiesType>>
changedInterfaces;
reply.read(changedInterfaces);
std::string vendorId;
std::string udevId;
std::string port;
for (const auto& [changedInterface, changedProps] : changedInterfaces)
{
if (changedInterface !=
"xyz.openbmc_project.Configuration.RdeSatelliteController")
{
continue;
}
if (DEBUG)
{
stdplus::print(stderr, "New device detected: {}\n",
std::string(changedObject));
}
for (auto& [key, value] : changedProps)
{
if (key == "VID")
{
vendorId = std::get<std::string>(value);
}
else if (key == "USBPORT")
{
port = std::get<std::string>(value);
}
else if (key == "UDEVID")
{
udevId = std::get<std::string>(value);
}
}
if (vendorId.empty() || port.empty() || udevId.empty())
{
stdplus::print(stderr,
"Matcher does not have required properties\n");
return;
}
// TODO(@harshtya): Call RDE Setup here
}
});
}
std::unique_ptr<sdbusplus::bus::match_t> RdeMatchHandler::handleMatchRemove(
std::shared_ptr<sdbusplus::asio::connection>& systemBus,
sdbusplus::asio::object_server& objectServer)
{
return std::make_unique<sdbusplus::bus::match_t>(
*systemBus, sdbusplus::bus::match::rules::interfacesRemoved(),
[this, &objectServer](sdbusplus::message_t& reply) {
sdbusplus::message::object_path changedObject;
std::vector<std::string> interfacesRemoved;
reply.read(changedObject, interfacesRemoved);
auto it = deviceToDbusIntfMap.find(std::string(changedObject));
if (it != deviceToDbusIntfMap.end())
{
std::shared_ptr<sdbusplus::asio::dbus_interface> iface = it->second;
auto removed = objectServer.remove_interface(iface);
stdplus::print(stderr, "Removed RDE Device from tree: {}\n",
removed);
deviceToDbusIntfMap.erase(std::string(changedObject));
auto it = objectPathToDeviceIdMap.find(std::string(changedObject));
if (it != objectPathToDeviceIdMap.end())
{
cleanupMctpLink(it->second);
// TODO (@harshtya): clean up the Rde device from maps
// TODO (@harshtya): clean up the dictionaries
objectPathToDeviceIdMap.erase(std::string(changedObject));
deviceToNetIdMap.erase(it->second);
}
}
});
}
void RdeMatchHandler::triggerMatcher()
{
boost::asio::io_context io;
std::shared_ptr<sdbusplus::asio::connection> systemBus =
std::make_shared<sdbusplus::asio::connection>(io);
sdbusplus::asio::object_server objectServer(systemBus, true);
objectServer.add_manager("/xyz/openbmc_project/rde_devices");
std::string prefixPath = "/xyz/openbmc_project/rde_devices/";
// TODO(@harshtya): Add scan for existing devices
// Initialize the match handler for interfacesAdded
auto matchAdd =
handleMatchAdd(systemBus, objectServer, prefixPath, this->fd);
// Matcher to monitor for devices removed
auto matchRemove = handleMatchRemove(systemBus, objectServer);
systemBus->request_name("xyz.openbmc_project.rdeoperation");
io.run();
}
int RdeMatchHandler::rdeSetup(const int& fd,
sdbusplus::asio::object_server& objectServer,
const std::string& changedObject,
const std::string& port,
const std::string& udevId,
const std::string& vendorId,
const std::string& prefixPath)
{
int netId = setupOnePort(port, udevId); // MCTP Setup
deviceToNetIdMap.emplace(udevId, netId);
int rc = initiateDiscovery(fd, udevId, netId);
if (rc)
{
stdplus::print(stderr,
"PLDM/RDE Discovery failed for device: {}"
"and udevId: {} after all retries\n",
port, udevId);
return rc;
}
std::string objectPath = std::format("{}{}", prefixPath, udevId);
if (DEBUG)
{
stdplus::print(stderr, "Creating object path for RDE Operation: {}\n ",
objectPath);
}
std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
objectServer.add_interface(objectPath, "xyz.openbmc_project.RdeDevice");
iface->register_property("VID", vendorId,
sdbusplus::asio::PropertyPermission::readOnly);
iface->register_property("USBPORT", port,
sdbusplus::asio::PropertyPermission::readOnly);
iface->register_property("UDEVID", udevId,
sdbusplus::asio::PropertyPermission::readOnly);
// TODO(@harshtya): Add RDE OPeration Handler Dbus method
iface->initialize();
deviceToDbusIntfMap.emplace(std::string(changedObject), iface);
objectPathToDeviceIdMap.emplace(std::string(changedObject), udevId);
return 0;
}