Redfish: PATCH command for Hypervisor DHCP network
This commit adds support to set the DHCP configuration
on the Hypervisor's Ethernet Interface
Tested By:
Configure the DHCPEnabled parameter and check the value is set.
1. curl -k -H "X-Auth-Token: $bmc_token" -X PATCH
-d '{"DHCPv4": {"DHCPEnabled": true}}'
https://${bmc}/redfish/v1/Systems/hypervisor/EthernetInterfaces/eth0
2. curl -k -H "X-Auth-Token: $bmc_token" -X GET
https://${bmc}/redfish/v1/Systems/hypervisor/EthernetInterfaces/eth0
Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com>
Change-Id: Ie1ac5659ef6af0f29cd91bda96574424a86fd095
diff --git a/redfish-core/lib/hypervisor_ethernet.hpp b/redfish-core/lib/hypervisor_ethernet.hpp
index 002f2ee..bcd5afe 100644
--- a/redfish-core/lib/hypervisor_ethernet.hpp
+++ b/redfish-core/lib/hypervisor_ethernet.hpp
@@ -144,7 +144,7 @@
};
inline bool extractHypervisorInterfaceData(
- const std::string& ethifaceId, const GetManagedObjects& dbusData,
+ const std::string& ethIfaceId, const GetManagedObjects& dbusData,
EthernetInterfaceData& ethData,
boost::container::flat_set<IPv4AddressData>& ipv4Config)
{
@@ -154,7 +154,7 @@
for (const auto& ifacePair : objpath.second)
{
if (objpath.first ==
- "/xyz/openbmc_project/network/hypervisor/" + ethifaceId)
+ "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId)
{
idFound = true;
if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
@@ -193,7 +193,7 @@
}
}
if (objpath.first == "/xyz/openbmc_project/network/hypervisor/" +
- ethifaceId + "/ipv4/addr0")
+ ethIfaceId + "/ipv4/addr0")
{
std::pair<boost::container::flat_set<IPv4AddressData>::iterator,
bool>
@@ -293,18 +293,18 @@
return idFound;
}
/**
- * Function that retrieves all properties for given VMI Ethernet Interface
- * Object from Settings Manager
- * @param ethifaceId a eth interface id to query on DBus
+ * Function that retrieves all properties for given Hypervisor Ethernet
+ * Interface Object from Settings Manager
+ * @param ethIfaceId Hypervisor ethernet interface id to query on DBus
* @param callback a function that shall be called to convert Dbus output
* into JSON
*/
template <typename CallbackFunc>
-void getHypervisorIfaceData(const std::string& ethifaceId,
+void getHypervisorIfaceData(const std::string& ethIfaceId,
CallbackFunc&& callback)
{
crow::connections::systemBus->async_method_call(
- [ethifaceId{std::string{ethifaceId}},
+ [ethIfaceId{std::string{ethIfaceId}},
callback{std::move(callback)}](const boost::system::error_code error,
const GetManagedObjects& resp) {
EthernetInterfaceData ethData{};
@@ -315,7 +315,7 @@
return;
}
- bool found = extractHypervisorInterfaceData(ethifaceId, resp,
+ bool found = extractHypervisorInterfaceData(ethIfaceId, resp,
ethData, ipv4Data);
if (!found)
{
@@ -331,32 +331,28 @@
* @brief Sets the Hypervisor Interface IPAddress DBUS
*
* @param[in] aResp Shared pointer for generating response message.
- * @param[in] ipv4Address Address from the incoming request
- * @param[in] ethifaceId Hypervisor Interface Id
+ * @param[in] ipv4Address Address from the incoming request
+ * @param[in] ethIfaceId Hypervisor Interface Id
*
* @return None.
*/
inline void setHypervisorIPv4Address(std::shared_ptr<AsyncResp> aResp,
- const std::string& ethifaceId,
+ const std::string& ethIfaceId,
const std::string& ipv4Address)
{
BMCWEB_LOG_DEBUG << "Setting the Hypervisor IPaddress : " << ipv4Address
- << " on Iface: " << ethifaceId;
- std::string path =
- "/xyz/openbmc_project/network/hypervisor/" + ethifaceId + "/ipv4/addr0";
- const char* hypervisorObj = path.c_str();
-
+ << " on Iface: " << ethIfaceId;
crow::connections::systemBus->async_method_call(
[aResp](const boost::system::error_code ec) {
if (ec)
{
BMCWEB_LOG_ERROR << "DBUS response error " << ec;
- // not an error, don't have to have the interface
return;
}
BMCWEB_LOG_DEBUG << "Hypervisor IPaddress is Set";
},
- "xyz.openbmc_project.Settings", hypervisorObj,
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0",
"org.freedesktop.DBus.Properties", "Set",
"xyz.openbmc_project.Network.IP", "Address",
std::variant<std::string>(ipv4Address));
@@ -367,33 +363,31 @@
*
* @param[in] aResp Shared pointer for generating response message.
* @param[in] subnet SubnetMask from the incoming request
- * @param[in] ethifaceId Hypervisor Interface Id
+ * @param[in] ethIfaceId Hypervisor Interface Id
*
* @return None.
*/
inline void setHypervisorIPv4Subnet(std::shared_ptr<AsyncResp> aResp,
- const std::string& ethifaceId,
+ const std::string& ethIfaceId,
const uint8_t subnet)
{
BMCWEB_LOG_DEBUG << "Setting the Hypervisor subnet : " << subnet
- << " on Iface: " << ethifaceId;
- std::string path =
- "/xyz/openbmc_project/network/hypervisor/" + ethifaceId + "/ipv4/addr0";
- const char* hypervisorObj = path.c_str();
+ << " on Iface: " << ethIfaceId;
crow::connections::systemBus->async_method_call(
[aResp](const boost::system::error_code ec) {
if (ec)
{
BMCWEB_LOG_ERROR << "DBUS response error " << ec;
- // not an error, don't have to have the interface
return;
}
BMCWEB_LOG_DEBUG << "SubnetMask is Set";
},
- "xyz.openbmc_project.Settings", hypervisorObj,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.IP", "PrefixLength",
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId +
+ "/ipv4/addr0"
+ "org.freedesktop.DBus.Properties",
+ "Set", "xyz.openbmc_project.Network.IP", "PrefixLength",
std::variant<uint8_t>(subnet));
}
@@ -402,12 +396,12 @@
*
* @param[in] aResp Shared pointer for generating response message.
* @param[in] gateway Gateway from the incoming request
- * @param[in] ethifaceId Hypervisor Interface Id
+ * @param[in] ethIfaceId Hypervisor Interface Id
*
* @return None.
*/
inline void setHypervisorIPv4Gateway(std::shared_ptr<AsyncResp> aResp,
- const std::string& ethifaceId,
+ const std::string& ethIfaceId,
const std::string& gateway)
{
BMCWEB_LOG_DEBUG
@@ -418,7 +412,6 @@
if (ec)
{
BMCWEB_LOG_ERROR << "DBUS response error " << ec;
- // not an error, don't have to have the interface
return;
}
BMCWEB_LOG_DEBUG << "Default Gateway is Set";
@@ -626,6 +619,8 @@
<< "," << *address;
createHypervisorIPv4(ifaceId, prefixLength, *gateway, *address,
asyncResp);
+ // Set the DHCPEnabled to false since the Static IPv4 is set
+ setDHCPEnabled(ifaceId, false, asyncResp);
}
else
{
@@ -676,6 +671,79 @@
std::variant<std::string>(hostName));
}
+ void setIPv4InterfaceEnabled(const std::string& ifaceId,
+ const bool& isActive,
+ const std::shared_ptr<AsyncResp> asyncResp)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ },
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/network/hypervisor/" + ifaceId +
+ "/ipv4/addr0",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Object.Enable", "Enabled",
+ std::variant<bool>(isActive));
+ }
+
+ void setDHCPEnabled(const std::string& ifaceId, const bool& ipv4DHCPEnabled,
+ const std::shared_ptr<AsyncResp> asyncResp)
+ {
+ const std::string dhcp =
+ GetDHCPEnabledEnumeration(ipv4DHCPEnabled, false);
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ },
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/network/hypervisor/" + ifaceId,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.EthernetInterface", "DHCPEnabled",
+ std::variant<std::string>{dhcp});
+
+ // Set the IPv4 address origin to the DHCP / Static as per the new value
+ // of the DHCPEnabled property
+ std::string origin;
+ if (ipv4DHCPEnabled == false)
+ {
+ origin = "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
+ }
+ else
+ {
+ // DHCPEnabled is set to true. Delete the current IPv4 settings
+ // to receive the new values from DHCP server.
+ deleteHypervisorIPv4(ifaceId, asyncResp);
+ origin = "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
+ }
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Hypervisor IPaddress Origin is Set";
+ },
+ "xyz.openbmc_project.Settings",
+ "/xyz/openbmc_project/network/hypervisor/" + ifaceId +
+ "/ipv4/addr0",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.IP", "Origin",
+ std::variant<std::string>(origin));
+ }
+
/**
* Functions triggers appropriate requests on DBus
*/
@@ -725,10 +793,13 @@
std::optional<std::string> hostName;
std::optional<nlohmann::json> ipv4StaticAddresses;
std::optional<nlohmann::json> ipv4Addresses;
+ std::optional<nlohmann::json> dhcpv4;
+ std::optional<bool> ipv4DHCPEnabled;
if (!json_util::readJson(req, res, "HostName", hostName,
"IPv4StaticAddresses", ipv4StaticAddresses,
- "IPv4Addresses", ipv4Addresses))
+ "IPv4Addresses", ipv4Addresses, "DHCPv4",
+ dhcpv4))
{
return;
}
@@ -738,10 +809,21 @@
messages::propertyNotWritable(asyncResp->res, "IPv4Addresses");
}
+ if (dhcpv4)
+ {
+ if (!json_util::readJson(*dhcpv4, res, "DHCPEnabled",
+ ipv4DHCPEnabled))
+ {
+ return;
+ }
+ }
+
getHypervisorIfaceData(
ifaceId,
[this, asyncResp, ifaceId, hostName = std::move(hostName),
- ipv4StaticAddresses = std::move(ipv4StaticAddresses)](
+ ipv4StaticAddresses = std::move(ipv4StaticAddresses),
+ ipv4DHCPEnabled = std::move(ipv4DHCPEnabled),
+ dhcpv4 = std::move(dhcpv4)](
const bool& success, const EthernetInterfaceData& ethData,
const boost::container::flat_set<IPv4AddressData>& ipv4Data) {
if (!success)
@@ -750,22 +832,44 @@
"EthernetInterface", ifaceId);
return;
}
+
if (ipv4StaticAddresses)
{
nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
- handleHypervisorIPv4StaticPatch(
- ifaceId, std::move(ipv4Static), asyncResp);
+ nlohmann::json& ipv4Json = ipv4Static[0];
+ // Check if the param is 'null'. If its null, it means that
+ // user wants to delete the IP address. Deleting the IP
+ // address is allowed only if its statically configured.
+ // Deleting the address originated from DHCP is not allowed.
+ if ((ipv4Json.is_null()) &&
+ (translateDHCPEnabledToBool(ethData.DHCPEnabled, true)))
+ {
+ BMCWEB_LOG_INFO
+ << "Ignoring the delete on ipv4StaticAddresses "
+ "as the interface is DHCP enabled";
+ }
+ else
+ {
+ handleHypervisorIPv4StaticPatch(
+ ifaceId, std::move(ipv4Static), asyncResp);
+ }
}
if (hostName)
{
handleHostnamePatch(*hostName, asyncResp);
}
- });
- // TODO : Task will be created for monitoring the Hypervisor interface
- // Hypervisor will notify once the IP is applied to the Hypervisor.
- // The status will be sent over to the client.
+ if (dhcpv4)
+ {
+ setDHCPEnabled(ifaceId, *ipv4DHCPEnabled, asyncResp);
+ }
+
+ // Set this interface to disabled/inactive. This will be set to
+ // enabled/active by the pldm once the hypervisor consumes the
+ // updated settings from the user.
+ setIPv4InterfaceEnabled(ifaceId, false, asyncResp);
+ });
res.result(boost::beast::http::status::accepted);
}
};