Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions common/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
#include <string>
#include <vector>

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <sys/mman.h>
#include <unistd.h>

PHOSPHOR_LOG2_USING;

namespace pldm
Expand Down Expand Up @@ -610,6 +617,88 @@ int emitRDEDeviceDetectedSignal(
return PLDM_SUCCESS;
}

void emitPldmMessagePollEventSignal(
uint8_t formatVersion, uint8_t tid, const std::string& tName,
uint8_t eventClass, uint32_t dataTransferHandle, uint16_t eventId,
uint16_t eventDataSize, int fd) {

try
{
auto& bus = DBusHandler::getBus();
auto msg = bus.new_signal("/xyz/openbmc_project/pldm",
"xyz.openbmc_project.PLDM.Event",
"PldmMessagePollEvent");

// Generate the current timestamp in microseconds
uint64_t timestamp = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();

// Please follow/comply_with the signature in yaml file
msg.append(timestamp,
tid,
tName,
formatVersion,
eventClass,
eventId,
dataTransferHandle,
eventDataSize,
sdbusplus::message::unix_fd(fd));
msg.signal_send();
}
catch (const std::exception& e)
{
lg2::error("Failed to emit PLDM pldmMessagePollEvent signal: {ERROR}",
"ERROR", e.what());
return;
}

lg2::info("Emitting PLDM Message Poll Event signal: FormatVersion={FV}, TID={TID}, "
"TerminusName={NAME}, EventClass={CLASS}, EventId={ID}, "
"DataTransferHandlee={DTH}, "
"Size={SIZE}, FD={FD}",
"FV", formatVersion,
"TID", tid,
"NAME", tName,
"CLASS", lg2::hex, eventClass,
"ID", lg2::hex, eventId,
"DTH", lg2::hex, dataTransferHandle,
"SIZE", lg2::hex, eventDataSize,
"FD", fd);
}

int create_mem_fd(const std::vector<uint8_t>& data)
{
// Create the anonymous file in RAM
int fd = memfd_create("event_data", MFD_CLOEXEC);
if (fd == -1) {
lg2::error("Failed to create memfd, errno: {ERRNO}",
"ERRNO", errno);
return -1;
}

size_t dataSize = data.size();
lg2::info("truncate memfd to size {SIZE}", "SIZE", dataSize);

if (ftruncate(fd, dataSize) == -1) {
lg2::error("Failed to truncate memfd to size {SIZE}, errno: {ERRNO}",
"SIZE", dataSize, "ERRNO", errno);
close(fd);
return -1;
}

if (write(fd, data.data(), dataSize) == -1) {
lg2::error("Failed to write to memfd, errno: {ERRNO}", "ERRNO", errno);
close(fd);
return -1;
}

// Reset the file offset to the beginning for the receiver
lseek(fd, 0, SEEK_SET);

return fd;
}

