pldmd: implement PLDM.Requester D-Bus API
Implement D-Bus API defined at
https://gerrit.openbmc-project.xyz/#/c/openbmc/phosphor-dbus-interfaces/+/27077/.
This commit provides an implementation of the PLDM instance id as per
DSP0240 v1.0.0. Ids are tracked per MCTP EID.
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I8a1ef213646529b71d9bf33edda67537f7c0f32a
diff --git a/dbus_impl_requester.cpp b/dbus_impl_requester.cpp
new file mode 100644
index 0000000..ec0fc53
--- /dev/null
+++ b/dbus_impl_requester.cpp
@@ -0,0 +1,37 @@
+#include "dbus_impl_requester.hpp"
+
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+using namespace phosphor::logging;
+
+namespace pldm
+{
+namespace dbus_api
+{
+
+uint8_t Requester::getInstanceId(uint8_t eid)
+{
+ if (ids.find(eid) == ids.end())
+ {
+ InstanceId id;
+ ids.emplace(eid, InstanceId());
+ }
+
+ uint8_t id{};
+ try
+ {
+ id = ids[eid].next();
+ }
+ catch (const std::runtime_error& e)
+ {
+ elog<TooManyResources>();
+ }
+
+ return id;
+}
+
+} // namespace dbus_api
+} // namespace pldm
diff --git a/dbus_impl_requester.hpp b/dbus_impl_requester.hpp
new file mode 100644
index 0000000..e892194
--- /dev/null
+++ b/dbus_impl_requester.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "instance_id.hpp"
+#include "xyz/openbmc_project/PLDM/Requester/server.hpp"
+
+#include <map>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server/object.hpp>
+
+namespace pldm
+{
+namespace dbus_api
+{
+
+using RequesterIntf = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::PLDM::server::Requester>;
+
+/** @class Requester
+ * @brief OpenBMC PLDM.Requester implementation.
+ * @details A concrete implementation for the
+ * xyz.openbmc_project.PLDM.Requester DBus APIs.
+ */
+class Requester : public RequesterIntf
+{
+ public:
+ Requester() = delete;
+ Requester(const Requester&) = delete;
+ Requester& operator=(const Requester&) = delete;
+ Requester(Requester&&) = delete;
+ Requester& operator=(Requester&&) = delete;
+ virtual ~Requester() = default;
+
+ /** @brief Constructor to put object onto bus at a dbus path.
+ * @param[in] bus - Bus to attach to.
+ * @param[in] path - Path to attach at.
+ */
+ Requester(sdbusplus::bus::bus& bus, const std::string& path) :
+ RequesterIntf(bus, path.c_str()){};
+
+ /** @brief Implementation for RequesterIntf.GetInstanceId */
+ uint8_t getInstanceId(uint8_t eid) override;
+
+ /** @brief Mark an instance id as unused
+ * @param[in] eid - MCTP eid to which this instance id belongs
+ * @param[in] instanceId - PLDM instance id to be freed
+ * @note will throw std::out_of_range if instanceId > 31
+ */
+ void markFree(uint8_t eid, uint8_t instanceId)
+ {
+ ids[eid].markFree(instanceId);
+ }
+
+ private:
+ /** @brief EID to PLDM Instance ID map */
+ std::map<uint8_t, InstanceId> ids;
+};
+
+} // namespace dbus_api
+} // namespace pldm
diff --git a/instance_id.cpp b/instance_id.cpp
new file mode 100644
index 0000000..52cd1d6
--- /dev/null
+++ b/instance_id.cpp
@@ -0,0 +1,25 @@
+#include "instance_id.hpp"
+
+#include <stdexcept>
+
+namespace pldm
+{
+
+uint8_t InstanceId::next()
+{
+ uint8_t idx = 0;
+ while (idx < id.size() && id.test(idx))
+ {
+ ++idx;
+ }
+
+ if (idx == id.size())
+ {
+ throw std::runtime_error("No free instance ids");
+ }
+
+ id.set(idx);
+ return idx;
+}
+
+} // namespace pldm
diff --git a/instance_id.hpp b/instance_id.hpp
new file mode 100644
index 0000000..70b284c
--- /dev/null
+++ b/instance_id.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <bitset>
+
+namespace pldm
+{
+
+constexpr size_t maxInstanceIds = 32;
+
+/** @class InstanceId
+ * @brief Implementation of PLDM instance id as per DSP0240 v1.0.0
+ */
+class InstanceId
+{
+ public:
+ /** @brief Get next unused instance id
+ * @return - PLDM instance id
+ */
+ uint8_t next();
+
+ /** @brief Mark an instance id as unused
+ * @param[in] instanceId - PLDM instance id to be freed
+ */
+ void markFree(uint8_t instanceId)
+ {
+ id.set(instanceId, false);
+ }
+
+ private:
+ std::bitset<maxInstanceIds> id;
+};
+
+} // namespace pldm
diff --git a/meson.build b/meson.build
index bca95eb..3a1e010 100644
--- a/meson.build
+++ b/meson.build
@@ -37,12 +37,15 @@
libpldm,
libpldmresponder,
dependency('sdbusplus'),
- dependency('sdeventplus')
+ dependency('sdeventplus'),
+ dependency('phosphor-dbus-interfaces')
]
executable(
'pldmd',
'pldmd.cpp',
+ 'dbus_impl_requester.cpp',
+ 'instance_id.cpp',
implicit_include_directories: false,
dependencies: deps,
install: true,
diff --git a/pldmd.cpp b/pldmd.cpp
index dce5625..39bee54 100644
--- a/pldmd.cpp
+++ b/pldmd.cpp
@@ -1,3 +1,4 @@
+#include "dbus_impl_requester.hpp"
#include "libpldmresponder/base.hpp"
#include "libpldmresponder/bios.hpp"
#include "libpldmresponder/platform.hpp"
@@ -40,7 +41,8 @@
using namespace sdeventplus;
using namespace sdeventplus::source;
-static Response processRxMsg(const std::vector<uint8_t>& requestMsg)
+static Response processRxMsg(const std::vector<uint8_t>& requestMsg,
+ dbus_api::Requester& requester)
{
Response response;
@@ -78,6 +80,10 @@
response.insert(response.end(), completion_code);
}
}
+ else
+ {
+ requester.markFree(eid, hdr->instance_id);
+ }
return response;
}
@@ -180,7 +186,10 @@
exit(EXIT_FAILURE);
}
- auto callback = [verbose](IO& /*io*/, int fd, uint32_t revents) {
+ auto bus = sdbusplus::bus::new_default();
+ dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
+ auto callback = [verbose, &dbusImplReq](IO& /*io*/, int fd,
+ uint32_t revents) {
if (!(revents & EPOLLIN))
{
return;
@@ -231,7 +240,7 @@
else
{
// process message and send response
- auto response = processRxMsg(requestMsg);
+ auto response = processRxMsg(requestMsg, dbusImplReq);
if (!response.empty())
{
if (verbose)
@@ -269,6 +278,8 @@
};
auto event = Event::get_default();
+ bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+ bus.request_name("xyz.openbmc_project.PLDM");
IO io(event, socketFd(), EPOLLIN, std::move(callback));
event.loop();
diff --git a/test/meson.build b/test/meson.build
index 1749605..ee509db 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -14,6 +14,7 @@
gtest = dependency('gtest', main: true, disabler: true, required: true)
gmock = dependency('gmock', disabler: true, required: true)
+pldmd = declare_dependency(sources: '../instance_id.cpp')
tests = [
'libpldm_base_test',
@@ -26,7 +27,8 @@
'libpldmresponder_bios_table_test',
'libpldmresponder_platform_test',
'libpldm_fru_test',
- 'libpldm_utils_test'
+ 'libpldm_utils_test',
+ 'pldmd_instanceid_test',
]
if get_option('oem-ibm').enabled()
@@ -41,6 +43,14 @@
implicit_include_directories: false,
link_args: dynamic_linker,
build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
- dependencies: [libpldm, libpldmresponder, gtest, gmock, dependency('sdbusplus'),dependency('phosphor-logging')]),
+ dependencies: [
+ libpldm,
+ libpldmresponder,
+ gtest,
+ gmock,
+ pldmd,
+ dependency('phosphor-dbus-interfaces'),
+ dependency('phosphor-logging'),
+ dependency('sdbusplus')]),
workdir: meson.current_source_dir())
endforeach
diff --git a/test/pldmd_instanceid_test.cpp b/test/pldmd_instanceid_test.cpp
new file mode 100644
index 0000000..35ff146
--- /dev/null
+++ b/test/pldmd_instanceid_test.cpp
@@ -0,0 +1,39 @@
+#include "instance_id.hpp"
+
+#include <stdexcept>
+
+#include <gtest/gtest.h>
+
+using namespace pldm;
+
+TEST(InstanceId, testNext)
+{
+ InstanceId id;
+ ASSERT_EQ(id.next(), 0);
+ ASSERT_EQ(id.next(), 1);
+}
+
+TEST(InstanceId, testAllUsed)
+{
+ InstanceId id;
+ for (size_t i = 0; i < maxInstanceIds; ++i)
+ {
+ ASSERT_EQ(id.next(), i);
+ }
+ EXPECT_THROW(id.next(), std::runtime_error);
+}
+
+TEST(InstanceId, testMarkfree)
+{
+ InstanceId id;
+ for (size_t i = 0; i < maxInstanceIds; ++i)
+ {
+ ASSERT_EQ(id.next(), i);
+ }
+ id.markFree(5);
+ ASSERT_EQ(id.next(), 5);
+ id.markFree(0);
+ ASSERT_EQ(id.next(), 0);
+ EXPECT_THROW(id.next(), std::runtime_error);
+ EXPECT_THROW(id.markFree(32), std::out_of_range);
+}