1d5afb2caSAndrew Geissler #pragma once 2d5afb2caSAndrew Geissler 3d5afb2caSAndrew Geissler #include <boost/container/flat_map.hpp> 4d5afb2caSAndrew Geissler #include <boost/container/flat_set.hpp> 5d5afb2caSAndrew Geissler #include <dbus_singleton.hpp> 6d5afb2caSAndrew Geissler #include <error_messages.hpp> 7d5afb2caSAndrew Geissler #include <node.hpp> 8d5afb2caSAndrew Geissler #include <utils/json_utils.hpp> 9d5afb2caSAndrew Geissler 10d5afb2caSAndrew Geissler #include <optional> 11d5afb2caSAndrew Geissler #include <utility> 12d5afb2caSAndrew Geissler #include <variant> 13d5afb2caSAndrew Geissler 14d5afb2caSAndrew Geissler namespace redfish 15d5afb2caSAndrew Geissler { 16d5afb2caSAndrew Geissler 17d5afb2caSAndrew Geissler /** 18cc0bb6f2SAndrew Geissler * @brief Retrieves hypervisor state properties over dbus 19cc0bb6f2SAndrew Geissler * 20cc0bb6f2SAndrew Geissler * The hypervisor state object is optional so this function will only set the 21cc0bb6f2SAndrew Geissler * state variables if the object is found 22cc0bb6f2SAndrew Geissler * 23cc0bb6f2SAndrew Geissler * @param[in] aResp Shared pointer for completing asynchronous calls. 24cc0bb6f2SAndrew Geissler * 25cc0bb6f2SAndrew Geissler * @return None. 26cc0bb6f2SAndrew Geissler */ 27*8d1b46d7Szhanghch05 inline void getHypervisorState(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 28cc0bb6f2SAndrew Geissler { 29cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Get hypervisor state information."; 30cc0bb6f2SAndrew Geissler crow::connections::systemBus->async_method_call( 31cc0bb6f2SAndrew Geissler [aResp](const boost::system::error_code ec, 32cc0bb6f2SAndrew Geissler const std::variant<std::string>& hostState) { 33cc0bb6f2SAndrew Geissler if (ec) 34cc0bb6f2SAndrew Geissler { 35cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 36cc0bb6f2SAndrew Geissler // This is an optional D-Bus object so just return if 37cc0bb6f2SAndrew Geissler // error occurs 38cc0bb6f2SAndrew Geissler return; 39cc0bb6f2SAndrew Geissler } 40cc0bb6f2SAndrew Geissler 41cc0bb6f2SAndrew Geissler const std::string* s = std::get_if<std::string>(&hostState); 42cc0bb6f2SAndrew Geissler if (s == nullptr) 43cc0bb6f2SAndrew Geissler { 44cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 45cc0bb6f2SAndrew Geissler return; 46cc0bb6f2SAndrew Geissler } 47cc0bb6f2SAndrew Geissler 48cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor state: " << *s; 49cc0bb6f2SAndrew Geissler // Verify Host State 50cc0bb6f2SAndrew Geissler if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 51cc0bb6f2SAndrew Geissler { 52cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 53cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 54cc0bb6f2SAndrew Geissler } 55cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 56cc0bb6f2SAndrew Geissler "Quiesced") 57cc0bb6f2SAndrew Geissler { 58cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 59cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 60cc0bb6f2SAndrew Geissler } 61cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 62cc0bb6f2SAndrew Geissler "Standby") 63cc0bb6f2SAndrew Geissler { 64cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 65cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 66cc0bb6f2SAndrew Geissler } 67cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 68cc0bb6f2SAndrew Geissler "TransitioningToRunning") 69cc0bb6f2SAndrew Geissler { 70cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOn"; 71cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Starting"; 72cc0bb6f2SAndrew Geissler } 73cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 74cc0bb6f2SAndrew Geissler "TransitioningToOff") 75cc0bb6f2SAndrew Geissler { 76cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOff"; 77cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 78cc0bb6f2SAndrew Geissler } 79cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState.Off") 80cc0bb6f2SAndrew Geissler { 81cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "Off"; 82cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Disabled"; 83cc0bb6f2SAndrew Geissler } 84cc0bb6f2SAndrew Geissler else 85cc0bb6f2SAndrew Geissler { 86cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 87cc0bb6f2SAndrew Geissler return; 88cc0bb6f2SAndrew Geissler } 89cc0bb6f2SAndrew Geissler }, 90cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Hypervisor", 91cc0bb6f2SAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 92cc0bb6f2SAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 93cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Host", "CurrentHostState"); 94cc0bb6f2SAndrew Geissler } 95cc0bb6f2SAndrew Geissler 96cc0bb6f2SAndrew Geissler /** 974fbaf64aSAndrew Geissler * @brief Populate Actions if any are valid for hypervisor object 984fbaf64aSAndrew Geissler * 994fbaf64aSAndrew Geissler * The hypervisor state object is optional so this function will only set the 1004fbaf64aSAndrew Geissler * Action if the object is found 1014fbaf64aSAndrew Geissler * 1024fbaf64aSAndrew Geissler * @param[in] aResp Shared pointer for completing asynchronous calls. 1034fbaf64aSAndrew Geissler * 1044fbaf64aSAndrew Geissler * @return None. 1054fbaf64aSAndrew Geissler */ 106*8d1b46d7Szhanghch05 inline void 107*8d1b46d7Szhanghch05 getHypervisorActions(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1084fbaf64aSAndrew Geissler { 1094fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "Get hypervisor actions."; 1104fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 1114fbaf64aSAndrew Geissler [aResp]( 1124fbaf64aSAndrew Geissler const boost::system::error_code ec, 1134fbaf64aSAndrew Geissler const std::vector<std::pair<std::string, std::vector<std::string>>>& 1144fbaf64aSAndrew Geissler objInfo) { 1154fbaf64aSAndrew Geissler if (ec) 1164fbaf64aSAndrew Geissler { 1174fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1184fbaf64aSAndrew Geissler // This is an optional D-Bus object so just return if 1194fbaf64aSAndrew Geissler // error occurs 1204fbaf64aSAndrew Geissler return; 1214fbaf64aSAndrew Geissler } 1224fbaf64aSAndrew Geissler 1234fbaf64aSAndrew Geissler if (objInfo.size() == 0) 1244fbaf64aSAndrew Geissler { 1254fbaf64aSAndrew Geissler // As noted above, this is an optional interface so just return 1264fbaf64aSAndrew Geissler // if there is no instance found 1274fbaf64aSAndrew Geissler return; 1284fbaf64aSAndrew Geissler } 1294fbaf64aSAndrew Geissler 1304fbaf64aSAndrew Geissler if (objInfo.size() > 1) 1314fbaf64aSAndrew Geissler { 1324fbaf64aSAndrew Geissler // More then one hypervisor object is not supported and is an 1334fbaf64aSAndrew Geissler // error 1344fbaf64aSAndrew Geissler messages::internalError(aResp->res); 1354fbaf64aSAndrew Geissler return; 1364fbaf64aSAndrew Geissler } 1374fbaf64aSAndrew Geissler 1384fbaf64aSAndrew Geissler // Object present so system support limited ComputerSystem Action 1394fbaf64aSAndrew Geissler aResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1404fbaf64aSAndrew Geissler {"target", 1414fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/Actions/ComputerSystem.Reset"}, 1424fbaf64aSAndrew Geissler {"@Redfish.ActionInfo", 1434fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/ResetActionInfo"}}; 1444fbaf64aSAndrew Geissler }, 1454fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 1464fbaf64aSAndrew Geissler "/xyz/openbmc_project/object_mapper", 1474fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", 1484fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 1494fbaf64aSAndrew Geissler std::array<const char*, 1>{"xyz.openbmc_project.State.Host"}); 1504fbaf64aSAndrew Geissler } 1514fbaf64aSAndrew Geissler 1524fbaf64aSAndrew Geissler /** 153d5afb2caSAndrew Geissler * Hypervisor Systems derived class for delivering Computer Systems Schema. 154d5afb2caSAndrew Geissler */ 155d5afb2caSAndrew Geissler class HypervisorSystem : public Node 156d5afb2caSAndrew Geissler { 157d5afb2caSAndrew Geissler public: 158d5afb2caSAndrew Geissler /* 159d5afb2caSAndrew Geissler * Default Constructor 160d5afb2caSAndrew Geissler */ 161d5afb2caSAndrew Geissler HypervisorSystem(App& app) : Node(app, "/redfish/v1/Systems/hypervisor/") 162d5afb2caSAndrew Geissler { 163d5afb2caSAndrew Geissler entityPrivileges = { 164d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 165d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 166d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 167d5afb2caSAndrew Geissler } 168d5afb2caSAndrew Geissler 169d5afb2caSAndrew Geissler private: 170d5afb2caSAndrew Geissler /** 171d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 172d5afb2caSAndrew Geissler */ 173*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 175d5afb2caSAndrew Geissler { 176d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 177d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec, 178d5afb2caSAndrew Geissler const std::variant<std::string>& /*hostName*/) { 179d5afb2caSAndrew Geissler if (ec) 180d5afb2caSAndrew Geissler { 181d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 182d5afb2caSAndrew Geissler "hypervisor"); 183d5afb2caSAndrew Geissler return; 184d5afb2caSAndrew Geissler } 185d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor is available"; 186d5afb2caSAndrew Geissler 187d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 188d5afb2caSAndrew Geissler "#ComputerSystem.v1_6_0.ComputerSystem"; 189d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 190d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor"; 191d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = "Hypervisor"; 192d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor"; 193d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Id"] = "hypervisor"; 194d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 195d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 196d5afb2caSAndrew Geissler asyncResp->res.jsonValue["EthernetInterfaces"] = { 197d5afb2caSAndrew Geissler {"@odata.id", "/redfish/v1/Systems/hypervisor/" 198d5afb2caSAndrew Geissler "EthernetInterfaces"}}; 199cc0bb6f2SAndrew Geissler getHypervisorState(asyncResp); 2004fbaf64aSAndrew Geissler getHypervisorActions(asyncResp); 201d5afb2caSAndrew Geissler // TODO: Add "SystemType" : "hypervisor" 202d5afb2caSAndrew Geissler }, 203d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 204d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 205d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 206d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 207d5afb2caSAndrew Geissler } 208d5afb2caSAndrew Geissler }; 209d5afb2caSAndrew Geissler 210d5afb2caSAndrew Geissler /** 211d5afb2caSAndrew Geissler * HypervisorInterfaceCollection class to handle the GET and PATCH on Hypervisor 212d5afb2caSAndrew Geissler * Interface 213d5afb2caSAndrew Geissler */ 214d5afb2caSAndrew Geissler class HypervisorInterfaceCollection : public Node 215d5afb2caSAndrew Geissler { 216d5afb2caSAndrew Geissler public: 217d5afb2caSAndrew Geissler HypervisorInterfaceCollection(App& app) : 218d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/") 219d5afb2caSAndrew Geissler { 220d5afb2caSAndrew Geissler entityPrivileges = { 221d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 222d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 223d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 224d5afb2caSAndrew Geissler } 225d5afb2caSAndrew Geissler 226d5afb2caSAndrew Geissler private: 227d5afb2caSAndrew Geissler /** 228d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 229d5afb2caSAndrew Geissler */ 230*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 231*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 232d5afb2caSAndrew Geissler { 233d5afb2caSAndrew Geissler const std::array<const char*, 1> interfaces = { 234d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface"}; 235d5afb2caSAndrew Geissler 236d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 237d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code error, 238d5afb2caSAndrew Geissler const std::vector<std::string>& ifaceList) { 239d5afb2caSAndrew Geissler if (error) 240d5afb2caSAndrew Geissler { 241d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 242d5afb2caSAndrew Geissler "hypervisor"); 243d5afb2caSAndrew Geissler return; 244d5afb2caSAndrew Geissler } 245d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 246d5afb2caSAndrew Geissler "#EthernetInterfaceCollection." 247d5afb2caSAndrew Geissler "EthernetInterfaceCollection"; 248d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 249d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces"; 250d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor Ethernet " 251d5afb2caSAndrew Geissler "Interface Collection"; 252d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 253d5afb2caSAndrew Geissler "Collection of Virtual Management " 254d5afb2caSAndrew Geissler "Interfaces for the hypervisor"; 255d5afb2caSAndrew Geissler 256d5afb2caSAndrew Geissler nlohmann::json& ifaceArray = 257d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members"]; 258d5afb2caSAndrew Geissler ifaceArray = nlohmann::json::array(); 259d5afb2caSAndrew Geissler for (const std::string& iface : ifaceList) 260d5afb2caSAndrew Geissler { 2612dfd18efSEd Tanous sdbusplus::message::object_path path(iface); 2622dfd18efSEd Tanous std::string name = path.filename(); 2632dfd18efSEd Tanous if (name.empty()) 264d5afb2caSAndrew Geissler { 2652dfd18efSEd Tanous continue; 2662dfd18efSEd Tanous } 2672dfd18efSEd Tanous 268d5afb2caSAndrew Geissler ifaceArray.push_back( 269d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Systems/hypervisor/" 270d5afb2caSAndrew Geissler "EthernetInterfaces/" + 2712dfd18efSEd Tanous name}}); 272d5afb2caSAndrew Geissler } 273d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 274d5afb2caSAndrew Geissler ifaceArray.size(); 275d5afb2caSAndrew Geissler }, 276d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 277d5afb2caSAndrew Geissler "/xyz/openbmc_project/object_mapper", 278d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 279d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 0, interfaces); 280d5afb2caSAndrew Geissler } 281d5afb2caSAndrew Geissler }; 282d5afb2caSAndrew Geissler 283d5afb2caSAndrew Geissler inline bool extractHypervisorInterfaceData( 284d5afb2caSAndrew Geissler const std::string& ethIfaceId, const GetManagedObjects& dbusData, 285d5afb2caSAndrew Geissler EthernetInterfaceData& ethData, 286d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData>& ipv4Config) 287d5afb2caSAndrew Geissler { 288d5afb2caSAndrew Geissler bool idFound = false; 289d5afb2caSAndrew Geissler for (const auto& objpath : dbusData) 290d5afb2caSAndrew Geissler { 291d5afb2caSAndrew Geissler for (const auto& ifacePair : objpath.second) 292d5afb2caSAndrew Geissler { 293d5afb2caSAndrew Geissler if (objpath.first == 294d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId) 295d5afb2caSAndrew Geissler { 296d5afb2caSAndrew Geissler idFound = true; 297d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 298d5afb2caSAndrew Geissler { 299d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 300d5afb2caSAndrew Geissler { 301d5afb2caSAndrew Geissler if (propertyPair.first == "MACAddress") 302d5afb2caSAndrew Geissler { 303d5afb2caSAndrew Geissler const std::string* mac = 304d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 305d5afb2caSAndrew Geissler if (mac != nullptr) 306d5afb2caSAndrew Geissler { 307d5afb2caSAndrew Geissler ethData.mac_address = *mac; 308d5afb2caSAndrew Geissler } 309d5afb2caSAndrew Geissler } 310d5afb2caSAndrew Geissler } 311d5afb2caSAndrew Geissler } 312d5afb2caSAndrew Geissler else if (ifacePair.first == 313d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface") 314d5afb2caSAndrew Geissler { 315d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 316d5afb2caSAndrew Geissler { 317d5afb2caSAndrew Geissler if (propertyPair.first == "DHCPEnabled") 318d5afb2caSAndrew Geissler { 319d5afb2caSAndrew Geissler const std::string* dhcp = 320d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 321d5afb2caSAndrew Geissler if (dhcp != nullptr) 322d5afb2caSAndrew Geissler { 323d5afb2caSAndrew Geissler ethData.DHCPEnabled = *dhcp; 324d5afb2caSAndrew Geissler break; // Interested on only "DHCPEnabled". 325d5afb2caSAndrew Geissler // Stop parsing since we got the 326d5afb2caSAndrew Geissler // "DHCPEnabled" value. 327d5afb2caSAndrew Geissler } 328d5afb2caSAndrew Geissler } 329d5afb2caSAndrew Geissler } 330d5afb2caSAndrew Geissler } 331d5afb2caSAndrew Geissler } 332d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor/" + 333d5afb2caSAndrew Geissler ethIfaceId + "/ipv4/addr0") 334d5afb2caSAndrew Geissler { 335d5afb2caSAndrew Geissler std::pair<boost::container::flat_set<IPv4AddressData>::iterator, 336d5afb2caSAndrew Geissler bool> 337d5afb2caSAndrew Geissler it = ipv4Config.insert(IPv4AddressData{}); 338d5afb2caSAndrew Geissler IPv4AddressData& ipv4Address = *it.first; 339d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Object.Enable") 340d5afb2caSAndrew Geissler { 341d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 342d5afb2caSAndrew Geissler { 343d5afb2caSAndrew Geissler if (property.first == "Enabled") 344d5afb2caSAndrew Geissler { 345d5afb2caSAndrew Geissler const bool* intfEnable = 346d5afb2caSAndrew Geissler std::get_if<bool>(&property.second); 347d5afb2caSAndrew Geissler if (intfEnable != nullptr) 348d5afb2caSAndrew Geissler { 349d5afb2caSAndrew Geissler ipv4Address.isActive = *intfEnable; 350d5afb2caSAndrew Geissler break; 351d5afb2caSAndrew Geissler } 352d5afb2caSAndrew Geissler } 353d5afb2caSAndrew Geissler } 354d5afb2caSAndrew Geissler } 355d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.IP") 356d5afb2caSAndrew Geissler { 357d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 358d5afb2caSAndrew Geissler { 359d5afb2caSAndrew Geissler if (property.first == "Address") 360d5afb2caSAndrew Geissler { 361d5afb2caSAndrew Geissler const std::string* address = 362d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 363d5afb2caSAndrew Geissler if (address != nullptr) 364d5afb2caSAndrew Geissler { 365d5afb2caSAndrew Geissler ipv4Address.address = *address; 366d5afb2caSAndrew Geissler } 367d5afb2caSAndrew Geissler } 368d5afb2caSAndrew Geissler else if (property.first == "Origin") 369d5afb2caSAndrew Geissler { 370d5afb2caSAndrew Geissler const std::string* origin = 371d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 372d5afb2caSAndrew Geissler if (origin != nullptr) 373d5afb2caSAndrew Geissler { 374d5afb2caSAndrew Geissler ipv4Address.origin = 375d5afb2caSAndrew Geissler translateAddressOriginDbusToRedfish(*origin, 376d5afb2caSAndrew Geissler true); 377d5afb2caSAndrew Geissler } 378d5afb2caSAndrew Geissler } 379d5afb2caSAndrew Geissler else if (property.first == "PrefixLength") 380d5afb2caSAndrew Geissler { 381d5afb2caSAndrew Geissler const uint8_t* mask = 382d5afb2caSAndrew Geissler std::get_if<uint8_t>(&property.second); 383d5afb2caSAndrew Geissler if (mask != nullptr) 384d5afb2caSAndrew Geissler { 385d5afb2caSAndrew Geissler // convert it to the string 386d5afb2caSAndrew Geissler ipv4Address.netmask = getNetmask(*mask); 387d5afb2caSAndrew Geissler } 388d5afb2caSAndrew Geissler } 389d5afb2caSAndrew Geissler else 390d5afb2caSAndrew Geissler { 391d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR 392d5afb2caSAndrew Geissler << "Got extra property: " << property.first 393d5afb2caSAndrew Geissler << " on the " << objpath.first.str << " object"; 394d5afb2caSAndrew Geissler } 395d5afb2caSAndrew Geissler } 396d5afb2caSAndrew Geissler } 397d5afb2caSAndrew Geissler } 398d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor") 399d5afb2caSAndrew Geissler { 400d5afb2caSAndrew Geissler // System configuration shows up in the global namespace, so no 401d5afb2caSAndrew Geissler // need to check eth number 402d5afb2caSAndrew Geissler if (ifacePair.first == 403d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration") 404d5afb2caSAndrew Geissler { 405d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 406d5afb2caSAndrew Geissler { 407d5afb2caSAndrew Geissler if (propertyPair.first == "HostName") 408d5afb2caSAndrew Geissler { 409d5afb2caSAndrew Geissler const std::string* hostName = 410d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 411d5afb2caSAndrew Geissler if (hostName != nullptr) 412d5afb2caSAndrew Geissler { 413d5afb2caSAndrew Geissler ethData.hostname = *hostName; 414d5afb2caSAndrew Geissler } 415d5afb2caSAndrew Geissler } 416d5afb2caSAndrew Geissler else if (propertyPair.first == "DefaultGateway") 417d5afb2caSAndrew Geissler { 418d5afb2caSAndrew Geissler const std::string* defaultGateway = 419d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 420d5afb2caSAndrew Geissler if (defaultGateway != nullptr) 421d5afb2caSAndrew Geissler { 422d5afb2caSAndrew Geissler ethData.default_gateway = *defaultGateway; 423d5afb2caSAndrew Geissler } 424d5afb2caSAndrew Geissler } 425d5afb2caSAndrew Geissler } 426d5afb2caSAndrew Geissler } 427d5afb2caSAndrew Geissler } 428d5afb2caSAndrew Geissler } 429d5afb2caSAndrew Geissler } 430d5afb2caSAndrew Geissler return idFound; 431d5afb2caSAndrew Geissler } 432d5afb2caSAndrew Geissler /** 433d5afb2caSAndrew Geissler * Function that retrieves all properties for given Hypervisor Ethernet 434d5afb2caSAndrew Geissler * Interface Object from Settings Manager 435d5afb2caSAndrew Geissler * @param ethIfaceId Hypervisor ethernet interface id to query on DBus 436d5afb2caSAndrew Geissler * @param callback a function that shall be called to convert Dbus output 437d5afb2caSAndrew Geissler * into JSON 438d5afb2caSAndrew Geissler */ 439d5afb2caSAndrew Geissler template <typename CallbackFunc> 440d5afb2caSAndrew Geissler void getHypervisorIfaceData(const std::string& ethIfaceId, 441d5afb2caSAndrew Geissler CallbackFunc&& callback) 442d5afb2caSAndrew Geissler { 443d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 444d5afb2caSAndrew Geissler [ethIfaceId{std::string{ethIfaceId}}, 445d5afb2caSAndrew Geissler callback{std::move(callback)}](const boost::system::error_code error, 446d5afb2caSAndrew Geissler const GetManagedObjects& resp) { 447d5afb2caSAndrew Geissler EthernetInterfaceData ethData{}; 448d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData> ipv4Data; 449d5afb2caSAndrew Geissler if (error) 450d5afb2caSAndrew Geissler { 451d5afb2caSAndrew Geissler callback(false, ethData, ipv4Data); 452d5afb2caSAndrew Geissler return; 453d5afb2caSAndrew Geissler } 454d5afb2caSAndrew Geissler 455d5afb2caSAndrew Geissler bool found = extractHypervisorInterfaceData(ethIfaceId, resp, 456d5afb2caSAndrew Geissler ethData, ipv4Data); 457d5afb2caSAndrew Geissler if (!found) 458d5afb2caSAndrew Geissler { 459d5afb2caSAndrew Geissler BMCWEB_LOG_INFO << "Hypervisor Interface not found"; 460d5afb2caSAndrew Geissler } 461d5afb2caSAndrew Geissler callback(found, ethData, ipv4Data); 462d5afb2caSAndrew Geissler }, 463d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", "/", 464d5afb2caSAndrew Geissler "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 465d5afb2caSAndrew Geissler } 466d5afb2caSAndrew Geissler 467d5afb2caSAndrew Geissler /** 468d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface IPAddress DBUS 469d5afb2caSAndrew Geissler * 470d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 471d5afb2caSAndrew Geissler * @param[in] ipv4Address Address from the incoming request 472d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 473d5afb2caSAndrew Geissler * 474d5afb2caSAndrew Geissler * @return None. 475d5afb2caSAndrew Geissler */ 476*8d1b46d7Szhanghch05 inline void 477*8d1b46d7Szhanghch05 setHypervisorIPv4Address(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 478d5afb2caSAndrew Geissler const std::string& ethIfaceId, 479d5afb2caSAndrew Geissler const std::string& ipv4Address) 480d5afb2caSAndrew Geissler { 481d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor IPaddress : " << ipv4Address 482d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 483d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 484d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 485d5afb2caSAndrew Geissler if (ec) 486d5afb2caSAndrew Geissler { 487d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 488d5afb2caSAndrew Geissler return; 489d5afb2caSAndrew Geissler } 490d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress is Set"; 491d5afb2caSAndrew Geissler }, 492d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 493d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 494d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 495d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Address", 496d5afb2caSAndrew Geissler std::variant<std::string>(ipv4Address)); 497d5afb2caSAndrew Geissler } 498d5afb2caSAndrew Geissler 499d5afb2caSAndrew Geissler /** 500d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface SubnetMask DBUS 501d5afb2caSAndrew Geissler * 502d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 503d5afb2caSAndrew Geissler * @param[in] subnet SubnetMask from the incoming request 504d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 505d5afb2caSAndrew Geissler * 506d5afb2caSAndrew Geissler * @return None. 507d5afb2caSAndrew Geissler */ 508*8d1b46d7Szhanghch05 inline void 509*8d1b46d7Szhanghch05 setHypervisorIPv4Subnet(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 510*8d1b46d7Szhanghch05 const std::string& ethIfaceId, const uint8_t subnet) 511d5afb2caSAndrew Geissler { 512d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor subnet : " << subnet 513d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 514d5afb2caSAndrew Geissler 515d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 516d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 517d5afb2caSAndrew Geissler if (ec) 518d5afb2caSAndrew Geissler { 519d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 520d5afb2caSAndrew Geissler return; 521d5afb2caSAndrew Geissler } 522d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "SubnetMask is Set"; 523d5afb2caSAndrew Geissler }, 524d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 525d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 526d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 527d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "PrefixLength", 528d5afb2caSAndrew Geissler std::variant<uint8_t>(subnet)); 529d5afb2caSAndrew Geissler } 530d5afb2caSAndrew Geissler 531d5afb2caSAndrew Geissler /** 532d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface Gateway DBUS 533d5afb2caSAndrew Geissler * 534d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 535d5afb2caSAndrew Geissler * @param[in] gateway Gateway from the incoming request 536d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 537d5afb2caSAndrew Geissler * 538d5afb2caSAndrew Geissler * @return None. 539d5afb2caSAndrew Geissler */ 540*8d1b46d7Szhanghch05 inline void 541*8d1b46d7Szhanghch05 setHypervisorIPv4Gateway(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 542d5afb2caSAndrew Geissler const std::string& gateway) 543d5afb2caSAndrew Geissler { 544d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG 545d5afb2caSAndrew Geissler << "Setting the DefaultGateway to the last configured gateway"; 546d5afb2caSAndrew Geissler 547d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 548d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 549d5afb2caSAndrew Geissler if (ec) 550d5afb2caSAndrew Geissler { 551d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 552d5afb2caSAndrew Geissler return; 553d5afb2caSAndrew Geissler } 554d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Default Gateway is Set"; 555d5afb2caSAndrew Geissler }, 556d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 557d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 558d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 559d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "DefaultGateway", 560d5afb2caSAndrew Geissler std::variant<std::string>(gateway)); 561d5afb2caSAndrew Geissler } 562d5afb2caSAndrew Geissler 563d5afb2caSAndrew Geissler /** 564d5afb2caSAndrew Geissler * @brief Creates a static IPv4 entry 565d5afb2caSAndrew Geissler * 566d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface upon which to create the IPv4 entry 567d5afb2caSAndrew Geissler * @param[in] prefixLength IPv4 prefix syntax for the subnet mask 568d5afb2caSAndrew Geissler * @param[in] gateway IPv4 address of this interfaces gateway 569d5afb2caSAndrew Geissler * @param[in] address IPv4 address to assign to this interface 570d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 571d5afb2caSAndrew Geissler * 572d5afb2caSAndrew Geissler * @return None 573d5afb2caSAndrew Geissler */ 574*8d1b46d7Szhanghch05 inline void 575*8d1b46d7Szhanghch05 createHypervisorIPv4(const std::string& ifaceId, uint8_t prefixLength, 576*8d1b46d7Szhanghch05 const std::string& gateway, const std::string& address, 577*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 578d5afb2caSAndrew Geissler { 579d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 580d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 581d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 582d5afb2caSAndrew Geissler } 583d5afb2caSAndrew Geissler 584d5afb2caSAndrew Geissler /** 585d5afb2caSAndrew Geissler * @brief Deletes given IPv4 interface 586d5afb2caSAndrew Geissler * 587d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface whose IP should be deleted 588d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 589d5afb2caSAndrew Geissler * 590d5afb2caSAndrew Geissler * @return None 591d5afb2caSAndrew Geissler */ 592*8d1b46d7Szhanghch05 inline void 593*8d1b46d7Szhanghch05 deleteHypervisorIPv4(const std::string& ifaceId, 594*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 595d5afb2caSAndrew Geissler { 596d5afb2caSAndrew Geissler std::string address = "0.0.0.0"; 597d5afb2caSAndrew Geissler std::string gateway = "0.0.0.0"; 598d5afb2caSAndrew Geissler const uint8_t prefixLength = 0; 599d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 600d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 601d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 602d5afb2caSAndrew Geissler } 603d5afb2caSAndrew Geissler 604d5afb2caSAndrew Geissler /** 605d5afb2caSAndrew Geissler * HypervisorInterface derived class for delivering Ethernet Schema 606d5afb2caSAndrew Geissler */ 607d5afb2caSAndrew Geissler class HypervisorInterface : public Node 608d5afb2caSAndrew Geissler { 609d5afb2caSAndrew Geissler public: 610d5afb2caSAndrew Geissler /* 611d5afb2caSAndrew Geissler * Default Constructor 612d5afb2caSAndrew Geissler */ 613d5afb2caSAndrew Geissler HypervisorInterface(App& app) : 614d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/<str>/", 615d5afb2caSAndrew Geissler std::string()) 616d5afb2caSAndrew Geissler { 617d5afb2caSAndrew Geissler entityPrivileges = { 618d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 619d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 620d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 621d5afb2caSAndrew Geissler } 622d5afb2caSAndrew Geissler 623d5afb2caSAndrew Geissler private: 624d5afb2caSAndrew Geissler void parseInterfaceData( 625d5afb2caSAndrew Geissler nlohmann::json& jsonResponse, const std::string& ifaceId, 626d5afb2caSAndrew Geissler const EthernetInterfaceData& ethData, 627d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) 628d5afb2caSAndrew Geissler { 629d5afb2caSAndrew Geissler jsonResponse["Id"] = ifaceId; 630d5afb2caSAndrew Geissler jsonResponse["@odata.id"] = 631d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces/" + ifaceId; 632d5afb2caSAndrew Geissler jsonResponse["InterfaceEnabled"] = true; 633d5afb2caSAndrew Geissler jsonResponse["MACAddress"] = ethData.mac_address; 634d5afb2caSAndrew Geissler 635d5afb2caSAndrew Geissler jsonResponse["HostName"] = ethData.hostname; 636d5afb2caSAndrew Geissler jsonResponse["DHCPv4"]["DHCPEnabled"] = 637d5afb2caSAndrew Geissler translateDHCPEnabledToBool(ethData.DHCPEnabled, true); 638d5afb2caSAndrew Geissler 639d5afb2caSAndrew Geissler nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"]; 640d5afb2caSAndrew Geissler nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"]; 641d5afb2caSAndrew Geissler ipv4Array = nlohmann::json::array(); 642d5afb2caSAndrew Geissler ipv4StaticArray = nlohmann::json::array(); 643d5afb2caSAndrew Geissler for (auto& ipv4Config : ipv4Data) 644d5afb2caSAndrew Geissler { 645d5afb2caSAndrew Geissler if (ipv4Config.isActive) 646d5afb2caSAndrew Geissler { 647d5afb2caSAndrew Geissler 648d5afb2caSAndrew Geissler ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin}, 649d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 650d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 651d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 652d5afb2caSAndrew Geissler if (ipv4Config.origin == "Static") 653d5afb2caSAndrew Geissler { 654d5afb2caSAndrew Geissler ipv4StaticArray.push_back( 655d5afb2caSAndrew Geissler {{"AddressOrigin", ipv4Config.origin}, 656d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 657d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 658d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 659d5afb2caSAndrew Geissler } 660d5afb2caSAndrew Geissler } 661d5afb2caSAndrew Geissler } 662d5afb2caSAndrew Geissler } 663d5afb2caSAndrew Geissler 664d5afb2caSAndrew Geissler void handleHypervisorIPv4StaticPatch( 665d5afb2caSAndrew Geissler const std::string& ifaceId, const nlohmann::json& input, 666*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 667d5afb2caSAndrew Geissler { 668d5afb2caSAndrew Geissler if ((!input.is_array()) || input.empty()) 669d5afb2caSAndrew Geissler { 670d5afb2caSAndrew Geissler messages::propertyValueTypeError(asyncResp->res, input.dump(), 671d5afb2caSAndrew Geissler "IPv4StaticAddresses"); 672d5afb2caSAndrew Geissler return; 673d5afb2caSAndrew Geissler } 674d5afb2caSAndrew Geissler 675d5afb2caSAndrew Geissler // Hypervisor considers the first IP address in the array list 676d5afb2caSAndrew Geissler // as the Hypervisor's virtual management interface supports single IPv4 677d5afb2caSAndrew Geissler // address 678d5afb2caSAndrew Geissler const nlohmann::json& thisJson = input[0]; 679d5afb2caSAndrew Geissler 680d5afb2caSAndrew Geissler // For the error string 681d5afb2caSAndrew Geissler std::string pathString = "IPv4StaticAddresses/1"; 682d5afb2caSAndrew Geissler 683d5afb2caSAndrew Geissler if (!thisJson.is_null() && !thisJson.empty()) 684d5afb2caSAndrew Geissler { 685d5afb2caSAndrew Geissler std::optional<std::string> address; 686d5afb2caSAndrew Geissler std::optional<std::string> subnetMask; 687d5afb2caSAndrew Geissler std::optional<std::string> gateway; 688d5afb2caSAndrew Geissler nlohmann::json thisJsonCopy = thisJson; 689d5afb2caSAndrew Geissler if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address", 690d5afb2caSAndrew Geissler address, "SubnetMask", subnetMask, 691d5afb2caSAndrew Geissler "Gateway", gateway)) 692d5afb2caSAndrew Geissler { 69371f52d96SEd Tanous messages::propertyValueFormatError( 69471f52d96SEd Tanous asyncResp->res, 69571f52d96SEd Tanous thisJson.dump(2, ' ', true, 69671f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 69771f52d96SEd Tanous pathString); 698d5afb2caSAndrew Geissler return; 699d5afb2caSAndrew Geissler } 700d5afb2caSAndrew Geissler 701d5afb2caSAndrew Geissler uint8_t prefixLength = 0; 702d5afb2caSAndrew Geissler bool errorInEntry = false; 703d5afb2caSAndrew Geissler if (address) 704d5afb2caSAndrew Geissler { 705d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*address)) 706d5afb2caSAndrew Geissler { 707d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *address, 708d5afb2caSAndrew Geissler pathString + "/Address"); 709d5afb2caSAndrew Geissler errorInEntry = true; 710d5afb2caSAndrew Geissler } 711d5afb2caSAndrew Geissler } 712d5afb2caSAndrew Geissler else 713d5afb2caSAndrew Geissler { 714d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 715d5afb2caSAndrew Geissler pathString + "/Address"); 716d5afb2caSAndrew Geissler errorInEntry = true; 717d5afb2caSAndrew Geissler } 718d5afb2caSAndrew Geissler 719d5afb2caSAndrew Geissler if (subnetMask) 720d5afb2caSAndrew Geissler { 721d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 722d5afb2caSAndrew Geissler { 723d5afb2caSAndrew Geissler messages::propertyValueFormatError( 724d5afb2caSAndrew Geissler asyncResp->res, *subnetMask, 725d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 726d5afb2caSAndrew Geissler errorInEntry = true; 727d5afb2caSAndrew Geissler } 728d5afb2caSAndrew Geissler } 729d5afb2caSAndrew Geissler else 730d5afb2caSAndrew Geissler { 731d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 732d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 733d5afb2caSAndrew Geissler errorInEntry = true; 734d5afb2caSAndrew Geissler } 735d5afb2caSAndrew Geissler 736d5afb2caSAndrew Geissler if (gateway) 737d5afb2caSAndrew Geissler { 738d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*gateway)) 739d5afb2caSAndrew Geissler { 740d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *gateway, 741d5afb2caSAndrew Geissler pathString + "/Gateway"); 742d5afb2caSAndrew Geissler errorInEntry = true; 743d5afb2caSAndrew Geissler } 744d5afb2caSAndrew Geissler } 745d5afb2caSAndrew Geissler else 746d5afb2caSAndrew Geissler { 747d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 748d5afb2caSAndrew Geissler pathString + "/Gateway"); 749d5afb2caSAndrew Geissler errorInEntry = true; 750d5afb2caSAndrew Geissler } 751d5afb2caSAndrew Geissler 752d5afb2caSAndrew Geissler if (errorInEntry) 753d5afb2caSAndrew Geissler { 754d5afb2caSAndrew Geissler return; 755d5afb2caSAndrew Geissler } 756d5afb2caSAndrew Geissler 757d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Calling createHypervisorIPv4 on : " << ifaceId 758d5afb2caSAndrew Geissler << "," << *address; 759d5afb2caSAndrew Geissler createHypervisorIPv4(ifaceId, prefixLength, *gateway, *address, 760d5afb2caSAndrew Geissler asyncResp); 761d5afb2caSAndrew Geissler // Set the DHCPEnabled to false since the Static IPv4 is set 762d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, false, asyncResp); 763d5afb2caSAndrew Geissler } 764d5afb2caSAndrew Geissler else 765d5afb2caSAndrew Geissler { 766d5afb2caSAndrew Geissler if (thisJson.is_null()) 767d5afb2caSAndrew Geissler { 768d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 769d5afb2caSAndrew Geissler } 770d5afb2caSAndrew Geissler } 771d5afb2caSAndrew Geissler } 772d5afb2caSAndrew Geissler 773d5afb2caSAndrew Geissler bool isHostnameValid(const std::string& hostName) 774d5afb2caSAndrew Geissler { 775d5afb2caSAndrew Geissler // As per RFC 1123 776d5afb2caSAndrew Geissler // Allow up to 255 characters 777d5afb2caSAndrew Geissler if (hostName.length() > 255) 778d5afb2caSAndrew Geissler { 779d5afb2caSAndrew Geissler return false; 780d5afb2caSAndrew Geissler } 781d5afb2caSAndrew Geissler // Validate the regex 782d5afb2caSAndrew Geissler const std::regex pattern( 783d5afb2caSAndrew Geissler "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); 784d5afb2caSAndrew Geissler 785d5afb2caSAndrew Geissler return std::regex_match(hostName, pattern); 786d5afb2caSAndrew Geissler } 787d5afb2caSAndrew Geissler 788*8d1b46d7Szhanghch05 void 789*8d1b46d7Szhanghch05 handleHostnamePatch(const std::string& hostName, 790*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 791d5afb2caSAndrew Geissler { 792d5afb2caSAndrew Geissler if (!isHostnameValid(hostName)) 793d5afb2caSAndrew Geissler { 794d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, hostName, 795d5afb2caSAndrew Geissler "HostName"); 796d5afb2caSAndrew Geissler return; 797d5afb2caSAndrew Geissler } 798d5afb2caSAndrew Geissler 799d5afb2caSAndrew Geissler asyncResp->res.jsonValue["HostName"] = hostName; 800d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 801d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 802d5afb2caSAndrew Geissler if (ec) 803d5afb2caSAndrew Geissler { 804d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 805d5afb2caSAndrew Geissler } 806d5afb2caSAndrew Geissler }, 807d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 808d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 809d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 810d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 811d5afb2caSAndrew Geissler std::variant<std::string>(hostName)); 812d5afb2caSAndrew Geissler } 813d5afb2caSAndrew Geissler 814*8d1b46d7Szhanghch05 void setIPv4InterfaceEnabled( 815*8d1b46d7Szhanghch05 const std::string& ifaceId, const bool& isActive, 816*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 817d5afb2caSAndrew Geissler { 818d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 819d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 820d5afb2caSAndrew Geissler if (ec) 821d5afb2caSAndrew Geissler { 822d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 823d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 824d5afb2caSAndrew Geissler return; 825d5afb2caSAndrew Geissler } 826d5afb2caSAndrew Geissler }, 827d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 828d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 829d5afb2caSAndrew Geissler "/ipv4/addr0", 830d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 831d5afb2caSAndrew Geissler "xyz.openbmc_project.Object.Enable", "Enabled", 832d5afb2caSAndrew Geissler std::variant<bool>(isActive)); 833d5afb2caSAndrew Geissler } 834d5afb2caSAndrew Geissler 835d5afb2caSAndrew Geissler void setDHCPEnabled(const std::string& ifaceId, const bool& ipv4DHCPEnabled, 836*8d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 837d5afb2caSAndrew Geissler { 838d5afb2caSAndrew Geissler const std::string dhcp = 839d5afb2caSAndrew Geissler getDhcpEnabledEnumeration(ipv4DHCPEnabled, false); 840d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 841d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 842d5afb2caSAndrew Geissler if (ec) 843d5afb2caSAndrew Geissler { 844d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 845d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 846d5afb2caSAndrew Geissler return; 847d5afb2caSAndrew Geissler } 848d5afb2caSAndrew Geissler }, 849d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 850d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId, 851d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 852d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface", "DHCPEnabled", 853d5afb2caSAndrew Geissler std::variant<std::string>{dhcp}); 854d5afb2caSAndrew Geissler 855d5afb2caSAndrew Geissler // Set the IPv4 address origin to the DHCP / Static as per the new value 856d5afb2caSAndrew Geissler // of the DHCPEnabled property 857d5afb2caSAndrew Geissler std::string origin; 858d5afb2caSAndrew Geissler if (ipv4DHCPEnabled == false) 859d5afb2caSAndrew Geissler { 860d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 861d5afb2caSAndrew Geissler } 862d5afb2caSAndrew Geissler else 863d5afb2caSAndrew Geissler { 864d5afb2caSAndrew Geissler // DHCPEnabled is set to true. Delete the current IPv4 settings 865d5afb2caSAndrew Geissler // to receive the new values from DHCP server. 866d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 867d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 868d5afb2caSAndrew Geissler } 869d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 870d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 871d5afb2caSAndrew Geissler if (ec) 872d5afb2caSAndrew Geissler { 873d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 874d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 875d5afb2caSAndrew Geissler return; 876d5afb2caSAndrew Geissler } 877d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress Origin is Set"; 878d5afb2caSAndrew Geissler }, 879d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 880d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 881d5afb2caSAndrew Geissler "/ipv4/addr0", 882d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 883d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Origin", 884d5afb2caSAndrew Geissler std::variant<std::string>(origin)); 885d5afb2caSAndrew Geissler } 886d5afb2caSAndrew Geissler 887d5afb2caSAndrew Geissler /** 888d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 889d5afb2caSAndrew Geissler */ 890*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 891*8d1b46d7Szhanghch05 const crow::Request&, 892d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 893d5afb2caSAndrew Geissler { 894d5afb2caSAndrew Geissler if (params.size() != 1) 895d5afb2caSAndrew Geissler { 896d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 897d5afb2caSAndrew Geissler return; 898d5afb2caSAndrew Geissler } 899d5afb2caSAndrew Geissler 900d5afb2caSAndrew Geissler getHypervisorIfaceData( 901d5afb2caSAndrew Geissler params[0], 902d5afb2caSAndrew Geissler [this, asyncResp, ifaceId{std::string(params[0])}]( 903d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 904d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) { 905d5afb2caSAndrew Geissler if (!success) 906d5afb2caSAndrew Geissler { 907d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 908d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 909d5afb2caSAndrew Geissler return; 910d5afb2caSAndrew Geissler } 911d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 912d5afb2caSAndrew Geissler "#EthernetInterface.v1_5_1.EthernetInterface"; 913d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = 914d5afb2caSAndrew Geissler "Hypervisor Ethernet Interface"; 915d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 916d5afb2caSAndrew Geissler "Hypervisor's Virtual Management Ethernet Interface"; 917d5afb2caSAndrew Geissler parseInterfaceData(asyncResp->res.jsonValue, ifaceId, ethData, 918d5afb2caSAndrew Geissler ipv4Data); 919d5afb2caSAndrew Geissler }); 920d5afb2caSAndrew Geissler } 921d5afb2caSAndrew Geissler 922*8d1b46d7Szhanghch05 void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 923*8d1b46d7Szhanghch05 const crow::Request& req, 924d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 925d5afb2caSAndrew Geissler { 926*8d1b46d7Szhanghch05 927d5afb2caSAndrew Geissler if (params.size() != 1) 928d5afb2caSAndrew Geissler { 929d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 930d5afb2caSAndrew Geissler return; 931d5afb2caSAndrew Geissler } 932d5afb2caSAndrew Geissler 933d5afb2caSAndrew Geissler const std::string& ifaceId = params[0]; 934d5afb2caSAndrew Geissler std::optional<std::string> hostName; 93564face74SRavi Teja std::optional<std::vector<nlohmann::json>> ipv4StaticAddresses; 936d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4Addresses; 937d5afb2caSAndrew Geissler std::optional<nlohmann::json> dhcpv4; 938d5afb2caSAndrew Geissler std::optional<bool> ipv4DHCPEnabled; 939d5afb2caSAndrew Geissler 940*8d1b46d7Szhanghch05 if (!json_util::readJson(req, asyncResp->res, "HostName", hostName, 941d5afb2caSAndrew Geissler "IPv4StaticAddresses", ipv4StaticAddresses, 942d5afb2caSAndrew Geissler "IPv4Addresses", ipv4Addresses, "DHCPv4", 943d5afb2caSAndrew Geissler dhcpv4)) 944d5afb2caSAndrew Geissler { 945d5afb2caSAndrew Geissler return; 946d5afb2caSAndrew Geissler } 947d5afb2caSAndrew Geissler 948d5afb2caSAndrew Geissler if (ipv4Addresses) 949d5afb2caSAndrew Geissler { 950d5afb2caSAndrew Geissler messages::propertyNotWritable(asyncResp->res, "IPv4Addresses"); 951d5afb2caSAndrew Geissler } 952d5afb2caSAndrew Geissler 953d5afb2caSAndrew Geissler if (dhcpv4) 954d5afb2caSAndrew Geissler { 955*8d1b46d7Szhanghch05 if (!json_util::readJson(*dhcpv4, asyncResp->res, "DHCPEnabled", 956d5afb2caSAndrew Geissler ipv4DHCPEnabled)) 957d5afb2caSAndrew Geissler { 958d5afb2caSAndrew Geissler return; 959d5afb2caSAndrew Geissler } 960d5afb2caSAndrew Geissler } 961d5afb2caSAndrew Geissler 962d5afb2caSAndrew Geissler getHypervisorIfaceData( 963d5afb2caSAndrew Geissler ifaceId, 964d5afb2caSAndrew Geissler [this, asyncResp, ifaceId, hostName = std::move(hostName), 965d5afb2caSAndrew Geissler ipv4StaticAddresses = std::move(ipv4StaticAddresses), 966d5afb2caSAndrew Geissler ipv4DHCPEnabled, dhcpv4 = std::move(dhcpv4)]( 967d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 968d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>&) { 969d5afb2caSAndrew Geissler if (!success) 970d5afb2caSAndrew Geissler { 971d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 972d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 973d5afb2caSAndrew Geissler return; 974d5afb2caSAndrew Geissler } 975d5afb2caSAndrew Geissler 976d5afb2caSAndrew Geissler if (ipv4StaticAddresses) 977d5afb2caSAndrew Geissler { 978d5afb2caSAndrew Geissler const nlohmann::json& ipv4Static = *ipv4StaticAddresses; 97964face74SRavi Teja if (ipv4Static.begin() == ipv4Static.end()) 98064face74SRavi Teja { 98164face74SRavi Teja messages::propertyValueTypeError( 98264face74SRavi Teja asyncResp->res, 98364face74SRavi Teja ipv4Static.dump( 98464face74SRavi Teja 2, ' ', true, 98564face74SRavi Teja nlohmann::json::error_handler_t::replace), 98664face74SRavi Teja "IPv4StaticAddresses"); 98764face74SRavi Teja return; 98864face74SRavi Teja } 98964face74SRavi Teja 99064face74SRavi Teja // One and only one hypervisor instance supported 99164face74SRavi Teja if (ipv4Static.size() != 1) 99264face74SRavi Teja { 99364face74SRavi Teja messages::propertyValueFormatError( 99464face74SRavi Teja asyncResp->res, 99564face74SRavi Teja ipv4Static.dump( 99664face74SRavi Teja 2, ' ', true, 99764face74SRavi Teja nlohmann::json::error_handler_t::replace), 99864face74SRavi Teja "IPv4StaticAddresses"); 99964face74SRavi Teja return; 100064face74SRavi Teja } 100164face74SRavi Teja 1002d5afb2caSAndrew Geissler const nlohmann::json& ipv4Json = ipv4Static[0]; 1003d5afb2caSAndrew Geissler // Check if the param is 'null'. If its null, it means that 1004d5afb2caSAndrew Geissler // user wants to delete the IP address. Deleting the IP 1005d5afb2caSAndrew Geissler // address is allowed only if its statically configured. 1006d5afb2caSAndrew Geissler // Deleting the address originated from DHCP is not allowed. 1007d5afb2caSAndrew Geissler if ((ipv4Json.is_null()) && 1008d5afb2caSAndrew Geissler (translateDHCPEnabledToBool(ethData.DHCPEnabled, true))) 1009d5afb2caSAndrew Geissler { 1010d5afb2caSAndrew Geissler BMCWEB_LOG_INFO 1011d5afb2caSAndrew Geissler << "Ignoring the delete on ipv4StaticAddresses " 1012d5afb2caSAndrew Geissler "as the interface is DHCP enabled"; 1013d5afb2caSAndrew Geissler } 1014d5afb2caSAndrew Geissler else 1015d5afb2caSAndrew Geissler { 1016d5afb2caSAndrew Geissler handleHypervisorIPv4StaticPatch(ifaceId, ipv4Static, 1017d5afb2caSAndrew Geissler asyncResp); 1018d5afb2caSAndrew Geissler } 1019d5afb2caSAndrew Geissler } 1020d5afb2caSAndrew Geissler 1021d5afb2caSAndrew Geissler if (hostName) 1022d5afb2caSAndrew Geissler { 1023d5afb2caSAndrew Geissler handleHostnamePatch(*hostName, asyncResp); 1024d5afb2caSAndrew Geissler } 1025d5afb2caSAndrew Geissler 1026d5afb2caSAndrew Geissler if (dhcpv4) 1027d5afb2caSAndrew Geissler { 1028d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, *ipv4DHCPEnabled, asyncResp); 1029d5afb2caSAndrew Geissler } 1030d5afb2caSAndrew Geissler 1031d5afb2caSAndrew Geissler // Set this interface to disabled/inactive. This will be set to 1032d5afb2caSAndrew Geissler // enabled/active by the pldm once the hypervisor consumes the 1033d5afb2caSAndrew Geissler // updated settings from the user. 1034d5afb2caSAndrew Geissler setIPv4InterfaceEnabled(ifaceId, false, asyncResp); 1035d5afb2caSAndrew Geissler }); 1036*8d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::accepted); 1037d5afb2caSAndrew Geissler } 1038d5afb2caSAndrew Geissler }; 10394fbaf64aSAndrew Geissler 10404fbaf64aSAndrew Geissler /** 10414fbaf64aSAndrew Geissler * HypervisorResetActionInfo derived class for delivering Computer Systems 10424fbaf64aSAndrew Geissler * ResetType AllowableValues using ResetInfo schema. 10434fbaf64aSAndrew Geissler */ 10444fbaf64aSAndrew Geissler class HypervisorResetActionInfo : public Node 10454fbaf64aSAndrew Geissler { 10464fbaf64aSAndrew Geissler public: 10474fbaf64aSAndrew Geissler /* 10484fbaf64aSAndrew Geissler * Default Constructor 10494fbaf64aSAndrew Geissler */ 10504fbaf64aSAndrew Geissler HypervisorResetActionInfo(App& app) : 10514fbaf64aSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/ResetActionInfo/") 10524fbaf64aSAndrew Geissler { 10534fbaf64aSAndrew Geissler entityPrivileges = { 10544fbaf64aSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 10554fbaf64aSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 10564fbaf64aSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 10574fbaf64aSAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 10584fbaf64aSAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 10594fbaf64aSAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 10604fbaf64aSAndrew Geissler } 10614fbaf64aSAndrew Geissler 10624fbaf64aSAndrew Geissler private: 10634fbaf64aSAndrew Geissler /** 10644fbaf64aSAndrew Geissler * Functions triggers appropriate requests on DBus 10654fbaf64aSAndrew Geissler */ 1066*8d1b46d7Szhanghch05 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1067*8d1b46d7Szhanghch05 const crow::Request&, const std::vector<std::string>&) override 10684fbaf64aSAndrew Geissler { 10694fbaf64aSAndrew Geissler // Only return action info if hypervisor D-Bus object present 10704fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 10714fbaf64aSAndrew Geissler [asyncResp](const boost::system::error_code ec, 10724fbaf64aSAndrew Geissler const std::vector<std::pair< 10734fbaf64aSAndrew Geissler std::string, std::vector<std::string>>>& objInfo) { 10744fbaf64aSAndrew Geissler if (ec) 10754fbaf64aSAndrew Geissler { 10764fbaf64aSAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 10774fbaf64aSAndrew Geissler 10784fbaf64aSAndrew Geissler // No hypervisor objects found by mapper 10794fbaf64aSAndrew Geissler if (ec.value() == boost::system::errc::io_error) 10804fbaf64aSAndrew Geissler { 10814fbaf64aSAndrew Geissler messages::resourceNotFound(asyncResp->res, "hypervisor", 10824fbaf64aSAndrew Geissler "ResetActionInfo"); 10834fbaf64aSAndrew Geissler return; 10844fbaf64aSAndrew Geissler } 10854fbaf64aSAndrew Geissler 10864fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 10874fbaf64aSAndrew Geissler return; 10884fbaf64aSAndrew Geissler } 10894fbaf64aSAndrew Geissler 10904fbaf64aSAndrew Geissler // One and only one hypervisor instance supported 10914fbaf64aSAndrew Geissler if (objInfo.size() != 1) 10924fbaf64aSAndrew Geissler { 10934fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 10944fbaf64aSAndrew Geissler return; 10954fbaf64aSAndrew Geissler } 10964fbaf64aSAndrew Geissler 10974fbaf64aSAndrew Geissler // The hypervisor object only support the ability to turn On 10984fbaf64aSAndrew Geissler // The system object Action should be utilized for other 10994fbaf64aSAndrew Geissler // operations 11004fbaf64aSAndrew Geissler asyncResp->res.jsonValue = { 11014fbaf64aSAndrew Geissler {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 11024fbaf64aSAndrew Geissler {"@odata.id", 11034fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/ResetActionInfo"}, 11044fbaf64aSAndrew Geissler {"Name", "Reset Action Info"}, 11054fbaf64aSAndrew Geissler {"Id", "ResetActionInfo"}, 11064fbaf64aSAndrew Geissler {"Parameters", 11074fbaf64aSAndrew Geissler {{{"Name", "ResetType"}, 11084fbaf64aSAndrew Geissler {"Required", true}, 11094fbaf64aSAndrew Geissler {"DataType", "String"}, 11104fbaf64aSAndrew Geissler {"AllowableValues", {"On"}}}}}}; 11114fbaf64aSAndrew Geissler }, 11124fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 11134fbaf64aSAndrew Geissler "/xyz/openbmc_project/object_mapper", 11144fbaf64aSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", 11154fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 11164fbaf64aSAndrew Geissler std::array<const char*, 1>{"xyz.openbmc_project.State.Host"}); 11174fbaf64aSAndrew Geissler } 11184fbaf64aSAndrew Geissler }; 11194fbaf64aSAndrew Geissler 11204fbaf64aSAndrew Geissler /** 11214fbaf64aSAndrew Geissler * HypervisorActionsReset class supports the POST method for Reset action. 11224fbaf64aSAndrew Geissler * The class sends data directly to D-Bus. 11234fbaf64aSAndrew Geissler */ 11244fbaf64aSAndrew Geissler class HypervisorActionsReset : public Node 11254fbaf64aSAndrew Geissler { 11264fbaf64aSAndrew Geissler public: 11274fbaf64aSAndrew Geissler HypervisorActionsReset(App& app) : 11284fbaf64aSAndrew Geissler Node(app, 11294fbaf64aSAndrew Geissler "/redfish/v1/Systems/hypervisor/Actions/ComputerSystem.Reset/") 11304fbaf64aSAndrew Geissler { 11314fbaf64aSAndrew Geissler entityPrivileges = { 11324fbaf64aSAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 11334fbaf64aSAndrew Geissler } 11344fbaf64aSAndrew Geissler 11354fbaf64aSAndrew Geissler private: 11364fbaf64aSAndrew Geissler /** 11374fbaf64aSAndrew Geissler * Function handles POST method request. 11384fbaf64aSAndrew Geissler * Analyzes POST body message before sends Reset request data to D-Bus. 11394fbaf64aSAndrew Geissler */ 1140*8d1b46d7Szhanghch05 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1141*8d1b46d7Szhanghch05 const crow::Request& req, 11424fbaf64aSAndrew Geissler const std::vector<std::string>&) override 11434fbaf64aSAndrew Geissler { 11444fbaf64aSAndrew Geissler 11454fbaf64aSAndrew Geissler std::optional<std::string> resetType; 1146*8d1b46d7Szhanghch05 if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 11474fbaf64aSAndrew Geissler { 11484fbaf64aSAndrew Geissler // readJson adds appropriate error to response 11494fbaf64aSAndrew Geissler return; 11504fbaf64aSAndrew Geissler } 11514fbaf64aSAndrew Geissler 11524fbaf64aSAndrew Geissler if (!resetType) 11534fbaf64aSAndrew Geissler { 11544fbaf64aSAndrew Geissler messages::actionParameterMissing( 11554fbaf64aSAndrew Geissler asyncResp->res, "ComputerSystem.Reset", "ResetType"); 11564fbaf64aSAndrew Geissler return; 11574fbaf64aSAndrew Geissler } 11584fbaf64aSAndrew Geissler 11594fbaf64aSAndrew Geissler // Hypervisor object only support On operation 11604fbaf64aSAndrew Geissler if (resetType != "On") 11614fbaf64aSAndrew Geissler { 11624fbaf64aSAndrew Geissler messages::propertyValueNotInList(asyncResp->res, *resetType, 11634fbaf64aSAndrew Geissler "ResetType"); 11644fbaf64aSAndrew Geissler return; 11654fbaf64aSAndrew Geissler } 11664fbaf64aSAndrew Geissler 11674fbaf64aSAndrew Geissler std::string command = "xyz.openbmc_project.State.Host.Transition.On"; 11684fbaf64aSAndrew Geissler 11694fbaf64aSAndrew Geissler crow::connections::systemBus->async_method_call( 11704fbaf64aSAndrew Geissler [asyncResp, resetType](const boost::system::error_code ec) { 11714fbaf64aSAndrew Geissler if (ec) 11724fbaf64aSAndrew Geissler { 11734fbaf64aSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 11744fbaf64aSAndrew Geissler if (ec.value() == boost::asio::error::invalid_argument) 11754fbaf64aSAndrew Geissler { 11764fbaf64aSAndrew Geissler messages::actionParameterNotSupported( 11774fbaf64aSAndrew Geissler asyncResp->res, *resetType, "Reset"); 11784fbaf64aSAndrew Geissler return; 11794fbaf64aSAndrew Geissler } 11804fbaf64aSAndrew Geissler 11814fbaf64aSAndrew Geissler if (ec.value() == boost::asio::error::host_unreachable) 11824fbaf64aSAndrew Geissler { 11834fbaf64aSAndrew Geissler messages::resourceNotFound(asyncResp->res, "Actions", 11844fbaf64aSAndrew Geissler "Reset"); 11854fbaf64aSAndrew Geissler return; 11864fbaf64aSAndrew Geissler } 11874fbaf64aSAndrew Geissler 11884fbaf64aSAndrew Geissler messages::internalError(asyncResp->res); 11894fbaf64aSAndrew Geissler return; 11904fbaf64aSAndrew Geissler } 11914fbaf64aSAndrew Geissler messages::success(asyncResp->res); 11924fbaf64aSAndrew Geissler }, 11934fbaf64aSAndrew Geissler "xyz.openbmc_project.State.Hypervisor", 11944fbaf64aSAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 11954fbaf64aSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 11964fbaf64aSAndrew Geissler "xyz.openbmc_project.State.Host", "RequestedHostTransition", 11974fbaf64aSAndrew Geissler std::variant<std::string>{std::move(command)}); 11984fbaf64aSAndrew Geissler } 11994fbaf64aSAndrew Geissler }; 1200d5afb2caSAndrew Geissler } // namespace redfish 1201