void recoverMctpEndpoint(const std::string& endpointObjPath)
{
auto& bus = DBusHandler::getBus();
Expand Down
27 changes: 27 additions & 0 deletions common/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <xyz/openbmc_project/Inventory/Manager/client.hpp>
#include <xyz/openbmc_project/Logging/Entry/server.hpp>
#include <xyz/openbmc_project/ObjectMapper/client.hpp>
#include <xyz/openbmc_project/PLDM/Event/server.hpp>

#include <cstdint>
#include <deque>
Expand Down Expand Up @@ -580,6 +581,32 @@ int emitRDEDeviceDetectedSignal(
uint8_t tid, eid mctpEid, pldm::UUID devUUID,
const std::vector<std::vector<uint8_t>>& pdrPayloads);

/** @brief Emit a D-Bus signal for a PLDM Message Poll event.
*
* This signal notifies subscribers that a message poll event has been
* received from a specific terminal, providing the necessary metadata
* to retrieve the event data.
*
* @param[in] formatVersion - The version of the event format (from PLDM spec)
* @param[in] tid - Terminal ID of the source
* @param[in] tName - Terminal name or identifier string
* @param[in] eventClass - The class of the event being polled
* @param[in] dataTransferHandle - Handle used to identify the data transfer
* @param[in] eventId - The unique identifier for the event
* @param[in] eventDataSize - The size of the event data in bytes
* @param[in] fd - File descriptor for the data transfer, if applicable
*/
void emitPldmMessagePollEventSignal(
uint8_t formatVersion, uint8_t tid, const std::string& tName,
uint8_t eventClass, uint32_t dataTransferHandle,
uint16_t eventId, uint16_t eventDataSize, int fd);

/** @brief Create a memfd and write data to it
* @param[in] data - data to write to the memfd
* @return fd - the file descriptor of the memfd
*/
int create_mem_fd(const std::vector<uint8_t>& data);

/**
* @brief call Recover() method to recover an MCTP Endpoint
* @param[in] MCTP Endpoint's object path
Expand Down
114 changes: 112 additions & 2 deletions platform-mc/event_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,84 @@ namespace platform_mc
{
namespace fs = std::filesystem;

void EventManager::logPldmErrorEvent(
pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
const uint8_t* eventData, size_t eventDataSize)
{
fs::path dir{"/tmp/pldmeventlog"};
fs::path filePath{"<unknown>"};

try
{
// Ensure directory exists (safe even if already exists)
fs::create_directories(dir);

// Epoch timestamp (seconds)
auto now = std::chrono::system_clock::now();
auto epoch =
std::chrono::duration_cast<std::chrono::seconds>(
now.time_since_epoch())
.count();

static std::atomic<uint32_t> counter{0};

// Build filename with hex fields
std::ostringstream filename;
filename << "pldm_oob_err_" << epoch
<< "_" << counter++
<< "_ec0x" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(eventClass)
<< "_tid0x" << std::setw(2)
<< static_cast<int>(tid)
<< "_eventid0x" << std::setw(4)
<< eventId
<< ".bin";

filePath = dir / filename.str();

// Open file
std::ofstream ofs(filePath, std::ios::binary);
if (!ofs)
{
lg2::error(
"Failed to open PLDM event file. PATH={PATH} ERRNO={ERRNO} ERRMSG={ERRMSG}",
"PATH", filePath.string(),
"ERRNO", errno,
"ERRMSG", std::strerror(errno));

return;
}

// Write raw event data
ofs.write(reinterpret_cast<const char*>(eventData),
eventDataSize);

if (!ofs)
{
lg2::error(
"Failed to write PLDM event data. PATH={PATH}",
"PATH", filePath.string());
return;
}
}
catch (const std::exception& e)
{
lg2::error(
"Exception writing PLDM event file. PATH={PATH} ERROR={ERROR}",
"PATH", filePath.string(),
"ERROR", e.what());
return;
}

// Use debug to avoid log flooding in production
lg2::debug(
"PLDM event file created. PATH={PATH} TID={TID} EVENTID={EVID} EVENTCLASS={EVCLASS}",
"PATH", filePath.string(),
"TID", static_cast<uint32_t>(tid),
"EVID", lg2::hex, static_cast<uint32_t>(eventId),
"EVCLASS", lg2::hex, static_cast<uint32_t>(eventClass));
}

int EventManager::handlePlatformEvent(
pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
const uint8_t* eventData, size_t eventDataSize)
Expand Down Expand Up @@ -103,6 +181,9 @@ int EventManager::handlePlatformEvent(
terminus->pollEvent = true;
terminus->pollEventId = poll_event.event_id;
terminus->pollDataTransferHandle = poll_event.data_transfer_handle;

if (eventId != PLDM_PLATFORM_EVENT_ID_NULL && verbose)
logPldmErrorEvent(tid, eventId, eventClass, eventData, eventDataSize);
}

return PLDM_SUCCESS;
Expand Down Expand Up @@ -525,9 +606,25 @@ int EventManager::getNextPartParameters(
return PLDM_SUCCESS;
}

std::string EventManager::getTerminusName(pldm_tid_t tid) const
{
auto it = termini.find(tid);
if (it != termini.end())
{
auto& terminus = it->second;
auto tNameOpt = terminus->getTerminusName();
if (tNameOpt)
{
return std::string(*tNameOpt);
}
}
// Fallback: Return TID as a string if name isn't available
return std::to_string(tid);
}

void EventManager::callPolledEventHandlers(pldm_tid_t tid, uint8_t eventClass,
uint16_t eventId,
std::vector<uint8_t>& eventMessage)
uint8_t formatVersion, uint32_t dataTransferHandle,
uint16_t eventId, std::vector<uint8_t>& eventMessage)
{
try
{
Expand All @@ -541,6 +638,18 @@ void EventManager::callPolledEventHandlers(pldm_tid_t tid, uint8_t eventClass,
lg2::error(
"Failed to handle platform event msg for terminus {TID}, event {EVENTID} return {RET}",
"TID", tid, "EVENTID", eventId, "RET", rc);
} else {
lg2::info("Handle platform event msg for terminus {TID}, event {EVENTID}, size {EVSIZE}",
"TID", tid, "EVENTID", lg2::hex, eventId, "EVSIZE", lg2::hex, eventMessage.size());

int fd = pldm::utils::create_mem_fd(eventMessage);
if (fd != -1) {
std::string tName = getTerminusName(tid);
pldm::utils::emitPldmMessagePollEventSignal(
formatVersion, tid, tName, eventClass, dataTransferHandle,
eventId, eventMessage.size(), fd);
close(fd);
}
}
}
}
Expand Down Expand Up @@ -617,6 +726,7 @@ exec::task<int> EventManager::pollForPlatformEventTask(
if (eventHandlers.contains(polledEventClass))
{
callPolledEventHandlers(polledEventTid, polledEventClass,
formatVersion, pollDataTransferHandle,
polledEventId, eventMessage);
}
eventMessage.clear();
Expand Down
35 changes: 32 additions & 3 deletions platform-mc/event_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class EventManager
virtual ~EventManager() = default;

explicit EventManager(TerminusManager& terminusManager,
TerminiMapper& termini) :
TerminiMapper& termini, const bool verbose) :
terminusManager(terminusManager), termini(termini)
{
// Default response handler for PollForPlatFormEventMessage
Expand All @@ -59,6 +59,7 @@ class EventManager
return this->handlePlatformEvent(tid, eventId, PLDM_CPER_EVENT,
eventData, eventDataSize);
}});
this->verbose = verbose;
};

/** @brief Handle platform event
Expand Down Expand Up @@ -212,13 +213,39 @@ class EventManager
*
* @param[in] tid - terminus ID
* @param[out] eventClass - Event class
* @param[in] formatVersion - The PLDM version/format of the event data
* @param[in] dataTransferHandle - Handle identifying the specific data block
* in the event transfer
* @param[out] eventId - Event ID
* @param[in] eventMessage - event data of response message
*
*/
void callPolledEventHandlers(pldm_tid_t tid, uint8_t eventClass,
uint16_t eventId,
std::vector<uint8_t>& eventMessage);
uint8_t formatVersion, uint32_t dataTransferHandle,
uint16_t eventId, std::vector<uint8_t>& eventMessage);

