Redfish Interface Implementation for Hypervisor-IPv4 Static IP
This commit implements the GET command for Power hypervisor
Virtual Management Interface's IPv4 static network.
Tested by:
1. GET https://${bmc}/redfish/v1/Systems/hypervisor/EthernetInterfaces/intf0
2. GET https://${bmc}/redfish/v1/Systems/hypervisor/EthernetInterfaces/intf1
3. Successfully ran the Redfish Validator
*** /redfish/v1/Systems/hypervisor/EthernetInterfaces/intf0
Type (#EthernetInterface.v1_5_1.EthernetInterface), GET SUCCESS (time: 0.400974)
PASS
*** /redfish/v1/Systems/hypervisor/EthernetInterfaces/intf1
Type (#EthernetInterface.v1_5_1.EthernetInterface), GET SUCCESS (time: 0.366143)
PASS
Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com>
Change-Id: Ie0f6996a01f9772e91dcf6d5045a20f3a257f67c
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index f8524ac..6f2e753 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -183,6 +183,7 @@
nodes.emplace_back(
std::make_unique<HypervisorInterfaceCollection>(app));
+ nodes.emplace_back(std::make_unique<HypervisorInterface>(app));
nodes.emplace_back(std::make_unique<HypervisorSystem>(app));
for (const auto& node : nodes)
diff --git a/redfish-core/lib/hypervisor_ethernet.hpp b/redfish-core/lib/hypervisor_ethernet.hpp
index ab6c0a5..70fb423 100644
--- a/redfish-core/lib/hypervisor_ethernet.hpp
+++ b/redfish-core/lib/hypervisor_ethernet.hpp
@@ -98,9 +98,9 @@
"xyz.openbmc_project.Network.EthernetInterface"};
crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code error_code,
- const std::vector<std::string> &iface_list) {
- if (error_code)
+ [asyncResp](const boost::system::error_code error,
+ const std::vector<std::string> &ifaceList) {
+ if (error)
{
messages::resourceNotFound(asyncResp->res, "System",
"hypervisor");
@@ -118,23 +118,22 @@
"Collection of Virtual Management "
"Interfaces for the hypervisor";
- nlohmann::json &iface_array =
+ nlohmann::json &ifaceArray =
asyncResp->res.jsonValue["Members"];
- iface_array = nlohmann::json::array();
- for (const std::string &iface_item : iface_list)
+ ifaceArray = nlohmann::json::array();
+ for (const std::string &iface : ifaceList)
{
- std::size_t last_pos = iface_item.rfind("/");
+ std::size_t last_pos = iface.rfind("/");
if (last_pos != std::string::npos)
{
- iface_array.push_back(
- {{"@odata.id",
- "/redfish/v1/Systems/hypervisor/"
- "EthernetInterfaces/" +
- iface_item.substr(last_pos + 1)}});
+ ifaceArray.push_back(
+ {{"@odata.id", "/redfish/v1/Systems/hypervisor/"
+ "EthernetInterfaces/" +
+ iface.substr(last_pos + 1)}});
}
}
asyncResp->res.jsonValue["Members@odata.count"] =
- iface_array.size();
+ ifaceArray.size();
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
@@ -143,4 +142,249 @@
}
};
+inline bool extractHypervisorInterfaceData(
+ const std::string ðifaceId, const GetManagedObjects &dbusData,
+ EthernetInterfaceData ðData,
+ boost::container::flat_set<IPv4AddressData> &ipv4Config)
+{
+ bool idFound = false;
+ for (const auto &objpath : dbusData)
+ {
+ for (const auto &ifacePair : objpath.second)
+ {
+ if (objpath.first ==
+ "/xyz/openbmc_project/network/vmi/" + ethifaceId)
+ {
+ idFound = true;
+ if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
+ {
+ for (const auto &propertyPair : ifacePair.second)
+ {
+ if (propertyPair.first == "MACAddress")
+ {
+ const std::string *mac =
+ std::get_if<std::string>(&propertyPair.second);
+ if (mac != nullptr)
+ {
+ ethData.mac_address = *mac;
+ }
+ }
+ }
+ }
+ }
+ if (objpath.first == "/xyz/openbmc_project/network/vmi/" +
+ ethifaceId + "/ipv4/addr0")
+ {
+ if (ifacePair.first == "xyz.openbmc_project.Network.IP")
+ {
+ std::pair<
+ boost::container::flat_set<IPv4AddressData>::iterator,
+ bool>
+ it = ipv4Config.insert(IPv4AddressData{});
+ IPv4AddressData &ipv4Address = *it.first;
+ for (auto &property : ifacePair.second)
+ {
+ if (property.first == "Address")
+ {
+ const std::string *address =
+ std::get_if<std::string>(&property.second);
+ if (address != nullptr)
+ {
+ ipv4Address.address = *address;
+ }
+ }
+ else if (property.first == "Origin")
+ {
+ const std::string *origin =
+ std::get_if<std::string>(&property.second);
+ if (origin != nullptr)
+ {
+ ipv4Address.origin =
+ translateAddressOriginDbusToRedfish(*origin,
+ true);
+ }
+ }
+ else if (property.first == "PrefixLength")
+ {
+ const uint8_t *mask =
+ std::get_if<uint8_t>(&property.second);
+ if (mask != nullptr)
+ {
+ // convert it to the string
+ ipv4Address.netmask = getNetmask(*mask);
+ }
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "Got extra property: " << property.first
+ << " on the " << objpath.first.str << " object";
+ }
+ }
+ }
+ }
+ if (objpath.first == "/xyz/openbmc_project/network/vmi")
+ {
+ // System configuration shows up in the global namespace, so no
+ // need to check eth number
+ if (ifacePair.first ==
+ "xyz.openbmc_project.Network.SystemConfiguration")
+ {
+ for (const auto &propertyPair : ifacePair.second)
+ {
+ if (propertyPair.first == "HostName")
+ {
+ const std::string *hostname =
+ sdbusplus::message::variant_ns::get_if<
+ std::string>(&propertyPair.second);
+ if (hostname != nullptr)
+ {
+ ethData.hostname = *hostname;
+ }
+ }
+ else if (propertyPair.first == "DefaultGateway")
+ {
+ const std::string *defaultGateway =
+ sdbusplus::message::variant_ns::get_if<
+ std::string>(&propertyPair.second);
+ if (defaultGateway != nullptr)
+ {
+ ethData.default_gateway = *defaultGateway;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ 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
+ * @param callback a function that shall be called to convert Dbus output
+ * into JSON
+ */
+template <typename CallbackFunc>
+void getHypervisorIfaceData(const std::string ðifaceId,
+ CallbackFunc &&callback)
+{
+ crow::connections::systemBus->async_method_call(
+ [ethifaceId{std::string{ethifaceId}},
+ callback{std::move(callback)}](const boost::system::error_code error,
+ const GetManagedObjects &resp) {
+ EthernetInterfaceData ethData{};
+ boost::container::flat_set<IPv4AddressData> ipv4Data;
+ if (error)
+ {
+ callback(false, ethData, ipv4Data);
+ return;
+ }
+
+ bool found = extractHypervisorInterfaceData(ethifaceId, resp,
+ ethData, ipv4Data);
+ if (!found)
+ {
+ BMCWEB_LOG_DEBUG << "Not found";
+ }
+ callback(found, ethData, ipv4Data);
+ },
+ "xyz.openbmc_project.Settings", "/",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+}
+
+/**
+ * HypervisorInterface derived class for delivering Ethernet Schema
+ */
+class HypervisorInterface : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ template <typename CrowApp>
+ HypervisorInterface(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/<str>/",
+ std::string())
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+ void parseInterfaceData(
+ nlohmann::json &jsonResponse, const std::string &ifaceId,
+ const EthernetInterfaceData ðData,
+ const boost::container::flat_set<IPv4AddressData> &ipv4Data)
+ {
+ jsonResponse["Id"] = ifaceId;
+ jsonResponse["@odata.id"] =
+ "/redfish/v1/Systems/hypervisor/EthernetInterfaces/" + ifaceId;
+ jsonResponse["InterfaceEnabled"] = true;
+ jsonResponse["MACAddress"] = ethData.mac_address;
+
+ if (!ethData.hostname.empty())
+ {
+ jsonResponse["HostName"] = ethData.hostname;
+ }
+
+ nlohmann::json &ipv4Array = jsonResponse["IPv4Addresses"];
+ nlohmann::json &ipv4StaticArray = jsonResponse["IPv4StaticAddresses"];
+ ipv4Array = nlohmann::json::array();
+ ipv4StaticArray = nlohmann::json::array();
+ for (auto &ipv4Config : ipv4Data)
+ {
+ ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin},
+ {"SubnetMask", ipv4Config.netmask},
+ {"Address", ipv4Config.address},
+ {"Gateway", ethData.default_gateway}});
+ if (ipv4Config.origin == "Static")
+ {
+ ipv4StaticArray.push_back(
+ {{"AddressOrigin", ipv4Config.origin},
+ {"SubnetMask", ipv4Config.netmask},
+ {"Address", ipv4Config.address},
+ {"Gateway", ethData.default_gateway}});
+ }
+ }
+ }
+
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> ¶ms) override
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ if (params.size() != 1)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ getHypervisorIfaceData(
+ params[0],
+ [this, asyncResp, ifaceId{std::string(params[0])}](
+ const bool &success, const EthernetInterfaceData ðData,
+ const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
+ if (!success)
+ {
+ messages::resourceNotFound(
+ asyncResp->res, "HostEthernetInterface", ifaceId);
+ return;
+ }
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#EthernetInterface.v1_5_1.EthernetInterface";
+ asyncResp->res.jsonValue["Name"] =
+ "Virtual Management Ethernet Interface";
+ asyncResp->res.jsonValue["Description"] =
+ "Virtual Interface Management Network Interface";
+ parseInterfaceData(asyncResp->res.jsonValue, ifaceId, ethData,
+ ipv4Data);
+ });
+ }
+};
} // namespace redfish