BMCDump: dump subtype input parameter support
The BMC dump is not accepting any parameters to specify the type of
dump or level of data to be collected. It was always creating a default
user-requested dump.
This commit allows for the specification of the dump type during the
dump creation process. A new table has been added in a new header file
which stores the valid dump types. When a new dump is requested, the
specified dump type is verified against this table. If no dump type is
mentioned, a user-requested BMC dump is created for backward
compatibility. If an invalid dump type is mentioned, an Invalid
Argument exception is thrown.
Tested:
- Create BMC dump with no arguments
- Create BMC dump with type as user
- Create a error log dump and make sure other types of dumps
which is using internal interface is not impacted.
- Built with master and p10bmc
Change-Id: I79f68be6ac6892ac7754b7221db64c22330b1822
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/dump_manager_bmc.cpp b/dump_manager_bmc.cpp
index 8161f41..6c99099 100644
--- a/dump_manager_bmc.cpp
+++ b/dump_manager_bmc.cpp
@@ -4,6 +4,7 @@
#include "bmc_dump_entry.hpp"
#include "dump_internal.hpp"
+#include "dump_types.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
#include "xyz/openbmc_project/Dump/Create/error.hpp"
@@ -31,6 +32,7 @@
using namespace phosphor::logging;
bool Manager::fUserDumpInProgress = false;
+constexpr auto BMC_DUMP = "BMC_DUMP";
namespace internal
{
@@ -50,11 +52,6 @@
lg2::warning("BMC dump accepts not more than 2 additional parameters");
}
- if (Manager::fUserDumpInProgress == true)
- {
- elog<sdbusplus::xyz::openbmc_project::Common::Error::Unavailable>();
- }
-
// Get the originator id and type from params
std::string originatorId;
originatorTypes originatorType;
@@ -62,8 +59,29 @@
phosphor::dump::extractOriginatorProperties(params, originatorId,
originatorType);
- std::vector<std::string> paths;
- auto id = captureDump(Type::UserRequested, paths);
+ using CreateParameters =
+ sdbusplus::common::xyz::openbmc_project::dump::Create::CreateParameters;
+
+ DumpTypes dumpType = DumpTypes::USER;
+ std::string type = extractParameter<std::string>(
+ convertCreateParametersToString(CreateParameters::DumpType), params);
+ if (!type.empty())
+ {
+ dumpType = validateDumpType(type, BMC_DUMP);
+ }
+ std::string path = extractParameter<std::string>(
+ convertCreateParametersToString(CreateParameters::FilePath), params);
+
+ if ((Manager::fUserDumpInProgress == true) && (dumpType == DumpTypes::USER))
+ {
+ lg2::info("Another user initiated dump in progress");
+ elog<sdbusplus::xyz::openbmc_project::Common::Error::Unavailable>();
+ }
+
+ lg2::info("Initiating new BMC dump with type: {TYPE} path: {PATH}", "TYPE",
+ dumpTypeToString(dumpType).value(), "PATH", path);
+
+ auto id = captureDump(dumpType, path);
// Entry Object path.
auto objPath = std::filesystem::path(baseEntryPath) / std::to_string(id);
@@ -89,13 +107,23 @@
elog<InternalFailure>();
}
- Manager::fUserDumpInProgress = true;
+ if (dumpType == DumpTypes::USER)
+ {
+ Manager::fUserDumpInProgress = true;
+ }
return objPath.string();
}
uint32_t Manager::captureDump(Type type,
const std::vector<std::string>& fullPaths)
{
+ // get dreport type map entry
+ auto tempType = TypeMap.find(type);
+ return captureDump(stringToDumpType(tempType->second).value(),
+ fullPaths.front());
+}
+uint32_t Manager::captureDump(DumpTypes type, const std::string& path)
+{
// Get Dump size.
auto size = getAllowedSize();
@@ -107,12 +135,10 @@
auto id = std::to_string(lastEntryId + 1);
dumpPath /= id;
- // get dreport type map entry
- auto tempType = TypeMap.find(type);
+ auto strType = dumpTypeToString(type).value();
execl("/usr/bin/dreport", "dreport", "-d", dumpPath.c_str(), "-i",
id.c_str(), "-s", std::to_string(size).c_str(), "-q", "-v", "-p",
- fullPaths.empty() ? "" : fullPaths.front().c_str(), "-t",
- tempType->second.c_str(), nullptr);
+ path.empty() ? "" : path.c_str(), "-t", strType.c_str(), nullptr);
// dreport script execution is failed.
auto error = errno;
@@ -124,7 +150,7 @@
else if (pid > 0)
{
Child::Callback callback = [this, type, pid](Child&, const siginfo_t*) {
- if (type == Type::UserRequested)
+ if (type == DumpTypes::USER)
{
lg2::info("User initiated dump completed, resetting flag");
Manager::fUserDumpInProgress = false;
diff --git a/dump_manager_bmc.hpp b/dump_manager_bmc.hpp
index 6dbb7ad..22e688d 100644
--- a/dump_manager_bmc.hpp
+++ b/dump_manager_bmc.hpp
@@ -113,6 +113,14 @@
*/
uint32_t captureDump(Type type, const std::vector<std::string>& fullPaths);
+ /** @brief Capture BMC Dump based on the Dump type.
+ * @param[in] type - Type of the dump to pass to dreport
+ * @param[in] path - An absolute path to the file
+ * to be included as part of Dump package.
+ * @return id - The Dump entry id number.
+ */
+ uint32_t captureDump(DumpTypes type, const std::string& path);
+
/** @brief Remove specified watch object pointer from the
* watch map and associated entry from the map.
* @param[in] path - unique identifier of the map
diff --git a/dump_types.cpp b/dump_types.cpp
new file mode 100644
index 0000000..539bca4
--- /dev/null
+++ b/dump_types.cpp
@@ -0,0 +1,77 @@
+#include "dump_types.hpp"
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+namespace phosphor
+{
+namespace dump
+{
+DUMP_TYPE_TABLE dumpTypeTable = {
+ {"xyz.openbmc_project.Dump.Create.DumpType.UserRequested",
+ {DumpTypes::USER, "BMC_DUMP"}}};
+
+DUMP_TYPE_TO_STRING_MAP dumpTypeToStringMap = {
+ {DumpTypes::USER, "user"},
+};
+
+std::optional<std::string> dumpTypeToString(const DumpTypes& dumpType)
+{
+ auto it = dumpTypeToStringMap.find(dumpType);
+ if (it != dumpTypeToStringMap.end())
+ {
+ return it->second;
+ }
+ return std::nullopt;
+}
+
+std::optional<DumpTypes> stringToDumpType(const std::string& str)
+{
+ auto it = std::ranges::find_if(dumpTypeToStringMap,
+ [&str](const auto& pair) {
+ return pair.second == str;
+ });
+
+ if (it != dumpTypeToStringMap.end())
+ {
+ return it->first;
+ }
+ return std::nullopt;
+}
+
+DumpTypes validateDumpType(const std::string& type, const std::string& category)
+{
+ using namespace phosphor::logging;
+ using InvalidArgument =
+ sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+ // Dump type user will be return if type is empty
+ DumpTypes dumpType = DumpTypes::USER;
+ if (type.empty())
+ {
+ return dumpType;
+ }
+
+ // Find any matching dump collection type for the category
+ auto it = std::find_if(dumpTypeTable.begin(), dumpTypeTable.end(),
+ [&](const auto& pair) {
+ return pair.first == type && pair.second.second == category;
+ });
+
+ if (it != dumpTypeTable.end())
+ {
+ dumpType = it->second.first;
+ }
+ else
+ {
+ lg2::error("An invalid dump type: {TYPE} passed", "TYPE", type);
+ elog<InvalidArgument>(Argument::ARGUMENT_NAME("BMC_DUMP_TYPE"),
+ Argument::ARGUMENT_VALUE(type.c_str()));
+ }
+ return dumpType;
+}
+
+} // namespace dump
+} // namespace phosphor
diff --git a/dump_types.hpp b/dump_types.hpp
new file mode 100644
index 0000000..be1e92d
--- /dev/null
+++ b/dump_types.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <optional>
+#include <ranges>
+#include <string>
+#include <unordered_map>
+
+namespace phosphor
+{
+namespace dump
+{
+// Overall dump category for example BMC dump
+using DUMP_CATEGORY = std::string;
+
+// Dump type
+using DUMP_TYPE = std::string;
+
+// Dump collection indicator
+using DUMP_COLLECTION_TYPE = std::string;
+
+// Dump types
+enum class DumpTypes
+{
+ USER,
+};
+
+// A table of dump types
+using DUMP_TYPE_TABLE =
+ std::unordered_map<DUMP_TYPE, std::pair<DumpTypes, DUMP_CATEGORY>>;
+
+// Mapping between dump type and dump collection type string
+using DUMP_TYPE_TO_STRING_MAP =
+ std::unordered_map<DumpTypes, DUMP_COLLECTION_TYPE>;
+
+/**
+ * @brief Converts a DumpTypes enum value to dump name.
+ *
+ * @param[in] dumpType The DumpTypes value to be converted.
+ * @return Name of the dump as string, std::nullopt if not found.
+ */
+std::optional<std::string> dumpTypeToString(const DumpTypes& dumpType);
+
+/**
+ * @brief Converts dump name to its corresponding DumpTypes enum value.
+ *
+ * @param[in] str The string to be converted to a DumpTypes value.
+ * @return The DumpTypes value that corresponds to the name or std::nullopt if
+ * not found.
+ */
+std::optional<DumpTypes> stringToDumpType(const std::string& str);
+
+/**
+ * @brief Validates dump type and returns corresponding collection type
+ *
+ * This function checks the provided dump type against the specified category.
+ * If the dump type is empty, it defaults to "user". If the dump type does not
+ * exist or does not match with the specified category, it logs an error and
+ * throws an InvalidArgument exception.
+ *
+ * @param[in] type - The dump type to be validated.
+ * @param[in] category - The category to match against the dump type.
+ *
+ * @return The corresponding dump collection type if the dump type and category
+ * match an entry in the dumpTypeTable. If the type is empty or does not match
+ * any entry, it returns "user".
+ *
+ * @throws InvalidArgument - Thrown if the type does not match the specified
+ * category or does not exist in the table.
+ */
+DumpTypes validateDumpType(const std::string& type,
+ const std::string& category);
+
+} // namespace dump
+} // namespace phosphor
diff --git a/dump_utils.cpp b/dump_utils.cpp
index 792138c..da703ec 100644
--- a/dump_utils.cpp
+++ b/dump_utils.cpp
@@ -1,5 +1,7 @@
#include "dump_utils.hpp"
+#include "dump_types.hpp"
+
#include <phosphor-logging/lg2.hpp>
namespace phosphor
diff --git a/dump_utils.hpp b/dump_utils.hpp
index 6d39bef..01e4166 100644
--- a/dump_utils.hpp
+++ b/dump_utils.hpp
@@ -1,5 +1,6 @@
#pragma once
#include "dump_manager.hpp"
+#include "dump_types.hpp"
#include <systemd/sd-event.h>
#include <unistd.h>
@@ -300,5 +301,39 @@
return (getHostState() == HostState::Quiesced);
}
+/** @brief Extract the dump create parameters
+ * @param[in] key - The name of the parameter
+ * @param[in] params - The map of parameters passed as input
+ *
+ * @return On success, a std::optional containing the value of the parameter
+ * (of type T). On failure (key not found in the map or the value is not of type
+ * T), returns an empty std::optional.
+ */
+template <typename T>
+T extractParameter(const std::string& key,
+ phosphor::dump::DumpCreateParams& params)
+{
+ using InvalidArgument =
+ sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
+ auto it = params.find(key);
+ if (it != params.end())
+ {
+ const auto& [foundKey, variantValue] = *it;
+ if (std::holds_alternative<T>(variantValue))
+ {
+ return std::get<T>(variantValue);
+ }
+ else
+ {
+ lg2::error("An invalid input passed for key: {KEY}", "KEY", key);
+ elog<InvalidArgument>(Argument::ARGUMENT_NAME(key.c_str()),
+ Argument::ARGUMENT_VALUE("INVALID INPUT"));
+ }
+ }
+ return T{};
+}
+
} // namespace dump
} // namespace phosphor
diff --git a/meson.build b/meson.build
index 1ba3e32..5696b45 100644
--- a/meson.build
+++ b/meson.build
@@ -160,6 +160,7 @@
'dump_offload.cpp',
'dump_manager_faultlog.cpp',
'faultlog_dump_entry.cpp',
+ 'dump_types.cpp'
]
phosphor_dump_manager_dependency = [