| /* |
| * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & |
| * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "nsm_passthrough_cmd.hpp" |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <sdbusplus/bus.hpp> |
| |
| #include <chrono> |
| #include <fstream> |
| #include <iostream> |
| #include <ostream> |
| #include <string> |
| #include <thread> |
| |
| namespace nsmtool |
| { |
| namespace passthrough |
| { |
| |
| std::vector<std::unique_ptr<SendNSMCommand>> sendNSMCommandObjects; |
| std::vector<std::unique_ptr<GetCommandStatus>> getCommandStatusObjects; |
| std::vector<std::unique_ptr<WaitCommandStatusComplete>> |
| waitCommandStatusCompleteObjects; |
| std::vector<std::unique_ptr<GetNSMResponse>> getNSMResponseObjects; |
| std::vector<std::unique_ptr<GetDebugInfoFromFD>> getDebugInfoFromFDObjects; |
| std::vector<std::unique_ptr<GetLogInfoFromFD>> getLogInfoFromFDObjects; |
| std::vector<std::unique_ptr<CallEraseTraceDbusAPI>> |
| callEraseTraceDbusAPIForObject; |
| std::vector<std::unique_ptr<CallEraseDebugInfoDbusAPI>> |
| callEraseDebugInfoDbusAPIForObject; |
| |
| void readAndPrintFDData(sdbusplus::message::unix_fd& unixfd) |
| { |
| std::vector<uint8_t> buffer; |
| int dupFd = dup(unixfd.fd); |
| if (dupFd < 0) |
| { |
| std::cout << "FD ERROR while duplicating." << std::endl; |
| return; |
| } |
| auto fCleanup = [dupFd](FILE* f) -> void { |
| fclose(f); |
| close(dupFd); |
| }; |
| std::unique_ptr<FILE, decltype(fCleanup)> file(fdopen(dupFd, "rb"), |
| fCleanup); |
| if (!file) |
| { |
| std::cout << "FD open ERROR." << std::endl; |
| close(dupFd); |
| return; |
| } |
| int rc = fseek(file.get(), 0, SEEK_END); |
| if (rc < 0) |
| { |
| std::cout << "FSEEK ERROR" << std::endl; |
| return; |
| } |
| auto filesize = ftell(file.get()); |
| if (filesize <= 0) |
| { |
| std::cout << "No data to print." << std::endl; |
| return; |
| } |
| rewind(file.get()); |
| size_t size = static_cast<size_t>(filesize); |
| buffer.resize(size); |
| auto len = fread(buffer.data(), 1, size, file.get()); |
| if (len != size) |
| { |
| std::cout << "Length ERROR." << std::endl; |
| return; |
| } |
| |
| // print data in format same as hexdump <file> |
| const size_t bytesPerLine = 16; |
| size_t totalBytes = buffer.size(); |
| |
| std::cout << "[Fd data] = " << std::endl; |
| for (size_t i = 0; i < totalBytes; i += bytesPerLine) |
| { |
| std::cout << std::setw(8) << std::setfill('0') << std::hex << i << " "; |
| |
| for (size_t j = 0; j < bytesPerLine; ++j) |
| { |
| if (i + j < totalBytes) |
| { |
| std::cout << std::setw(2) << std::setfill('0') << std::hex |
| << static_cast<int>(buffer[i + j]) << " "; |
| } |
| else |
| { |
| // Fill with spaces if not enough bytes |
| std::cout << " "; |
| } |
| if (j == 7) |
| { |
| // Add extra space after the first 8 bytes |
| std::cout << " "; |
| } |
| } |
| |
| // Print the ASCII representation |
| std::cout << " |"; |
| for (size_t j = 0; j < bytesPerLine; ++j) |
| { |
| if (i + j < totalBytes) |
| { |
| char ch = buffer[i + j]; |
| std::cout << (std::isprint(ch) ? ch : '.'); |
| } |
| else |
| { |
| // Fill with spaces for missing bytes |
| std::cout << ' '; |
| } |
| } |
| std::cout << "|" << std::endl; |
| } |
| } |
| |
| SendNSMCommand::SendNSMCommand(CLI::App* app) |
| { |
| std::string targetType; |
| int targetInstanceId; // Use int here to avoid issues with small integer |
| // types |
| int messageType; // Use int and cast later |
| int commandCode; // Use int and cast later |
| std::string filePath; |
| |
| // Define options using int types for the problematic fields |
| auto subcmd = app->add_subcommand("sendNSMCommand", |
| "Send NSM Passthrough Command"); |
| subcmd |
| ->add_option("-t,--targetType", targetType, |
| "Target Type (e.g., GPU, Switch, Baseboard)") |
| ->required(); |
| subcmd |
| ->add_option("-i,--targetInstanceId", targetInstanceId, |
| "Target Instance ID") |
| ->required(); |
| subcmd->add_option("-m,--messageType", messageType, "Message Type") |
| ->required(); |
| subcmd->add_option("-c,--commandCode", commandCode, "Command Code") |
| ->required(); |
| subcmd->add_option("-f,--filePath", filePath, "File path for data") |
| ->required(); |
| |
| // In the callback, cast the integers to uint8_t when necessary |
| subcmd->callback([this, &targetType, &targetInstanceId, &messageType, |
| &commandCode, &filePath]() { |
| uint8_t castedTargetInstanceId = static_cast<uint8_t>(targetInstanceId); |
| uint8_t castedMessageType = static_cast<uint8_t>(messageType); |
| uint8_t castedCommandCode = static_cast<uint8_t>(commandCode); |
| |
| this->execute(targetType, castedTargetInstanceId, castedMessageType, |
| castedCommandCode, filePath); |
| }); |
| } |
| |
| void SendNSMCommand::getMatchingFruDeviceObjectPath( |
| const std::string& targetType, uint8_t targetInstanceId, |
| std::function<void(const std::string&)> callback) |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| std::map<std::string, std::map<std::string, std::vector<std::string>>> |
| subtree; |
| |
| auto method = bus.new_method_call("xyz.openbmc_project.ObjectMapper", |
| "/xyz/openbmc_project/object_mapper", |
| "xyz.openbmc_project.ObjectMapper", |
| "GetSubTree"); |
| method.append("/xyz/openbmc_project/FruDevice/", 1, |
| std::vector<std::string>({})); |
| |
| try |
| { |
| auto reply = bus.call(method); |
| reply.read(subtree); |
| |
| for (const auto& [objectPath, interfaces] : subtree) |
| { |
| getDeviceType( |
| objectPath, targetType, targetInstanceId, |
| [this, callback](const std::string& matchedObjectPath) { |
| if (!matchedObjectPath.empty()) |
| { |
| callback(matchedObjectPath); // Pass the matched object path |
| return; // Exit early to avoid checking other devices |
| } |
| }); |
| } |
| |
| callback(""); // No match found |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| callback(""); // Error encountered |
| } |
| } |
| |
| void SendNSMCommand::getDeviceType( |
| const std::string& objectPath, const std::string& targetType, |
| uint8_t targetInstanceId, std::function<void(const std::string&)> callback) |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| auto deviceTypeMethod = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| deviceTypeMethod.append("xyz.openbmc_project.FruDevice", "DEVICE_TYPE"); |
| |
| try |
| { |
| auto deviceReply = bus.call(deviceTypeMethod); |
| std::variant<uint8_t> deviceType; |
| deviceReply.read(deviceType); |
| |
| NSMDevID targetTypeId; |
| if (targetType == "GPU") |
| targetTypeId = NSM_DEV_ID_GPU; |
| else if (targetType == "Switch") |
| targetTypeId = NSM_DEV_ID_SWITCH; |
| else if (targetType == "PCIeBridge") |
| targetTypeId = NSM_DEV_ID_PCIE_BRIDGE; |
| else if (targetType == "Baseboard") |
| targetTypeId = NSM_DEV_ID_BASEBOARD; |
| else if (targetType == "MCTPBridge") |
| targetTypeId = NSM_DEV_ID_MCTP_BRIDGE; |
| else |
| { |
| return; |
| } |
| |
| if (std::get<uint8_t>(deviceType) == targetTypeId) |
| { |
| getInstanceNumber(objectPath, targetInstanceId, callback); |
| } |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| {} |
| } |
| |
| void SendNSMCommand::getInstanceNumber( |
| const std::string& objectPath, uint8_t targetInstanceId, |
| std::function<void(const std::string&)> callback) |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| auto instanceNumberMethod = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| instanceNumberMethod.append("xyz.openbmc_project.FruDevice", |
| "INSTANCE_NUMBER"); |
| |
| try |
| { |
| auto instanceReply = bus.call(instanceNumberMethod); |
| std::variant<uint8_t> instanceNumber; |
| instanceReply.read(instanceNumber); |
| |
| if (std::get<uint8_t>(instanceNumber) == targetInstanceId) |
| { |
| callback(objectPath); // Found matching object path, stop processing |
| } |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| {} |
| } |
| |
| void SendNSMCommand::execute(const std::string& targetType, |
| uint8_t targetInstanceId, uint8_t messageType, |
| uint8_t commandCode, const std::string& filePath) |
| { |
| getMatchingFruDeviceObjectPath(targetType, targetInstanceId, |
| [this, messageType, commandCode, |
| filePath](const std::string& objectPath) { |
| if (objectPath.empty()) |
| { |
| return; |
| } |
| |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| |
| int fd = open(filePath.c_str(), O_RDONLY); |
| if (fd == -1) |
| { |
| return; |
| } |
| |
| sdbusplus::message::unix_fd unixFd(fd); |
| |
| try |
| { |
| auto method = bus.new_method_call( |
| "xyz.openbmc_project.NSM", objectPath.c_str(), |
| "xyz.openbmc_project.NSM.NSMRawCommand", "SendNSMRawCommand"); |
| method.append(messageType, commandCode, unixFd); |
| |
| auto reply = bus.call(method); |
| sdbusplus::message::object_path returnedObjectPath; |
| uint8_t completionCode; |
| reply.read(returnedObjectPath, completionCode); |
| |
| std::cout << "ObjectPath = " << std::string(returnedObjectPath) |
| << std::endl; |
| |
| close(fd); |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| {} |
| }); |
| } |
| |
| GetCommandStatus::GetCommandStatus(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand("getCommandStatus", |
| "Get NSM Command Status"); |
| subcmd->add_option("--object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void GetCommandStatus::execute(const std::string& objectPath) |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| |
| try |
| { |
| auto method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| method.append("xyz.openbmc_project.NSM.NSMRawCommandStatus", "Status"); |
| |
| auto reply = bus.call(method); |
| std::variant<std::string> status; |
| reply.read(status); |
| |
| std::cout << std::get<std::string>(status) << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| {} |
| } |
| |
| WaitCommandStatusComplete::WaitCommandStatusComplete(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand("waitCommandStatusComplete", |
| "Wait for NSM Command Completion"); |
| subcmd->add_option("--object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void WaitCommandStatusComplete::execute(const std::string& objectPath) |
| { |
| std::string status; |
| do |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| try |
| { |
| auto method = bus.new_method_call( |
| "xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| method.append("xyz.openbmc_project.NSM.NSMRawCommandStatus", |
| "Status"); |
| |
| auto reply = bus.call(method); |
| std::variant<std::string> statusVariant; |
| reply.read(statusVariant); |
| status = std::get<std::string>(statusVariant); |
| |
| std::cout << status << std::endl; |
| |
| if (status == |
| "xyz.openbmc_project.NSM.NSMRawCommandStatus.SetOperationStatus.CommandInProgress") |
| { |
| std::this_thread::sleep_for(std::chrono::milliseconds(500)); |
| } |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| return; |
| } |
| } while ( |
| status == |
| "xyz.openbmc_project.NSM.NSMRawCommandStatus.SetOperationStatus.CommandInProgress"); |
| } |
| |
| GetNSMResponse::GetNSMResponse(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand("getNSMResponse", |
| "Get NSM Command Response"); |
| subcmd->add_option("--object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void GetNSMResponse::execute(const std::string& objectPath) |
| { |
| sdbusplus::bus::bus bus = sdbusplus::bus::new_default(); |
| |
| try |
| { |
| auto method = bus.new_method_call( |
| "xyz.openbmc_project.NSM", objectPath.c_str(), |
| "xyz.openbmc_project.NSM.NSMRawCommand", "GetNSMCommandResponse"); |
| |
| auto reply = bus.call(method); |
| uint8_t completionCode; |
| uint16_t reasonCode; |
| sdbusplus::message::unix_fd responseFd; |
| reply.read(completionCode, reasonCode, responseFd); |
| |
| std::cout << "Completion Code: " << static_cast<int>(completionCode) |
| << std::endl; |
| std::cout << "Reason Code: " << static_cast<int>(reasonCode) |
| << std::endl; |
| |
| int fd = static_cast<int>(responseFd); |
| char buffer[4096]; |
| ssize_t bytesRead; |
| std::vector<uint8_t> responseData; |
| |
| // Read the response data from the file descriptor |
| while ((bytesRead = read(fd, buffer, sizeof(buffer))) > 0) |
| { |
| responseData.insert(responseData.end(), buffer, buffer + bytesRead); |
| } |
| |
| // Print the response data in hex format |
| std::cout << "Response Data (Hex): "; |
| for (const auto& byte : responseData) |
| { |
| printf("%02X ", byte); // Print each byte in hex |
| } |
| std::cout << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| {} |
| } |
| |
| GetDebugInfoFromFD::GetDebugInfoFromFD(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = |
| app->add_subcommand("getDebugInfoFromFD", |
| "Get Network Device Debug Info from FD as client"); |
| subcmd->add_option("-o, --object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void GetDebugInfoFromFD::execute(const std::string& objectPath) |
| { |
| try |
| { |
| auto bus = sdbusplus::bus::new_default(); |
| dbus::PropertyMap allProperties; |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "GetAll"); |
| method.append("com.nvidia.Dump.DebugInfo", ""); |
| auto reply = bus.call(method); |
| reply.read(allProperties); |
| |
| if (allProperties.contains("Status")) |
| { |
| std::string status = |
| std::get<std::string>(allProperties.at("Status")); |
| std::cout << "[Status] = " << status << std::endl; |
| } |
| if (allProperties.contains("NextRecordHandle")) |
| { |
| uint64_t nxtRecHndl = |
| std::get<uint64_t>(allProperties.at("NextRecordHandle")); |
| std::cout << std::dec << "[Next record handle] = " << nxtRecHndl |
| << std::endl; |
| } |
| if (allProperties.contains("RecordHandle")) |
| { |
| uint64_t recHndl = |
| std::get<uint64_t>(allProperties.at("RecordHandle")); |
| std::cout << std::dec << "[Record handle] = " << recHndl |
| << std::endl; |
| } |
| if (allProperties.contains("Fd")) |
| { |
| sdbusplus::message::unix_fd unixfd = |
| std::get<sdbusplus::message::unix_fd>(allProperties.at("Fd")); |
| |
| readAndPrintFDData(unixfd); |
| } |
| std::cout << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout << "Error while fetching data from DebugInfo PDI" |
| << std::endl; |
| } |
| } |
| |
| GetLogInfoFromFD::GetLogInfoFromFD(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand( |
| "getLogInfoFromFD", "Get Network Device Log Info from FD as client"); |
| subcmd->add_option("-o, --object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void GetLogInfoFromFD::execute(const std::string& objectPath) |
| { |
| try |
| { |
| auto bus = sdbusplus::bus::new_default(); |
| dbus::PropertyMap allProperties; |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "GetAll"); |
| method.append("com.nvidia.Dump.LogInfo", ""); |
| auto reply = bus.call(method); |
| reply.read(allProperties); |
| |
| if (allProperties.contains("Status")) |
| { |
| std::string status = |
| std::get<std::string>(allProperties.at("Status")); |
| std::cout << "[Status] = " << status << std::endl; |
| } |
| if (allProperties.contains("NextRecordHandle")) |
| { |
| uint64_t nxtRecHndl = |
| std::get<uint64_t>(allProperties.at("NextRecordHandle")); |
| std::cout << std::dec << "[Next record handle] = " << nxtRecHndl |
| << std::endl; |
| } |
| if (allProperties.contains("RecordHandle")) |
| { |
| uint64_t recHndl = |
| std::get<uint64_t>(allProperties.at("RecordHandle")); |
| std::cout << std::dec << "[Record handle] = " << recHndl |
| << std::endl; |
| } |
| if (allProperties.contains("Fd")) |
| { |
| sdbusplus::message::unix_fd unixfd = |
| std::get<sdbusplus::message::unix_fd>(allProperties.at("Fd")); |
| |
| readAndPrintFDData(unixfd); |
| } |
| if (allProperties.contains("EntryPrefix")) |
| { |
| uint64_t entryPre = |
| std::get<uint64_t>(allProperties.at("EntryPrefix")); |
| std::cout << std::dec << "[Entry Prefix] = " << entryPre |
| << std::endl; |
| } |
| if (allProperties.contains("EntrySuffix")) |
| { |
| uint64_t entrySuf = |
| std::get<uint64_t>(allProperties.at("EntrySuffix")); |
| std::cout << std::dec << "[Entry Suffix] = " << entrySuf |
| << std::endl; |
| } |
| if (allProperties.contains("Length")) |
| { |
| uint64_t len = std::get<uint64_t>(allProperties.at("Length")); |
| std::cout << std::dec << "[Length] = " << len << std::endl; |
| } |
| if (allProperties.contains("LostEvents")) |
| { |
| uint64_t lostEvnt = |
| std::get<uint64_t>(allProperties.at("LostEvents")); |
| std::cout << std::dec << "[Lost Events] = " << lostEvnt |
| << std::endl; |
| } |
| if (allProperties.contains("TimeSynced")) |
| { |
| std::string timeSync = |
| std::get<std::string>(allProperties.at("TimeSynced")); |
| std::cout << "[Time Synced] = " << timeSync << std::endl; |
| } |
| if (allProperties.contains("TimeStamp")) |
| { |
| uint64_t timeStmp = |
| std::get<uint64_t>(allProperties.at("TimeStamp")); |
| std::cout << std::dec << "[Time Stamp] = " << timeStmp << std::endl; |
| } |
| std::cout << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout << "Error while fetching data from LogInfo PDI" << std::endl; |
| } |
| } |
| |
| CallEraseTraceDbusAPI::CallEraseTraceDbusAPI(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand( |
| "callEraseTraceDbusAPI", |
| "Call Erase Trace Dbus API for Network Device as client"); |
| subcmd->add_option("-o, --object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void CallEraseTraceDbusAPI::execute(const std::string& objectPath) |
| { |
| auto bus = sdbusplus::bus::new_default(); |
| try |
| { |
| // Call Erase trace API for objectPath |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "com.nvidia.Dump.Erase", "EraseTrace"); |
| auto reply = bus.call(method); |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout << "Error while EraseTrace API call" << std::endl; |
| } |
| |
| try |
| { |
| // Check Status |
| std::variant<std::tuple<std::string, std::string>> allStatus; |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| method.append("com.nvidia.Dump.Erase", "EraseTraceStatus"); |
| std::tuple<std::string, std::string> operationAndEraseStatus; |
| |
| do |
| { |
| auto reply = bus.call(method); |
| reply.read(allStatus); |
| |
| operationAndEraseStatus = |
| std::get<std::tuple<std::string, std::string>>(allStatus); |
| } while (std::get<0>(operationAndEraseStatus) == |
| "com.nvidia.Dump.Erase.OperationStatus.InProgress"); |
| |
| std::cout << "[Operation Status] = " |
| << std::get<0>(operationAndEraseStatus) << std::endl; |
| std::cout << "[Erase Status] = " << std::get<1>(operationAndEraseStatus) |
| << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout << "Error while fetching status from EraseTraceStatus on PDI" |
| << std::endl; |
| } |
| } |
| |
| CallEraseDebugInfoDbusAPI::CallEraseDebugInfoDbusAPI(CLI::App* app) |
| { |
| std::string objectPath; |
| |
| auto subcmd = app->add_subcommand( |
| "callEraseDebugInfoDbusAPI", |
| "Call Erase Debug InfoDbus API for Network Device as client"); |
| subcmd->add_option("-o,--object_path", objectPath, "D-Bus Object Path") |
| ->required(); |
| |
| subcmd->callback([this, &objectPath]() { this->execute(objectPath); }); |
| } |
| |
| void CallEraseDebugInfoDbusAPI::execute(const std::string& objectPath) |
| { |
| auto bus = sdbusplus::bus::new_default(); |
| try |
| { |
| // Call Erase Debug Info API for objectPath |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "com.nvidia.Dump.Erase", "EraseDebugInfo"); |
| method.append("com.nvidia.Dump.Erase.EraseInfoType.FWSavedDumpInfo"); |
| auto reply = bus.call(method); |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout << "Error while EraseDebugInfo API call" << std::endl; |
| } |
| |
| try |
| { |
| // Check Status |
| std::variant<std::tuple<std::string, std::string>> allStatus; |
| sdbusplus::message::message method = |
| bus.new_method_call("xyz.openbmc_project.NSM", objectPath.c_str(), |
| "org.freedesktop.DBus.Properties", "Get"); |
| method.append("com.nvidia.Dump.Erase", "EraseDebugInfoStatus"); |
| std::tuple<std::string, std::string> operationAndEraseStatus; |
| |
| do |
| { |
| auto reply = bus.call(method); |
| reply.read(allStatus); |
| |
| operationAndEraseStatus = |
| std::get<std::tuple<std::string, std::string>>(allStatus); |
| } while (std::get<0>(operationAndEraseStatus) == |
| "com.nvidia.Dump.Erase.OperationStatus.InProgress"); |
| |
| std::cout << "[Operation Status] = " |
| << std::get<0>(operationAndEraseStatus) << std::endl; |
| std::cout << "[Erase Status] = " << std::get<1>(operationAndEraseStatus) |
| << std::endl; |
| } |
| catch (const sdbusplus::exception::SdBusError& e) |
| { |
| std::cout |
| << "Error while fetching status from EraseDebugInfoStatus on PDI" |
| << std::endl; |
| } |
| } |
| |
| void registerCommand(CLI::App& app) |
| { |
| auto* passthroughApp = app.add_subcommand( |
| "passthrough", "Passthrough command support for dbus API testing"); |
| |
| // Using unique_ptr to manage the dynamically allocated commands |
| auto sendNSMCommand = std::make_unique<SendNSMCommand>(passthroughApp); |
| auto getCommandStatus = std::make_unique<GetCommandStatus>(passthroughApp); |
| auto waitCommandStatusComplete = |
| std::make_unique<WaitCommandStatusComplete>(passthroughApp); |
| auto getNSMResponse = std::make_unique<GetNSMResponse>(passthroughApp); |
| auto getDebugInfoFromFD = |
| std::make_unique<GetDebugInfoFromFD>(passthroughApp); |
| auto getLogInfoFromFD = std::make_unique<GetLogInfoFromFD>(passthroughApp); |
| auto callEraseTraceDbusAPI = |
| std::make_unique<CallEraseTraceDbusAPI>(passthroughApp); |
| auto callEraseDebugInfoDbusAPI = |
| std::make_unique<CallEraseDebugInfoDbusAPI>(passthroughApp); |
| |
| // Push the unique_ptrs to the global vector to keep them alive |
| sendNSMCommandObjects.push_back(std::move(sendNSMCommand)); |
| getCommandStatusObjects.push_back(std::move(getCommandStatus)); |
| waitCommandStatusCompleteObjects.push_back( |
| std::move(waitCommandStatusComplete)); |
| getNSMResponseObjects.push_back(std::move(getNSMResponse)); |
| getDebugInfoFromFDObjects.push_back(std::move(getDebugInfoFromFD)); |
| getLogInfoFromFDObjects.push_back(std::move(getLogInfoFromFD)); |
| callEraseTraceDbusAPIForObject.push_back(std::move(callEraseTraceDbusAPI)); |
| callEraseDebugInfoDbusAPIForObject.push_back( |
| std::move(callEraseDebugInfoDbusAPI)); |
| } |
| |
| } // namespace passthrough |
| } // namespace nsmtool |