tool: Refactor base type Commands
Each command will be implemented as a CLI subcommand
command handers registration process:
CLI::App app;
auto base = app.add_subcommand("base");
auto GetPLDMVersion = base->add_subcommand("GetPLDMVersion");
/* register callback for GetPLDMVersion Command */
GetPLDMVersion->callback(exec());
CLI11_PARSER();
Each command will be implemented as a class. To avoid duplicate,
An interface class is abstracted as the base class for commands.
CommandInterface
{
CommandInterface(CLI::App* app){
app->callback([&](){exec();}) //register exec() to CLI11
}
virtual createRequestMsg();
virtual parseResponseMsg();
exec(){
createRequestMsg();
send_recv();
parseResponseMsg();
}
};
GetPLDMVersion : public CommandInterface
{
GetPLDMVersion(CLI::App *app){
app->add_option(); // add options for this command
}
...
}
Then, the main is like below:
int main()
{
CLI::App app{"PLDM requester tool for OpenBMC"};
auto base = app.add_subcommand("base");
auto version = base->add_subcommand("GetPLDMVersion");
GetPLDMVersion getPLDMVersion(version);
CLI11_PARSE(app, argc, argv);
}
Tested:
root@fp5280g2:~# pldmtool base GetPLDMTypes
Encode request successfully
Request Message:
08 01 80 00 04
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 5
Total length:5
Loopback response message:
08 01 80 00 04
On first recv(),response == request : RC = 0
Total length: 14
Shutdown Socket successful : RC = 0
Response Message:
08 01 00 00 04 00 0d 00 00 00 00 00 00 00
Supported types: 0(base) 2(platform) 3(bios)
root@fp5280g2:~# pldmtool base GetPLDMVersion -t platform
Encode request successfully
Request Message:
08 01 80 00 03 00 00 00 00 01 02
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 11
Total length:11
Loopback response message:
08 01 80 00 03 00 00 00 00 01 02
On first recv(),response == request : RC = 0
Total length: 15
Shutdown Socket successful : RC = 0
Response Message:
08 01 00 00 03 00 00 00 00 00 05 f1 f1 f1 00
Type 2(platform): 1.1.1
root@fp5280g2:~# pldmtool raw -d 0x80 0x00 0x04
Encode request successfully
Request Message:
08 01 80 00 04
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 5
Total length:5
Loopback response message:
08 01 80 00 04
On first recv(),response == request : RC = 0
Total length: 14
Shutdown Socket successful : RC = 0
Response Message:
08 01 00 00 04 00 0d 00 00 00 00 00 00 00
Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I658b2c8094e9e5d972d786b26f9f8d52bc011981
diff --git a/tool/pldm_base_cmd.cpp b/tool/pldm_base_cmd.cpp
index 7c199c1..601635c 100644
--- a/tool/pldm_base_cmd.cpp
+++ b/tool/pldm_base_cmd.cpp
@@ -2,258 +2,167 @@
#include "pldm_cmd_helper.hpp"
+#include <map>
+#include <memory>
#include <string>
+#include <vector>
-constexpr uint8_t PLDM_ENTITY_ID = 8;
-constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
-constexpr uint8_t PLDM_LOCAL_INSTANCE_ID = 0;
+#include "libpldm/utils.h"
-using namespace std;
-
-/*
- * Main function that handles the GetPLDMTypes response callback via mctp
- *
- */
-void getPLDMTypes(vector<std::string>&& /*args*/)
+namespace pldmtool
{
- // Create and encode the request message
- vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
- sizeof(MCTP_MSG_TYPE_PLDM) +
- sizeof(PLDM_ENTITY_ID));
- auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
- // Encode the get_types request message
- uint8_t instanceId = PLDM_LOCAL_INSTANCE_ID;
- auto returnCode = encode_get_types_req(instanceId, request);
- if (returnCode)
- {
- cerr << "Failed to encode request msg for GetPLDMType : RC = "
- << returnCode << endl;
- return;
- }
- cout << "Encoded request succesfully : RC = " << returnCode << endl;
-
- // Insert the PLDM message type and EID at the begining of the request msg.
- requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
- requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
- cout << "Request Message:" << endl;
- printBuffer(requestMsg);
-
- // Create the response message
- vector<uint8_t> responseMsg;
-
- // Compares the response with request packet on first socket recv() call.
- // If above condition is qualified then, reads the actual response from
- // the socket to output buffer responseMsg.
- returnCode = mctpSockSendRecv(requestMsg, responseMsg);
- if (!returnCode)
- {
- cout << "Socket recv() successful : RC = " << returnCode << endl;
- cout << "Response Message : " << endl;
- printBuffer(responseMsg);
- }
- else
- {
- cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
- return;
- }
-}
-
-/*
- * Main function that handles the GetPLDMVersion response callback via mctp
- *
- */
-void getPLDMVersion(vector<std::string>&& args)
+namespace base
{
- // Create a request packet
- std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
- PLDM_GET_VERSION_REQ_BYTES);
- auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
- uint8_t pldmType = 0x0;
-
- if (!args[1].c_str())
- {
- cout << "Mandatory argument PLDM Command Type not provided!" << endl;
- cout << "Run pldmtool --help for more information" << endl;
- return;
- }
-
- if (!strcasecmp(args[1].c_str(), "base"))
- {
- cout << "PLDM Type requested : " << args[1] << endl;
- pldmType = PLDM_BASE;
- }
- else if (!strcasecmp(args[1].c_str(), "bios"))
- {
- cout << "PLDM Type requested : " << args[1] << endl;
- pldmType = PLDM_BIOS;
- }
- else if (!strcasecmp(args[1].c_str(), "fru"))
- {
- cout << "PLDM Type requested : " << args[1] << endl;
- pldmType = PLDM_FRU;
- }
- else if (!strcasecmp(args[1].c_str(), "oem"))
- {
- cout << "PLDM Type requested : " << args[1] << endl;
- pldmType = PLDM_OEM;
- }
- else
- {
- cerr << "Unsupported pldm command type OR not supported yet : "
- << args[1] << endl;
- return;
- }
-
- uint8_t instanceId = PLDM_LOCAL_INSTANCE_ID;
- uint32_t transferHandle = 0x0;
- transfer_op_flag opFlag = PLDM_GET_FIRSTPART;
-
- // encode the get_version request
- auto returnCode = encode_get_version_req(instanceId, transferHandle, opFlag,
- pldmType, request);
- if (returnCode)
- {
- cerr << "Failed to encode request msg for GetPLDMVersion. RC = "
- << returnCode << endl;
- return;
- }
- cout << "Encoded request succesfully : RC = " << returnCode << endl;
-
- // Insert the PLDM message type and EID at the begining of the request msg.
- requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
- requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
- cout << "Request Message:" << endl;
- printBuffer(requestMsg);
-
- // Create the response message
- vector<uint8_t> responseMsg;
-
- // Compares the response with request packet on first socket recv() call.
- // If above condition is qualified then, reads the actual response from
- // the socket to output buffer responseMsg.
- returnCode = mctpSockSendRecv(requestMsg, responseMsg);
- if (!returnCode)
- {
- cout << "Socket recv() successful : RC = " << returnCode << endl;
- cout << "Response Message:" << endl;
- printBuffer(responseMsg);
- }
- else
- {
- cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
- return;
- }
-}
-
-/*
- * Main function that handles the PLDM raw command response callback via mctp
- *
- */
-void handleRawOp(vector<std::string>&& args)
+namespace
{
- // Minimu 3 bytes of header data needs to passed. else its a invalid request
- if (size(args) < 3)
+
+using namespace pldmtool::helper;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+const std::map<const char*, pldm_supported_types> pldmTypes{
+ {"base", PLDM_BASE}, {"platform", PLDM_PLATFORM}, {"bios", PLDM_BIOS},
+ {"fru", PLDM_FRU}, {"oem", PLDM_OEM},
+};
+
+} // namespace
+
+class GetPLDMTypes : public CommandInterface
+{
+ public:
+ ~GetPLDMTypes() = default;
+ GetPLDMTypes() = delete;
+ GetPLDMTypes(const GetPLDMTypes&) = delete;
+ GetPLDMTypes(GetPLDMTypes&&) = default;
+ GetPLDMTypes& operator=(const GetPLDMTypes&) = delete;
+ GetPLDMTypes& operator=(GetPLDMTypes&&) = default;
+
+ using CommandInterface::CommandInterface;
+
+ std::pair<int, std::vector<uint8_t>> createRequestMsg() override
{
- cerr << "Not enough arguments passed."
- " Minimum, need to pass PLDM header raw data"
- << endl;
- return;
+ std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ auto rc = encode_get_types_req(PLDM_LOCAL_INSTANCE_ID, request);
+ return {rc, requestMsg};
}
- // Create a request packet and initialize it
- std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
- requestMsg.clear();
-
- // Read the raw data passed in the command line
- // Form request message from the raw data passed
- for (auto&& rawByte : args)
+ void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
{
- requestMsg.insert(requestMsg.end(), stoi(rawByte, nullptr, 16));
- }
-
- // Validating the payload raw data based on pldm command type
- uint8_t pldmCmd = requestMsg[2];
- switch (pldmCmd)
- {
- case PLDM_GET_PLDM_VERSION:
- if (size(requestMsg) !=
- (sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES))
- {
- cerr << "Not enough raw data provided." << endl;
- cerr << "Total length can be = 3 bytes of header + 6 bytes"
- " for payload. Please refer spec for details"
- << endl;
- return;
- }
- break;
- case PLDM_GET_TID:
- case PLDM_GET_PLDM_TYPES:
- if (size(requestMsg) != sizeof(pldm_msg_hdr))
- {
- cerr << "Total length can be = 3 bytes of header + 0 bytes"
- " for payload. Please refer spec for details"
- << endl;
- return;
- }
- break;
- case PLDM_GET_PLDM_COMMANDS:
- if (size(requestMsg) !=
- sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES)
- {
- cerr << "Total length can be = 3 bytes of header + 5 bytes"
- " for payload. Please refer spec for details"
- << endl;
- return;
- }
- break;
- case PLDM_SET_STATE_EFFECTER_STATES:
- // payload size depends on comp_effecter_count
- // if count=1 then, request size will be 8 bytes including header
- // if count=9 then, request size will be 19 bytes including header
- if ((size(requestMsg) < 8) ||
- (size(requestMsg) >
- sizeof(pldm_msg_hdr) +
- PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES))
- {
- cerr << "Total length can be = 3 bytes of header + min/max 8/19"
- " bytes for payload. Please refer spec for details"
- << endl;
- return;
- }
- break;
- default:
- cerr << "Command Not supported/implemented : " << args[2] << endl;
- cerr << "Contact backend Team" << endl;
+ uint8_t cc = 0;
+ std::vector<bitfield8_t> types(8);
+ auto rc = decode_get_types_resp(responsePtr, payloadLength, &cc,
+ types.data());
+ if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+ {
+ std::cerr << "Response Message Error: "
+ << "rc=" << rc << ",cc=" << (int)cc << std::endl;
return;
+ }
+
+ printPldmTypes(types);
}
- // Add the MCTP type and PLDM entity id at the end
- requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
- requestMsg.insert(requestMsg.begin(), PLDM_ENTITY_ID);
-
- cout << "Request Message" << endl;
- printBuffer(requestMsg);
-
- // Create the response message
- vector<uint8_t> responseMsg;
-
- // Compares the response with request packet on first socket recv() call.
- // If above condition is qualified then, reads the actual response from
- // the socket to output buffer responseMsg.
- int returnCode = mctpSockSendRecv(requestMsg, responseMsg);
- if (!returnCode)
+ private:
+ void printPldmTypes(std::vector<bitfield8_t>& types)
{
- cout << "Socket recv() successful : RC = " << returnCode << endl;
- cout << "Response Message:" << endl;
- printBuffer(responseMsg);
+ std::cout << "Supported types:";
+ for (int i = 0; i < PLDM_MAX_TYPES; i++)
+ {
+ bitfield8_t b = types[i / 8];
+ if (b.byte & (1 << i % 8))
+ {
+ std::cout << " " << i;
+ auto it = std::find_if(
+ pldmTypes.begin(), pldmTypes.end(),
+ [i](const auto& typePair) { return typePair.second == i; });
+ if (it != pldmTypes.end())
+ {
+
+ std::cout << "(" << it->first << ")";
+ }
+ }
+ }
+
+ std::cout << std::endl;
}
- else
+};
+
+class GetPLDMVersion : public CommandInterface
+{
+ public:
+ ~GetPLDMVersion() = default;
+ GetPLDMVersion() = delete;
+ GetPLDMVersion(const GetPLDMVersion&) = delete;
+ GetPLDMVersion(GetPLDMVersion&&) = default;
+ GetPLDMVersion& operator=(const GetPLDMVersion&) = delete;
+ GetPLDMVersion& operator=(GetPLDMVersion&&) = default;
+
+ explicit GetPLDMVersion(const char* type, const char* name, CLI::App* app) :
+ CommandInterface(type, name, app)
{
- cerr << "Failed to recieve from socket : RC = " << returnCode << endl;
- return;
+ app->add_option("-t,--type", pldmType, "pldm supported type")
+ ->required()
+ ->transform(CLI::CheckedTransformer(pldmTypes, CLI::ignore_case));
}
+ std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+ {
+ std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+ PLDM_GET_VERSION_REQ_BYTES);
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ auto rc = encode_get_version_req(PLDM_LOCAL_INSTANCE_ID, 0,
+ PLDM_GET_FIRSTPART, pldmType, request);
+ return {rc, requestMsg};
+ }
+
+ void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+ {
+ uint8_t cc = 0, transferFlag = 0;
+ uint32_t transferHandle = 0;
+ ver32_t version;
+ auto rc =
+ decode_get_version_resp(responsePtr, payloadLength, &cc,
+ &transferHandle, &transferFlag, &version);
+ if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+ {
+ std::cerr << "Response Message Error: "
+ << "rc=" << rc << ",cc=" << (int)cc << std::endl;
+ return;
+ }
+ char buffer[16] = {0};
+ ver2str(&version, buffer, sizeof(buffer));
+ std::cout << "Type " << pldmType;
+ auto it = std::find_if(
+ pldmTypes.begin(), pldmTypes.end(),
+ [&](const auto& typePair) { return typePair.second == pldmType; });
+
+ if (it != pldmTypes.end())
+ {
+ std::cout << "(" << it->first << ")";
+ }
+ std::cout << ": " << buffer << std::endl;
+ }
+
+ private:
+ pldm_supported_types pldmType;
+};
+
+void registerCommand(CLI::App& app)
+{
+ auto base = app.add_subcommand("base", "base type command");
+ base->require_subcommand(1);
+ auto getPLDMTypes =
+ base->add_subcommand("GetPLDMTypes", "get pldm supported types");
+ commands.push_back(
+ std::make_unique<GetPLDMTypes>("base", "GetPLDMTypes", getPLDMTypes));
+
+ auto getPLDMVersion =
+ base->add_subcommand("GetPLDMVersion", "get version of a certain type");
+ commands.push_back(std::make_unique<GetPLDMVersion>(
+ "base", "GetPLDMVersion", getPLDMVersion));
}
+
+} // namespace base
+} // namespace pldmtool