multiple channel configuration support
Previously, the ipmi daemon only supported eth0 and hard-coded it
to channel 1. This allows one to map via a configuration. The
channel number provided is checked against a configuration to retrieve
the ethernet device identifier, e.g. eth0.
Tested: Ran on a quanta-q71l and was able to properly set MAC, IP,
Netmask, Gateway IP, and then verified the data was set for the eth1
via `ip addr show eth1`.
Change-Id: I92f63188297304e9454fd0d6fe32bc6cf84bb181
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/app/channel.cpp b/app/channel.cpp
index 91d9987..64cc6e9 100644
--- a/app/channel.cpp
+++ b/app/channel.cpp
@@ -2,6 +2,7 @@
#include "types.hpp"
#include "transporthandler.hpp"
#include "utils.hpp"
+#include "net.hpp"
#include <string>
#include <arpa/inet.h>
@@ -10,13 +11,22 @@
#include <phosphor-logging/elog-errors.hpp>
#include "xyz/openbmc_project/Common/error.hpp"
-extern struct ChannelConfig_t channelConfig;
-
constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+/** @struct SetChannelAccessRequest
+ *
+ * IPMI payload for Set Channel access command request.
+ */
+struct SetChannelAccessRequest
+{
+ uint8_t channelNumber; //!< Channel number.
+ uint8_t setting; //!< The setting values.
+ uint8_t privilegeLevelLimit; //!< The Privilege Level Limit
+} __attribute__((packed));
+
/** @struct GetChannelAccessRequest
*
* IPMI payload for Get Channel access command request.
@@ -54,6 +64,22 @@
ipmi::DbusObjectInfo ipObject;
ipmi::DbusObjectInfo systemObject;
+ if (*data_len < sizeof(SetChannelAccessRequest))
+ {
+ return IPMI_CC_INVALID;
+ }
+
+ auto requestData = reinterpret_cast<const SetChannelAccessRequest*>
+ (request);
+ int channel = requestData->channelNumber & CHANNEL_MASK;
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+ if (ethdevice.empty())
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE;
+ auto channelConf = getChannelConfig(channel);
+
// Todo: parse the request data if needed.
// Using Set Channel cmd to apply changes of Set Lan Cmd.
try
@@ -61,23 +87,23 @@
sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
log<level::INFO>("Network data from Cache",
- entry("PREFIX=%s", channelConfig.netmask.c_str()),
- entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
- entry("GATEWAY=%s", channelConfig.gateway.c_str()),
- entry("VLAN=%d", channelConfig.vlanID),
- entry("IPSRC=%d", channelConfig.ipsrc));
+ entry("PREFIX=%s", channelConf->netmask.c_str()),
+ entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
+ entry("GATEWAY=%s", channelConf->gateway.c_str()),
+ entry("VLAN=%d", channelConf->vlanID),
+ entry("IPSRC=%d", channelConf->ipsrc));
- if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
+ if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
{
//get the first twelve bits which is vlan id
//not interested in rest of the bits.
- channelConfig.vlanID = le32toh(channelConfig.vlanID);
- vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
+ channelConf->vlanID = le32toh(channelConf->vlanID);
+ vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
}
// if the asked ip src is DHCP then not interested in
// any given data except vlan.
- if (channelConfig.ipsrc != ipmi::network::IPOrigin::DHCP)
+ if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP)
{
// always get the system object
systemObject = ipmi::getDbusObject(
@@ -97,11 +123,10 @@
// if the system is having ip object,then
// get the IP object.
- ipObject = ipmi::getIPObject(
- bus,
- ipmi::network::IP_INTERFACE,
- ipmi::network::ROOT,
- ipmi::network::IP_TYPE);
+ ipObject = ipmi::getDbusObject(bus,
+ ipmi::network::IP_INTERFACE,
+ ipmi::network::ROOT,
+ ethIp);
// Get the parent interface of the IP object.
try
@@ -120,7 +145,7 @@
ipmi::network::ETHERNET_INTERFACE));
commit<InternalFailure>();
rc = IPMI_CC_UNSPECIFIED_ERROR;
- channelConfig.clear();
+ channelConf->clear();
return rc;
}
@@ -138,7 +163,7 @@
bus,
ipmi::network::ETHERNET_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::INTERFACE);
+ ethdevice);
networkInterfacePath = std::move(networkInterfaceObject.first);
}
@@ -154,21 +179,21 @@
// check whether user has given all the data
// or the configured system interface is dhcp enabled,
// in both of the cases get the values from the cache.
- if ((!channelConfig.ipaddr.empty() &&
- !channelConfig.netmask.empty() &&
- !channelConfig.gateway.empty()) ||
+ if ((!channelConf->ipaddr.empty() &&
+ !channelConf->netmask.empty() &&
+ !channelConf->gateway.empty()) ||
(enableDHCP)) // configured system interface mode = DHCP
{
//convert mask into prefix
- ipaddress = channelConfig.ipaddr;
- prefix = ipmi::network::toPrefix(AF_INET, channelConfig.netmask);
- gateway = channelConfig.gateway;
- if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
+ ipaddress = channelConf->ipaddr;
+ prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask);
+ gateway = channelConf->gateway;
+ if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK)
{
//get the first twelve bits which is vlan id
//not interested in rest of the bits.
- channelConfig.vlanID = le32toh(channelConfig.vlanID);
- vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
+ channelConf->vlanID = le32toh(channelConf->vlanID);
+ vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK;
}
else
{
@@ -196,21 +221,20 @@
ipObject.first,
ipmi::network::IP_INTERFACE);
- ipaddress = channelConfig.ipaddr.empty() ?
+ ipaddress = channelConf->ipaddr.empty() ?
properties["Address"].get<std::string>() :
- channelConfig.ipaddr;
+ channelConf->ipaddr;
- prefix = channelConfig.netmask.empty() ?
+ prefix = channelConf->netmask.empty() ?
properties["PrefixLength"].get<uint8_t>() :
ipmi::network::toPrefix(AF_INET,
- channelConfig.netmask);
-
+ channelConf->netmask);
}
catch (InternalFailure& e)
{
log<level::INFO>("Failed to get IP object which matches",
entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
- entry("MATCH=%s", ipmi::network::IP_TYPE));
+ entry("MATCH=%s", ethIp));
}
auto systemProperties = ipmi::getAllDbusProperties(
@@ -219,10 +243,9 @@
systemObject.first,
ipmi::network::SYSTEMCONFIG_INTERFACE);
- gateway = channelConfig.gateway.empty() ?
+ gateway = channelConf->gateway.empty() ?
systemProperties["DefaultGateway"].get<std::string>() :
- channelConfig.gateway;
-
+ channelConf->gateway;
}
}
@@ -248,7 +271,7 @@
bus,
ipmi::network::ETHERNET_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::INTERFACE);
+ ethdevice);
// setting the physical interface mode to static.
ipmi::setDbusProperty(bus,
@@ -264,14 +287,14 @@
ipmi::deleteAllDbusObjects(bus,
ipmi::network::ROOT,
ipmi::network::IP_INTERFACE,
- ipmi::network::IP_TYPE);
+ ethIp);
if (vlanID)
{
ipmi::network::createVLAN(bus,
ipmi::network::SERVICE,
ipmi::network::ROOT,
- ipmi::network::INTERFACE,
+ ethdevice,
vlanID);
auto networkInterfaceObject = ipmi::getDbusObject(
@@ -282,7 +305,7 @@
networkInterfacePath = networkInterfaceObject.first;
}
- if (channelConfig.ipsrc == ipmi::network::IPOrigin::DHCP)
+ if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP)
{
ipmi::setDbusProperty(bus,
ipmi::network::SERVICE,
@@ -330,13 +353,13 @@
entry("ADDRESS=%s", ipaddress.c_str()),
entry("GATEWAY=%s", gateway.c_str()),
entry("VLANID=%d", vlanID),
- entry("IPSRC=%d", channelConfig.ipsrc));
+ entry("IPSRC=%d", channelConf->ipsrc));
commit<InternalFailure>();
rc = IPMI_CC_UNSPECIFIED_ERROR;
}
- channelConfig.clear();
+ channelConf->clear();
return rc;
}
@@ -350,17 +373,15 @@
auto responseData = reinterpret_cast<GetChannelAccessResponse*>
(outPayload.data());
- // Channel 1 is arbitrarily assigned to ETH0 channel
- constexpr auto channelOne = 0x01;
-
/*
* The value Eh is used as a way to identify the current channel that
* the command is being received from.
*/
constexpr auto channelE = 0x0E;
+ int channel = requestData->channelNumber;
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
- if (requestData->channelNumber != channelOne &&
- requestData->channelNumber != channelE)
+ if (channel != channelE && ethdevice.empty())
{
*data_len = 0;
return IPMI_CC_INVALID_FIELD_REQUEST;
@@ -406,20 +427,20 @@
IPMI_CHANNEL_TYPE_IPMB,
1,0x41,0xA7,0x00,0,0};
uint8_t *p = (uint8_t*) request;
+ int channel = (*p) & CHANNEL_MASK;
+ std::string ethdevice = ipmi::network::ChanneltoEthernet(channel);
printf("IPMI APP GET CHANNEL INFO\n");
- // The supported channels numbers are 1 and 8.
+ // The supported channels numbers are those which are configured.
// Channel Number E is used as way to identify the current channel
// that the command is being is received from.
- if (*p == 0xe || *p == 1 || *p == 8) {
-
- *data_len = sizeof(resp);
- memcpy(response, resp, *data_len);
-
- } else {
+ if (channel != 0xe && ethdevice.empty()) {
rc = IPMI_CC_PARM_OUT_OF_RANGE;
*data_len = 0;
+ } else {
+ *data_len = sizeof(resp);
+ memcpy(response, resp, *data_len);
}
return rc;