/** @brief Log a PLDM error event to the BMC journal or event log.
*
* This function processes incoming PLDM events and creates a corresponding
* error entry. It ensures the event data is parsed according to the specified
* event class.
*
* @param[in] tid - Terminal ID of the source that generated the event
* @param[in] eventId - The unique identifier for the specific event
* @param[in] eventClass - The class of the event (e.g., sensor, effecter)
* @param[in] eventData - Pointer to the raw event data buffer
* @param[in] eventDataSize - Size of the event data buffer in bytes
*/
void logPldmErrorEvent(
pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
const uint8_t* eventData, size_t eventDataSize);

/** @brief Get the terminus name for a given TID
*
* @param[in] tid - Terminal ID
* @return The terminus name as a string, or a fallback string if not found
*/
std::string getTerminusName(pldm_tid_t tid) const;

/** @brief Reference of terminusManager */
TerminusManager& terminusManager;
Expand All @@ -231,6 +258,8 @@ class EventManager

/** @brief map of PLDM event type of polled event to EventHandlers */
pldm::platform_mc::EventMap eventHandlers;

bool verbose{false};
};
} // namespace platform_mc
} // namespace pldm
8 changes: 5 additions & 3 deletions platform-mc/manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ class Manager : public pldm::MctpDiscoveryHandlerIntf
~Manager() = default;

explicit Manager(sdeventplus::Event& event, RequesterHandler& handler,
pldm::InstanceIdDb& instanceIdDb) :
pldm::InstanceIdDb& instanceIdDb, const bool verbose) :
terminusManager(event, handler, instanceIdDb, termini, this,
pldm::BmcMctpEid),
platformManager(terminusManager, termini, this),
sensorManager(event, terminusManager, termini, this),
eventManager(terminusManager, termini)
{}
eventManager(terminusManager, termini, verbose)
{this->verbose = verbose;}

/** @brief Helper function to do the actions before discovering terminus
*
Expand Down Expand Up @@ -287,6 +287,8 @@ class Manager : public pldm::MctpDiscoveryHandlerIntf

/** @brief map of PLDM event type to EventHandlers */
PollHandlers pollHandlers;

bool verbose{false};
};
} // namespace platform_mc
} // namespace pldm
2 changes: 1 addition & 1 deletion pldmd/pldmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ int main(int argc, char** argv)
DBusHandler dbusHandler;

std::unique_ptr<platform_mc::Manager> platformManager =
std::make_unique<platform_mc::Manager>(event, reqHandler, instanceIdDb);
std::make_unique<platform_mc::Manager>(event, reqHandler, instanceIdDb, verbose);

#ifdef LIBPLDMRESPONDER
using namespace pldm::state_sensor;
Expand Down