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/transporthandler.cpp b/transporthandler.cpp
index 50bc473..f4326c1 100644
--- a/transporthandler.cpp
+++ b/transporthandler.cpp
@@ -9,6 +9,7 @@
#include "ipmid.hpp"
#include "transporthandler.hpp"
#include "utils.hpp"
+#include "net.hpp"
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog-errors.hpp>
@@ -23,7 +24,7 @@
const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
-struct ChannelConfig_t channelConfig;
+std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
@@ -31,13 +32,34 @@
void register_netfn_transport_functions() __attribute__((constructor));
+struct ChannelConfig_t* getChannelConfig(int channel)
+{
+ auto item = channelConfig.find(channel);
+ if (item == channelConfig.end())
+ {
+ channelConfig[channel] = std::make_unique<struct ChannelConfig_t>();
+ }
+
+ return channelConfig[channel].get();
+}
+
// Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network Manager or
// Cache based on Set-In-Progress State
-ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data)
+ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel)
{
ipmi_ret_t rc = IPMI_CC_OK;
sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+ // if ethdevice is an empty string they weren't expecting this channel.
+ if (ethdevice.empty())
+ {
+ // TODO: return error from getNetworkData()
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE;
+ auto channelConf = getChannelConfig(channel);
+
try
{
switch (lan_param)
@@ -45,7 +67,7 @@
case LAN_PARM_IP:
{
std::string ipaddress;
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
try
{
@@ -53,7 +75,7 @@
bus,
ipmi::network::IP_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::IP_TYPE);
+ ethIP);
auto properties = ipmi::getAllDbusProperties(
bus,
@@ -62,7 +84,6 @@
ipmi::network::IP_INTERFACE);
ipaddress = properties["Address"].get<std::string>();
-
}
// ignore the exception, as it is a valid condtion that
// system is not confiured with any ip.
@@ -71,9 +92,9 @@
// nothing to do.
}
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- ipaddress = channelConfig.ipaddr;
+ ipaddress = channelConf->ipaddr;
}
inet_pton(AF_INET, ipaddress.c_str(),
@@ -85,7 +106,7 @@
{
std::string networkInterfacePath;
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
try
{
@@ -96,7 +117,7 @@
bus,
ipmi::network::IP_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::IP_TYPE);
+ ethIP);
// Get the parent interface of the IP object.
try
@@ -133,7 +154,7 @@
bus,
ipmi::network::ETHERNET_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::INTERFACE);
+ ethdevice);
networkInterfacePath = networkInterfaceObject.first;
}
@@ -152,9 +173,9 @@
memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE);
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- memcpy(data, &(channelConfig.ipsrc),
+ memcpy(data, &(channelConf->ipsrc),
ipmi::network::IPSRC_SIZE_BYTE);
}
}
@@ -163,7 +184,7 @@
case LAN_PARM_SUBNET:
{
unsigned long mask {};
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
try
{
@@ -191,9 +212,9 @@
}
memcpy(data, &mask, ipmi::network::IPV4_ADDRESS_SIZE_BYTE);
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- inet_pton(AF_INET, channelConfig.netmask.c_str(),
+ inet_pton(AF_INET, channelConf->netmask.c_str(),
reinterpret_cast<void*>(data));
}
@@ -204,7 +225,7 @@
{
std::string gateway;
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
try
{
@@ -230,9 +251,9 @@
}
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- gateway = channelConfig.gateway;
+ gateway = channelConf->gateway;
}
inet_pton(AF_INET, gateway.c_str(),
@@ -243,12 +264,13 @@
case LAN_PARM_MAC:
{
std::string macAddress;
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
auto macObjectInfo = ipmi::getDbusObject(
bus,
ipmi::network::MAC_INTERFACE,
- ipmi::network::ROOT);
+ ipmi::network::ROOT,
+ ethdevice);
auto variant = ipmi::getDbusProperty(
bus,
@@ -260,9 +282,9 @@
macAddress = variant.get<std::string>();
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- macAddress = channelConfig.macAddress;
+ macAddress = channelConf->macAddress;
}
sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
@@ -278,7 +300,7 @@
case LAN_PARM_VLAN:
{
uint16_t vlanID {};
- if (channelConfig.lan_set_in_progress == SET_COMPLETE)
+ if (channelConf->lan_set_in_progress == SET_COMPLETE)
{
try
{
@@ -308,9 +330,9 @@
memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE);
}
- else if (channelConfig.lan_set_in_progress == SET_IN_PROGRESS)
+ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
{
- memcpy(data, &(channelConfig.vlanID),
+ memcpy(data, &(channelConf->vlanID),
ipmi::network::VLAN_SIZE_BYTE);
}
}
@@ -364,6 +386,15 @@
auto reqptr = reinterpret_cast<const set_lan_t*>(request);
sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
+ // channel number is the lower nibble
+ int channel = reqptr->channel & CHANNEL_MASK;
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+ if (ethdevice.empty())
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ auto channelConf = getChannelConfig(channel);
+
switch (reqptr->parameter)
{
case LAN_PARM_IP:
@@ -372,8 +403,7 @@
reqptr->data[0], reqptr->data[1],
reqptr->data[2], reqptr->data[3]);
- channelConfig.ipaddr.assign(ipaddr);
-
+ channelConf->ipaddr.assign(ipaddr);
}
break;
@@ -381,7 +411,7 @@
{
uint8_t ipsrc{};
memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
- channelConfig.ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
+ channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
}
break;
@@ -401,7 +431,7 @@
bus,
ipmi::network::MAC_INTERFACE,
ipmi::network::ROOT,
- ipmi::network::INTERFACE);
+ ethdevice);
ipmi::setDbusProperty(bus,
macObjectInfo.second,
@@ -410,8 +440,7 @@
"MACAddress",
std::string(mac));
- channelConfig.macAddress = mac;
-
+ channelConf->macAddress = mac;
}
break;
@@ -420,7 +449,7 @@
snprintf(netmask, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
reqptr->data[0], reqptr->data[1],
reqptr->data[2], reqptr->data[3]);
- channelConfig.netmask.assign(netmask);
+ channelConf->netmask.assign(netmask);
}
break;
@@ -429,8 +458,7 @@
snprintf(gateway, INET_ADDRSTRLEN, ipmi::network::IP_ADDRESS_FORMAT,
reqptr->data[0], reqptr->data[1],
reqptr->data[2], reqptr->data[3]);
- channelConfig.gateway.assign(gateway);
-
+ channelConf->gateway.assign(gateway);
}
break;
@@ -442,7 +470,7 @@
// We assume that ipmitool always send enable
// bit as 1.
vlan = le16toh(vlan);
- channelConfig.vlanID = vlan;
+ channelConf->vlanID = vlan;
}
break;
@@ -450,22 +478,20 @@
{
if (reqptr->data[0] == SET_COMPLETE)
{
- channelConfig.lan_set_in_progress = SET_COMPLETE;
+ channelConf->lan_set_in_progress = SET_COMPLETE;
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("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));
log<level::INFO>("Use Set Channel Access command to apply");
-
}
else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
{
- channelConfig.lan_set_in_progress = SET_IN_PROGRESS;
+ channelConf->lan_set_in_progress = SET_IN_PROGRESS;
}
-
}
break;
@@ -473,7 +499,6 @@
{
rc = IPMI_CC_PARM_NOT_SUPPORTED;
}
-
}
return rc;
@@ -499,6 +524,8 @@
const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
get_lan_t *reqptr = (get_lan_t*) request;
+ // channel number is the lower nibble
+ int channel = reqptr->rev_channel & CHANNEL_MASK;
if (reqptr->rev_channel & 0x80) // Revision is bit 7
{
@@ -508,9 +535,16 @@
return IPMI_CC_OK;
}
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+ if (ethdevice.empty())
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ auto channelConf = getChannelConfig(channel);
+
if (reqptr->parameter == LAN_PARM_INPROGRESS)
{
- uint8_t buf[] = {current_revision, channelConfig.lan_set_in_progress};
+ uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress};
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
}
@@ -536,7 +570,7 @@
*data_len = sizeof(current_revision);
memcpy(buf, ¤t_revision, *data_len);
- if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
+ if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
{
if (reqptr->parameter == LAN_PARM_MAC)
{
@@ -559,7 +593,7 @@
*data_len = sizeof(current_revision);
memcpy(buf, ¤t_revision, *data_len);
- if (getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
+ if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK)
{
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
@@ -570,7 +604,7 @@
uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {};
*data_len = sizeof(current_revision);
memcpy(buff, ¤t_revision, *data_len);
- if (getNetworkData(reqptr->parameter, &buff[1]) == IPMI_CC_OK)
+ if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK)
{
*data_len = sizeof(buff);
memcpy(response, &buff, *data_len);