netipmid: Update netipmid to use ipmid as the main queue
All ipmi processing is now done in the main ipmi queue
(phosphor-host-ipmid) and messages are passed via dbus. This removes the
handler registration for providers and just passes the message along to
the main queue instead of executing the provider in-situ. This makes the
net-ipmid more like the bt-bridge or kcs-bridge that are simple channel
handlers that move messages from a medium to the queue.
Change-Id: Icc9d580fd5546505c95acf0bea47c70e09809b7d
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/Makefile.am b/Makefile.am
index 392b820..f8b2160 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,8 +41,6 @@
main.cpp \
integrity_algo.hpp \
integrity_algo.cpp \
- provider_registration.hpp \
- provider_registration.cpp \
crypt_algo.hpp \
crypt_algo.cpp \
sol/console_buffer.hpp \
@@ -71,10 +69,8 @@
$(PHOSPHOR_LOGGING_LIBS) \
$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
$(LIBIPMID_LIBS) \
- $(LIBADD_DLOPEN) \
-lchannellayer \
- -luserlayer \
- -export-dynamic
+ -luserlayer
netipmid_CXXFLAGS = \
-flto \
diff --git a/command_table.cpp b/command_table.cpp
index d0ef173..e911bc6 100644
--- a/command_table.cpp
+++ b/command_table.cpp
@@ -6,12 +6,23 @@
#include "sessions_manager.hpp"
#include <iomanip>
+#include <main.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
+#include <user_channel/user_layer.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
using namespace phosphor::logging;
+namespace ipmi
+{
+using Value = sdbusplus::message::variant<bool, uint8_t, int16_t, uint16_t,
+ int32_t, uint32_t, int64_t, uint64_t,
+ double, std::string>;
+
+} // namespace ipmi
+
namespace command
{
@@ -23,8 +34,7 @@
{
log<level::DEBUG>(
"Already Registered",
- phosphor::logging::entry("SKIPPED_ENTRY=0x%x",
- uint32_t(inCommand.command)));
+ phosphor::logging::entry("SKIPPED_ENTRY=0x%x", inCommand.command));
return;
}
@@ -43,8 +53,52 @@
if (iterator == commandTable.end())
{
- response.resize(1);
- response[0] = IPMI_CC_INVALID;
+ CommandID command(inCommand);
+
+ auto bus = getSdBus();
+ // forward the request onto the main ipmi queue
+ auto method = bus->new_method_call(
+ "xyz.openbmc_project.Ipmi.Host", "/xyz/openbmc_project/Ipmi",
+ "xyz.openbmc_project.Ipmi.Server", "execute");
+ uint8_t lun = command.lun();
+ uint8_t netFn = command.netFn();
+ uint8_t cmd = command.cmd();
+ std::shared_ptr<session::Session> session =
+ std::get<session::Manager&>(singletonPool)
+ .getSession(handler.sessionID);
+ std::map<std::string, ipmi::Value> options = {
+ {"userId", ipmi::Value(ipmi::ipmiUserGetUserId(session->userName))},
+ {"privilege", ipmi::Value(static_cast<int>(session->curPrivLevel))},
+ };
+ method.append(netFn, lun, cmd, commandData, options);
+ using IpmiDbusRspType = std::tuple<uint8_t, uint8_t, uint8_t, uint8_t,
+ std::vector<uint8_t>>;
+ IpmiDbusRspType rspTuple;
+ try
+ {
+ auto reply = bus->call(method);
+ reply.read(rspTuple);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
+ log<level::ERR>("Error sending command to ipmi queue");
+ elog<InternalFailure>();
+ }
+ auto& [rnetFn, rlun, rcmd, cc, responseData] = rspTuple;
+ if (uint8_t(netFn + 1) != rnetFn || rlun != lun || rcmd != cmd)
+ {
+ response.push_back(IPMI_CC_UNSPECIFIED_ERROR);
+ log<level::ERR>("DBus call/response mismatch from ipmi queue");
+ elog<InternalFailure>();
+ }
+ else
+ {
+ response.reserve(1 + responseData.size());
+ response.push_back(cc);
+ response.insert(response.end(), responseData.begin(),
+ responseData.end());
+ }
}
else
{
@@ -80,62 +134,13 @@
errResponse.resize(1);
errResponse[0] = IPMI_CC_INSUFFICIENT_PRIVILEGE;
log<level::INFO>("Table: Insufficient privilege for command",
- entry("LUN=%x", int(command.NetFnLun.lun)),
- entry("NETFN=%x", int(command.NetFnLun.netFn)),
- entry("CMD=%x", command.cmd));
+ entry("LUN=%x", command.lun()),
+ entry("NETFN=%x", command.netFn()),
+ entry("CMD=%x", command.cmd()));
return errResponse;
}
return functor(commandData, handler);
}
-std::vector<uint8_t>
- ProviderIpmidEntry::executeCommand(std::vector<uint8_t>& commandData,
- const message::Handler& handler)
-{
- std::vector<uint8_t> response(message::parser::MAX_PAYLOAD_SIZE - 1);
- size_t respSize = commandData.size();
- ipmi_ret_t ipmiRC = IPMI_CC_UNSPECIFIED_ERROR;
- std::shared_ptr<session::Session> session =
- std::get<session::Manager&>(singletonPool)
- .getSession(handler.sessionID);
-
- if (session->curPrivLevel >= Entry::getPrivilege())
- {
- try
- {
- ipmiRC = functor(0, 0, reinterpret_cast<void*>(commandData.data()),
- reinterpret_cast<void*>(response.data() + 1),
- &respSize, NULL);
- }
- // IPMI command handlers can throw unhandled exceptions, catch those
- // and return sane error code.
- catch (const std::exception& e)
- {
- log<level::ERR>("Table: Unspecified error for command",
- entry("EXCEPTION=%s", e.what()),
- entry("LUN=%x", int(command.NetFnLun.lun)),
- entry("NETFN=%x", int(command.NetFnLun.netFn)),
- entry("CMD=%x", command.cmd));
- respSize = 0;
- // fall through
- }
- }
- else
- {
- respSize = 0;
- ipmiRC = IPMI_CC_INSUFFICIENT_PRIVILEGE;
- }
- /*
- * respSize gets you the size of the response data for the IPMI command. The
- * first byte in a response to the IPMI command is the Completion Code.
- * So we are inserting completion code as the first byte and incrementing
- * the response payload size by the size of the completion code.
- */
- response[0] = ipmiRC;
- response.resize(respSize + sizeof(ipmi_ret_t));
-
- return response;
-}
-
} // namespace command
diff --git a/command_table.hpp b/command_table.hpp
index 1ce8f10..7e9df05 100644
--- a/command_table.hpp
+++ b/command_table.hpp
@@ -10,23 +10,31 @@
namespace command
{
-union CommandID
+struct CommandID
{
- uint32_t command;
-
- uint8_t reserved;
- message::PayloadType payloadType;
-
- union
+ static constexpr size_t lunBits = 2;
+ CommandID(uint32_t command) : command(command)
{
- uint8_t netFn : 6;
- uint8_t lun : 2;
+ }
- uint8_t netFnLun;
- } NetFnLun;
-
- uint8_t cmd;
-} __attribute__((packed));
+ uint8_t netFnLun() const
+ {
+ return static_cast<uint8_t>(command >> CHAR_BIT);
+ }
+ uint8_t netFn() const
+ {
+ return netFnLun() >> lunBits;
+ }
+ uint8_t lun() const
+ {
+ return netFnLun() & ((1 << (lunBits + 1)) - 1);
+ }
+ uint8_t cmd() const
+ {
+ return static_cast<uint8_t>(command);
+ }
+ uint32_t command;
+};
/**
* CommandFunctor is the functor register for commands defined in
@@ -199,47 +207,6 @@
};
/**
- * @class ProviderIpmidEntry
- *
- * ProviderIpmidEntry is used to register commands to the Command Table, that
- * are registered by IPMI provider libraries.
- *
- */
-class ProviderIpmidEntry final : public Entry
-{
- public:
- ProviderIpmidEntry(CommandID command, ipmid_callback_t functor,
- session::Privilege privilege) :
- Entry(command, privilege),
- functor(functor)
- {
- }
-
- /**
- * @brief Execute the command
- *
- * Execute the callback handler
- *
- * @param[in] commandData - Request Data for the command
- * @param[in] handler - Reference to the Message Handler
- *
- * @return Response data for the command
- */
- std::vector<uint8_t>
- executeCommand(std::vector<uint8_t>& commandData,
- const message::Handler& handler) override;
-
- virtual ~ProviderIpmidEntry() = default;
- ProviderIpmidEntry(const ProviderIpmidEntry&) = default;
- ProviderIpmidEntry& operator=(const ProviderIpmidEntry&) = default;
- ProviderIpmidEntry(ProviderIpmidEntry&&) = default;
- ProviderIpmidEntry& operator=(ProviderIpmidEntry&&) = default;
-
- private:
- ipmid_callback_t functor;
-};
-
-/**
* @class Table
*
* Table keeps the IPMI command entries as a sorted associative container with
diff --git a/configure.ac b/configure.ac
index 05234a0..305b7f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,8 +53,7 @@
AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])])
# Checks for library functions.
-LT_INIT([dlopen disable-static shared])
-LT_LIB_DLLOAD
+LT_INIT([disable-static shared])
AC_CONFIG_FILES([Makefile test/Makefile])
AC_OUTPUT
diff --git a/main.cpp b/main.cpp
index 43ad596..04f3d44 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,7 +5,6 @@
#include "command_table.hpp"
#include "message.hpp"
#include "message_handler.hpp"
-#include "provider_registration.hpp"
#include "socket_channel.hpp"
#include "sol_module.hpp"
@@ -19,7 +18,6 @@
#include <phosphor-logging/log.hpp>
#include <sdbusplus/asio/connection.hpp>
-#include <sdbusplus/timer.hpp>
#include <tuple>
using namespace phosphor::logging;
@@ -38,14 +36,6 @@
sd_bus* bus = nullptr;
sd_event* events = nullptr;
-// Global timer for network changes
-std::unique_ptr<phosphor::Timer> networkTimer = nullptr;
-
-FILE* ipmidbus = nullptr;
-static unsigned short selReservationID = 0xFFFF;
-static bool selReservationValid = false;
-sd_bus_slot* ipmid_slot = nullptr;
-
std::shared_ptr<sdbusplus::bus::bus> sdbusp;
/*
@@ -64,45 +54,6 @@
return sdbusp;
}
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-sd_event* ipmid_get_sd_event_connection()
-{
- return events;
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-unsigned short reserveSel(void)
-{
- // IPMI spec, Reservation ID, the value simply increases against each
- // execution of the Reserve SEL command.
- if (++selReservationID == 0)
- {
- selReservationID = 1;
- }
- selReservationValid = true;
- return selReservationID;
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-bool checkSELReservation(unsigned short id)
-{
- return (selReservationValid && selReservationID == id);
-}
-
-/*
- * @brief Required by apphandler IPMI Provider Library
- */
-void cancelSELReservation(void)
-{
- selReservationValid = false;
-}
-
EInterfaceIndex getInterfaceIndex(void)
{
return interfaceLAN1;
@@ -110,11 +61,6 @@
int main()
{
- /*
- * Required by apphandler IPMI Provider Library for logging.
- */
- ipmidbus = fopen("/dev/null", "w");
-
// Connect to system bus
auto rc = sd_bus_default_system(&bus);
if (rc < 0)
@@ -138,9 +84,6 @@
command::registerGUIDChangeCallback();
cache::guid = command::getSystemGUID();
- // Register all the IPMI provider libraries applicable for net-ipmid
- provider::registerCallbackHandlers(NET_IPMID_LIB_PATH);
-
// Register the phosphor-net-ipmid session setup commands
command::sessionSetupCommands();
diff --git a/provider_registration.cpp b/provider_registration.cpp
deleted file mode 100644
index 616dc90..0000000
--- a/provider_registration.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "provider_registration.hpp"
-
-#include "command_table.hpp"
-#include "main.hpp"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <ipmid/api.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <phosphor-logging/log.hpp>
-
-using namespace phosphor::logging;
-
-namespace provider
-{
-
-int handler_select(const struct dirent* entry)
-{
- // Check for versioned libraries .so.*
- if (strstr(entry->d_name, PROVIDER_SONAME_EXTN))
- {
- return 1;
- }
- else
- {
- return 0;
- }
-}
-
-void registerCallbackHandlers(const char* providerLibPath)
-{
- if (providerLibPath == NULL)
- {
- log<level::ERR>(
- "Path not provided for registering IPMI provider libraries");
- return;
- }
-
- struct dirent** handlerList = nullptr;
- std::string handlerPath(providerLibPath);
-
- auto numLibs =
- scandir(providerLibPath, &handlerList, handler_select, alphasort);
- if (numLibs < 0)
- {
- return;
- }
-
- // dlopen each IPMI provider shared library
- while (numLibs--)
- {
- handlerPath = providerLibPath;
- handlerPath += handlerList[numLibs]->d_name;
-
- auto lib_handler = dlopen(handlerPath.c_str(), RTLD_NOW);
-
- if (lib_handler == NULL)
- {
- log<level::ERR>("Error opening provider library",
- entry("PATH=%s", handlerPath.c_str()),
- entry("ERROR=%s", dlerror()));
- }
- free(handlerList[numLibs]);
- }
-
- free(handlerList);
-}
-
-} // namespace provider
-
-/*
- * @brief Method that gets called from IPMI provider shared libraries to get
- * the command handlers registered.
- *
- * When the IPMI provider shared library is loaded, the dynamic loader program
- * looks for special section(.ctors on ELF) which contains references to the
- * functions marked with the constructor attributes. This function is invoked
- * in such manner.
- *
- * @param[in] netfn - Network Function code
- * @param[in] cmd - Command
- * @param[in] context - User specific data
- * @param[in] handler - The callback routine for the command
- * @param[in] priv - IPMI Command Privilege
- */
-void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_context_t context, ipmid_callback_t handler,
- ipmi_cmd_privilege_t priv)
-{
- uint16_t netFn = netfn << 10;
-
- // The payload type of IPMI commands provided by the shared libraries
- // is IPMI
- command::CommandID command = {
- ((static_cast<uint32_t>(message::PayloadType::IPMI)) << 16) | netFn |
- cmd};
-
- std::get<command::Table&>(singletonPool)
- .registerCommand(command, std::make_unique<command::ProviderIpmidEntry>(
- command, handler,
- static_cast<session::Privilege>(priv)));
-}
diff --git a/provider_registration.hpp b/provider_registration.hpp
deleted file mode 100644
index ad956fc..0000000
--- a/provider_registration.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-namespace provider
-{
-
-/**
- * @brief Provider Library filename extension
- *
- * Autotools versions the shared libraries, so the shared libraries end with
- * extension name .so.*
- */
-
-constexpr auto PROVIDER_SONAME_EXTN = ".so.";
-
-/**
- * @brief Register Callback handlers for IPMI provider libraries
- *
- * Open the directory path for net-ipmid provider libraries and scan the
- * directory for files that end with .so.*. and dlopen the shared libraries
- * to register the handlers for the callback routines.
- *
- * @param[in] providerLibPath - Directory path for reading the IPMI provider
- * libraries
- */
-void registerCallbackHandlers(const char* providerLibPath);
-
-} // namespace provider