blob: 44ed4d6524fbb37d7a35dcda00d83070fcb07c28 [file] [edit]
/**
* Copyright 2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "libpldm/pldm_rde.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/container/flat_map.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <sdbusplus/message/types.hpp>
#include <filesystem>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <random>
#include <regex>
#include <span>
#include <string>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
const constexpr char* rdeDevicesPath = "/xyz/openbmc_project/rde_devices";
const constexpr char* unitPercent =
"xyz.openbmc_project.Sensor.Value.Unit.Percent";
const constexpr char* valueMutabilityInterfaceName =
"xyz.openbmc_project.Sensor.ValueMutability";
const constexpr char* rdeDeviceInterface = "xyz.openbmc_project.RdeDevice";
using ObjPathToServiceMapType = std::map<std::string, std::string>;
using GetSubTreeType = std::vector<
std::pair<std::string,
std::vector<std::pair<std::string, std::vector<std::string>>>>>;
using Association = std::tuple<std::string, std::string, std::string>;
namespace mapper
{
constexpr const char* busName = "xyz.openbmc_project.ObjectMapper";
constexpr const char* path = "/xyz/openbmc_project/object_mapper";
constexpr const char* interface = "xyz.openbmc_project.ObjectMapper";
constexpr const char* subtree = "GetSubTree";
} // namespace mapper
namespace association
{
const static constexpr char* interface =
"xyz.openbmc_project.Association.Definitions";
} // namespace association
/**
* @brief Check if it is an error response
*
* @param[in] resp A json object storing the response
*
* @return bool (True for error response and false otherwise)
*/
bool isResponseError(const std::string& resp);
/**
* @brief Create association between D-bus objects
*
* @param[in] association Pointer to an associations interface
* @param[in] path A D-bus object path
*
* @return void
*/
void createAssociation(
std::shared_ptr<sdbusplus::asio::dbus_interface>& association,
const std::string& path);
/**
* @brief Setup a matcher to detect Rde device D-bus object discovery
*
* @param[in] bus A D-bus bus object
* @param[in] handler A callback function to be called when match is found
*
* @return std::vector<std::unique_ptr<sdbusplus::bus::match_t>> (Match object)
*/
std::vector<std::unique_ptr<sdbusplus::bus::match_t>>
setupRdeDeviceDetectionMatches(
sdbusplus::bus_t& bus,
const std::function<void(sdbusplus::message_t&)>& handler);
/**
* @brief Setup a matcher to detect Rde device D-bus object removal
*
* @param[in] bus A D-bus bus object
* @param[in] handler A callback function to be called when match is found
*
* @return std::vector<std::unique_ptr<sdbusplus::bus::match_t>> (Match object)
*/
std::unique_ptr<sdbusplus::bus::match_t> setupRdeDeviceRemovalMatches(
sdbusplus::bus_t& bus,
const std::function<void(sdbusplus::message_t&)>& handler);
/**
* @brief Send Redfish queries to Rde device
*
* @param[in] dbusConnection A D-bus bus object to send D-bus requests
* @param[in] uri A Redfish resource uri to query
* @param[in] rdeDeviceId Rde device id
* @param[in] rdeServiceName Name of the service that handles D-bus requests for
* Rde device
* @param[in] rdeObjPath Rde device D-bus object path
* @param[in] operationType Pldm operation type
* @param[in] requestPayload Request payload to send
*
* @return std::string (Response for the Redfish query)
*/
std::string sendRdeDbusRequest(sdbusplus::bus_t& dbusConnection,
const std::string& uri,
const std::string& rdeDeviceId,
const std::string& rdeServiceName,
const std::string& rdeObjPath,
pldm_rde_operation_type operationType,
const std::string& requestPayload);
/** @struct GetRdeDevices
*
* Container that stores data and method needed to get the Rde device object
* paths
*/
struct GetRdeDevices : std::enable_shared_from_this<GetRdeDevices>
{
GetRdeDevices(std::shared_ptr<sdbusplus::asio::connection> connection,
std::function<void(ObjPathToServiceMapType& serviceMap)>&&
callbackFunc) :
dbusConnection(std::move(connection)), callback(std::move(callbackFunc))
{}
void getRdeDevices(size_t retries = 0)
{
if (retries > 5)
{
retries = 5;
}
std::vector<std::string> interfaces = {rdeDeviceInterface};
std::shared_ptr<GetRdeDevices> self = shared_from_this();
dbusConnection->async_method_call(
[self, retries](const boost::system::error_code& ec,
const GetSubTreeType& subtree) {
if (ec)
{
std::cerr << "Error in the mapper call. ec : " << ec
<< std::endl;
if (retries == 0U)
{
return;
}
auto timer = std::make_shared<boost::asio::steady_timer>(
self->dbusConnection->get_io_context());
timer->expires_after(std::chrono::seconds(10));
timer->async_wait([self, timer, retries](
const boost::system::error_code& ec) {
if (ec)
{
std::cerr << "Timer error" << std::endl;
return;
}
self->getRdeDevices(retries - 1);
});
return;
}
for (const auto& [path, objDict] : subtree)
{
if (objDict.empty())
{
return;
}
self->rdeDevObjPathsToServiceMap[path] = objDict.begin()->first;
}
},
mapper::busName, mapper::path, mapper::interface, mapper::subtree,
"/", 0, interfaces);
}
~GetRdeDevices()
{
callback(rdeDevObjPathsToServiceMap);
}
std::shared_ptr<sdbusplus::asio::connection> dbusConnection;
std::function<void(ObjPathToServiceMapType& serviceMap)> callback;
ObjPathToServiceMapType rdeDevObjPathsToServiceMap;
};