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 /** 18*cc0bb6f2SAndrew Geissler * @brief Retrieves hypervisor state properties over dbus 19*cc0bb6f2SAndrew Geissler * 20*cc0bb6f2SAndrew Geissler * The hypervisor state object is optional so this function will only set the 21*cc0bb6f2SAndrew Geissler * state variables if the object is found 22*cc0bb6f2SAndrew Geissler * 23*cc0bb6f2SAndrew Geissler * @param[in] aResp Shared pointer for completing asynchronous calls. 24*cc0bb6f2SAndrew Geissler * 25*cc0bb6f2SAndrew Geissler * @return None. 26*cc0bb6f2SAndrew Geissler */ 27*cc0bb6f2SAndrew Geissler inline void getHypervisorState(const std::shared_ptr<AsyncResp>& aResp) 28*cc0bb6f2SAndrew Geissler { 29*cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Get hypervisor state information."; 30*cc0bb6f2SAndrew Geissler crow::connections::systemBus->async_method_call( 31*cc0bb6f2SAndrew Geissler [aResp](const boost::system::error_code ec, 32*cc0bb6f2SAndrew Geissler const std::variant<std::string>& hostState) { 33*cc0bb6f2SAndrew Geissler if (ec) 34*cc0bb6f2SAndrew Geissler { 35*cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 36*cc0bb6f2SAndrew Geissler // This is an optional D-Bus object so just return if 37*cc0bb6f2SAndrew Geissler // error occurs 38*cc0bb6f2SAndrew Geissler return; 39*cc0bb6f2SAndrew Geissler } 40*cc0bb6f2SAndrew Geissler 41*cc0bb6f2SAndrew Geissler const std::string* s = std::get_if<std::string>(&hostState); 42*cc0bb6f2SAndrew Geissler if (s == nullptr) 43*cc0bb6f2SAndrew Geissler { 44*cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 45*cc0bb6f2SAndrew Geissler return; 46*cc0bb6f2SAndrew Geissler } 47*cc0bb6f2SAndrew Geissler 48*cc0bb6f2SAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor state: " << *s; 49*cc0bb6f2SAndrew Geissler // Verify Host State 50*cc0bb6f2SAndrew Geissler if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 51*cc0bb6f2SAndrew Geissler { 52*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 53*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 54*cc0bb6f2SAndrew Geissler } 55*cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 56*cc0bb6f2SAndrew Geissler "Quiesced") 57*cc0bb6f2SAndrew Geissler { 58*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 59*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 60*cc0bb6f2SAndrew Geissler } 61*cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 62*cc0bb6f2SAndrew Geissler "Standby") 63*cc0bb6f2SAndrew Geissler { 64*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "On"; 65*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 66*cc0bb6f2SAndrew Geissler } 67*cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 68*cc0bb6f2SAndrew Geissler "TransitioningToRunning") 69*cc0bb6f2SAndrew Geissler { 70*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOn"; 71*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Starting"; 72*cc0bb6f2SAndrew Geissler } 73*cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState." 74*cc0bb6f2SAndrew Geissler "TransitioningToOff") 75*cc0bb6f2SAndrew Geissler { 76*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "PoweringOff"; 77*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Enabled"; 78*cc0bb6f2SAndrew Geissler } 79*cc0bb6f2SAndrew Geissler else if (*s == "xyz.openbmc_project.State.Host.HostState.Off") 80*cc0bb6f2SAndrew Geissler { 81*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["PowerState"] = "Off"; 82*cc0bb6f2SAndrew Geissler aResp->res.jsonValue["Status"]["State"] = "Disabled"; 83*cc0bb6f2SAndrew Geissler } 84*cc0bb6f2SAndrew Geissler else 85*cc0bb6f2SAndrew Geissler { 86*cc0bb6f2SAndrew Geissler messages::internalError(aResp->res); 87*cc0bb6f2SAndrew Geissler return; 88*cc0bb6f2SAndrew Geissler } 89*cc0bb6f2SAndrew Geissler }, 90*cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Hypervisor", 91*cc0bb6f2SAndrew Geissler "/xyz/openbmc_project/state/hypervisor0", 92*cc0bb6f2SAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 93*cc0bb6f2SAndrew Geissler "xyz.openbmc_project.State.Host", "CurrentHostState"); 94*cc0bb6f2SAndrew Geissler } 95*cc0bb6f2SAndrew Geissler 96*cc0bb6f2SAndrew Geissler /** 97d5afb2caSAndrew Geissler * Hypervisor Systems derived class for delivering Computer Systems Schema. 98d5afb2caSAndrew Geissler */ 99d5afb2caSAndrew Geissler class HypervisorSystem : public Node 100d5afb2caSAndrew Geissler { 101d5afb2caSAndrew Geissler public: 102d5afb2caSAndrew Geissler /* 103d5afb2caSAndrew Geissler * Default Constructor 104d5afb2caSAndrew Geissler */ 105d5afb2caSAndrew Geissler HypervisorSystem(App& app) : Node(app, "/redfish/v1/Systems/hypervisor/") 106d5afb2caSAndrew Geissler { 107d5afb2caSAndrew Geissler entityPrivileges = { 108d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 109d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 110d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 111d5afb2caSAndrew Geissler } 112d5afb2caSAndrew Geissler 113d5afb2caSAndrew Geissler private: 114d5afb2caSAndrew Geissler /** 115d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 116d5afb2caSAndrew Geissler */ 117d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 118d5afb2caSAndrew Geissler const std::vector<std::string>&) override 119d5afb2caSAndrew Geissler { 120d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 121d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 122d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec, 123d5afb2caSAndrew Geissler const std::variant<std::string>& /*hostName*/) { 124d5afb2caSAndrew Geissler if (ec) 125d5afb2caSAndrew Geissler { 126d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 127d5afb2caSAndrew Geissler "hypervisor"); 128d5afb2caSAndrew Geissler return; 129d5afb2caSAndrew Geissler } 130d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor is available"; 131d5afb2caSAndrew Geissler 132d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 133d5afb2caSAndrew Geissler "#ComputerSystem.v1_6_0.ComputerSystem"; 134d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 135d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor"; 136d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = "Hypervisor"; 137d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor"; 138d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Id"] = "hypervisor"; 139d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 140d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 141d5afb2caSAndrew Geissler asyncResp->res.jsonValue["EthernetInterfaces"] = { 142d5afb2caSAndrew Geissler {"@odata.id", "/redfish/v1/Systems/hypervisor/" 143d5afb2caSAndrew Geissler "EthernetInterfaces"}}; 144*cc0bb6f2SAndrew Geissler getHypervisorState(asyncResp); 145d5afb2caSAndrew Geissler // TODO: Add "SystemType" : "hypervisor" 146d5afb2caSAndrew Geissler }, 147d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 148d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 149d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Get", 150d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 151d5afb2caSAndrew Geissler } 152d5afb2caSAndrew Geissler }; 153d5afb2caSAndrew Geissler 154d5afb2caSAndrew Geissler /** 155d5afb2caSAndrew Geissler * HypervisorInterfaceCollection class to handle the GET and PATCH on Hypervisor 156d5afb2caSAndrew Geissler * Interface 157d5afb2caSAndrew Geissler */ 158d5afb2caSAndrew Geissler class HypervisorInterfaceCollection : public Node 159d5afb2caSAndrew Geissler { 160d5afb2caSAndrew Geissler public: 161d5afb2caSAndrew Geissler HypervisorInterfaceCollection(App& app) : 162d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/") 163d5afb2caSAndrew Geissler { 164d5afb2caSAndrew Geissler entityPrivileges = { 165d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 166d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 167d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 168d5afb2caSAndrew Geissler } 169d5afb2caSAndrew Geissler 170d5afb2caSAndrew Geissler private: 171d5afb2caSAndrew Geissler /** 172d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 173d5afb2caSAndrew Geissler */ 174d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 175d5afb2caSAndrew Geissler const std::vector<std::string>&) override 176d5afb2caSAndrew Geissler { 177d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 178d5afb2caSAndrew Geissler const std::array<const char*, 1> interfaces = { 179d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface"}; 180d5afb2caSAndrew Geissler 181d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 182d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code error, 183d5afb2caSAndrew Geissler const std::vector<std::string>& ifaceList) { 184d5afb2caSAndrew Geissler if (error) 185d5afb2caSAndrew Geissler { 186d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, "System", 187d5afb2caSAndrew Geissler "hypervisor"); 188d5afb2caSAndrew Geissler return; 189d5afb2caSAndrew Geissler } 190d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 191d5afb2caSAndrew Geissler "#EthernetInterfaceCollection." 192d5afb2caSAndrew Geissler "EthernetInterfaceCollection"; 193d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.id"] = 194d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces"; 195d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = "Hypervisor Ethernet " 196d5afb2caSAndrew Geissler "Interface Collection"; 197d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 198d5afb2caSAndrew Geissler "Collection of Virtual Management " 199d5afb2caSAndrew Geissler "Interfaces for the hypervisor"; 200d5afb2caSAndrew Geissler 201d5afb2caSAndrew Geissler nlohmann::json& ifaceArray = 202d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members"]; 203d5afb2caSAndrew Geissler ifaceArray = nlohmann::json::array(); 204d5afb2caSAndrew Geissler for (const std::string& iface : ifaceList) 205d5afb2caSAndrew Geissler { 2062dfd18efSEd Tanous sdbusplus::message::object_path path(iface); 2072dfd18efSEd Tanous std::string name = path.filename(); 2082dfd18efSEd Tanous if (name.empty()) 209d5afb2caSAndrew Geissler { 2102dfd18efSEd Tanous continue; 2112dfd18efSEd Tanous } 2122dfd18efSEd Tanous 213d5afb2caSAndrew Geissler ifaceArray.push_back( 214d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Systems/hypervisor/" 215d5afb2caSAndrew Geissler "EthernetInterfaces/" + 2162dfd18efSEd Tanous name}}); 217d5afb2caSAndrew Geissler } 218d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 219d5afb2caSAndrew Geissler ifaceArray.size(); 220d5afb2caSAndrew Geissler }, 221d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 222d5afb2caSAndrew Geissler "/xyz/openbmc_project/object_mapper", 223d5afb2caSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 224d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 0, interfaces); 225d5afb2caSAndrew Geissler } 226d5afb2caSAndrew Geissler }; 227d5afb2caSAndrew Geissler 228d5afb2caSAndrew Geissler inline bool extractHypervisorInterfaceData( 229d5afb2caSAndrew Geissler const std::string& ethIfaceId, const GetManagedObjects& dbusData, 230d5afb2caSAndrew Geissler EthernetInterfaceData& ethData, 231d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData>& ipv4Config) 232d5afb2caSAndrew Geissler { 233d5afb2caSAndrew Geissler bool idFound = false; 234d5afb2caSAndrew Geissler for (const auto& objpath : dbusData) 235d5afb2caSAndrew Geissler { 236d5afb2caSAndrew Geissler for (const auto& ifacePair : objpath.second) 237d5afb2caSAndrew Geissler { 238d5afb2caSAndrew Geissler if (objpath.first == 239d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId) 240d5afb2caSAndrew Geissler { 241d5afb2caSAndrew Geissler idFound = true; 242d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 243d5afb2caSAndrew Geissler { 244d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 245d5afb2caSAndrew Geissler { 246d5afb2caSAndrew Geissler if (propertyPair.first == "MACAddress") 247d5afb2caSAndrew Geissler { 248d5afb2caSAndrew Geissler const std::string* mac = 249d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 250d5afb2caSAndrew Geissler if (mac != nullptr) 251d5afb2caSAndrew Geissler { 252d5afb2caSAndrew Geissler ethData.mac_address = *mac; 253d5afb2caSAndrew Geissler } 254d5afb2caSAndrew Geissler } 255d5afb2caSAndrew Geissler } 256d5afb2caSAndrew Geissler } 257d5afb2caSAndrew Geissler else if (ifacePair.first == 258d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface") 259d5afb2caSAndrew Geissler { 260d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 261d5afb2caSAndrew Geissler { 262d5afb2caSAndrew Geissler if (propertyPair.first == "DHCPEnabled") 263d5afb2caSAndrew Geissler { 264d5afb2caSAndrew Geissler const std::string* dhcp = 265d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 266d5afb2caSAndrew Geissler if (dhcp != nullptr) 267d5afb2caSAndrew Geissler { 268d5afb2caSAndrew Geissler ethData.DHCPEnabled = *dhcp; 269d5afb2caSAndrew Geissler break; // Interested on only "DHCPEnabled". 270d5afb2caSAndrew Geissler // Stop parsing since we got the 271d5afb2caSAndrew Geissler // "DHCPEnabled" value. 272d5afb2caSAndrew Geissler } 273d5afb2caSAndrew Geissler } 274d5afb2caSAndrew Geissler } 275d5afb2caSAndrew Geissler } 276d5afb2caSAndrew Geissler } 277d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor/" + 278d5afb2caSAndrew Geissler ethIfaceId + "/ipv4/addr0") 279d5afb2caSAndrew Geissler { 280d5afb2caSAndrew Geissler std::pair<boost::container::flat_set<IPv4AddressData>::iterator, 281d5afb2caSAndrew Geissler bool> 282d5afb2caSAndrew Geissler it = ipv4Config.insert(IPv4AddressData{}); 283d5afb2caSAndrew Geissler IPv4AddressData& ipv4Address = *it.first; 284d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Object.Enable") 285d5afb2caSAndrew Geissler { 286d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 287d5afb2caSAndrew Geissler { 288d5afb2caSAndrew Geissler if (property.first == "Enabled") 289d5afb2caSAndrew Geissler { 290d5afb2caSAndrew Geissler const bool* intfEnable = 291d5afb2caSAndrew Geissler std::get_if<bool>(&property.second); 292d5afb2caSAndrew Geissler if (intfEnable != nullptr) 293d5afb2caSAndrew Geissler { 294d5afb2caSAndrew Geissler ipv4Address.isActive = *intfEnable; 295d5afb2caSAndrew Geissler break; 296d5afb2caSAndrew Geissler } 297d5afb2caSAndrew Geissler } 298d5afb2caSAndrew Geissler } 299d5afb2caSAndrew Geissler } 300d5afb2caSAndrew Geissler if (ifacePair.first == "xyz.openbmc_project.Network.IP") 301d5afb2caSAndrew Geissler { 302d5afb2caSAndrew Geissler for (auto& property : ifacePair.second) 303d5afb2caSAndrew Geissler { 304d5afb2caSAndrew Geissler if (property.first == "Address") 305d5afb2caSAndrew Geissler { 306d5afb2caSAndrew Geissler const std::string* address = 307d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 308d5afb2caSAndrew Geissler if (address != nullptr) 309d5afb2caSAndrew Geissler { 310d5afb2caSAndrew Geissler ipv4Address.address = *address; 311d5afb2caSAndrew Geissler } 312d5afb2caSAndrew Geissler } 313d5afb2caSAndrew Geissler else if (property.first == "Origin") 314d5afb2caSAndrew Geissler { 315d5afb2caSAndrew Geissler const std::string* origin = 316d5afb2caSAndrew Geissler std::get_if<std::string>(&property.second); 317d5afb2caSAndrew Geissler if (origin != nullptr) 318d5afb2caSAndrew Geissler { 319d5afb2caSAndrew Geissler ipv4Address.origin = 320d5afb2caSAndrew Geissler translateAddressOriginDbusToRedfish(*origin, 321d5afb2caSAndrew Geissler true); 322d5afb2caSAndrew Geissler } 323d5afb2caSAndrew Geissler } 324d5afb2caSAndrew Geissler else if (property.first == "PrefixLength") 325d5afb2caSAndrew Geissler { 326d5afb2caSAndrew Geissler const uint8_t* mask = 327d5afb2caSAndrew Geissler std::get_if<uint8_t>(&property.second); 328d5afb2caSAndrew Geissler if (mask != nullptr) 329d5afb2caSAndrew Geissler { 330d5afb2caSAndrew Geissler // convert it to the string 331d5afb2caSAndrew Geissler ipv4Address.netmask = getNetmask(*mask); 332d5afb2caSAndrew Geissler } 333d5afb2caSAndrew Geissler } 334d5afb2caSAndrew Geissler else 335d5afb2caSAndrew Geissler { 336d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR 337d5afb2caSAndrew Geissler << "Got extra property: " << property.first 338d5afb2caSAndrew Geissler << " on the " << objpath.first.str << " object"; 339d5afb2caSAndrew Geissler } 340d5afb2caSAndrew Geissler } 341d5afb2caSAndrew Geissler } 342d5afb2caSAndrew Geissler } 343d5afb2caSAndrew Geissler if (objpath.first == "/xyz/openbmc_project/network/hypervisor") 344d5afb2caSAndrew Geissler { 345d5afb2caSAndrew Geissler // System configuration shows up in the global namespace, so no 346d5afb2caSAndrew Geissler // need to check eth number 347d5afb2caSAndrew Geissler if (ifacePair.first == 348d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration") 349d5afb2caSAndrew Geissler { 350d5afb2caSAndrew Geissler for (const auto& propertyPair : ifacePair.second) 351d5afb2caSAndrew Geissler { 352d5afb2caSAndrew Geissler if (propertyPair.first == "HostName") 353d5afb2caSAndrew Geissler { 354d5afb2caSAndrew Geissler const std::string* hostName = 355d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 356d5afb2caSAndrew Geissler if (hostName != nullptr) 357d5afb2caSAndrew Geissler { 358d5afb2caSAndrew Geissler ethData.hostname = *hostName; 359d5afb2caSAndrew Geissler } 360d5afb2caSAndrew Geissler } 361d5afb2caSAndrew Geissler else if (propertyPair.first == "DefaultGateway") 362d5afb2caSAndrew Geissler { 363d5afb2caSAndrew Geissler const std::string* defaultGateway = 364d5afb2caSAndrew Geissler std::get_if<std::string>(&propertyPair.second); 365d5afb2caSAndrew Geissler if (defaultGateway != nullptr) 366d5afb2caSAndrew Geissler { 367d5afb2caSAndrew Geissler ethData.default_gateway = *defaultGateway; 368d5afb2caSAndrew Geissler } 369d5afb2caSAndrew Geissler } 370d5afb2caSAndrew Geissler } 371d5afb2caSAndrew Geissler } 372d5afb2caSAndrew Geissler } 373d5afb2caSAndrew Geissler } 374d5afb2caSAndrew Geissler } 375d5afb2caSAndrew Geissler return idFound; 376d5afb2caSAndrew Geissler } 377d5afb2caSAndrew Geissler /** 378d5afb2caSAndrew Geissler * Function that retrieves all properties for given Hypervisor Ethernet 379d5afb2caSAndrew Geissler * Interface Object from Settings Manager 380d5afb2caSAndrew Geissler * @param ethIfaceId Hypervisor ethernet interface id to query on DBus 381d5afb2caSAndrew Geissler * @param callback a function that shall be called to convert Dbus output 382d5afb2caSAndrew Geissler * into JSON 383d5afb2caSAndrew Geissler */ 384d5afb2caSAndrew Geissler template <typename CallbackFunc> 385d5afb2caSAndrew Geissler void getHypervisorIfaceData(const std::string& ethIfaceId, 386d5afb2caSAndrew Geissler CallbackFunc&& callback) 387d5afb2caSAndrew Geissler { 388d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 389d5afb2caSAndrew Geissler [ethIfaceId{std::string{ethIfaceId}}, 390d5afb2caSAndrew Geissler callback{std::move(callback)}](const boost::system::error_code error, 391d5afb2caSAndrew Geissler const GetManagedObjects& resp) { 392d5afb2caSAndrew Geissler EthernetInterfaceData ethData{}; 393d5afb2caSAndrew Geissler boost::container::flat_set<IPv4AddressData> ipv4Data; 394d5afb2caSAndrew Geissler if (error) 395d5afb2caSAndrew Geissler { 396d5afb2caSAndrew Geissler callback(false, ethData, ipv4Data); 397d5afb2caSAndrew Geissler return; 398d5afb2caSAndrew Geissler } 399d5afb2caSAndrew Geissler 400d5afb2caSAndrew Geissler bool found = extractHypervisorInterfaceData(ethIfaceId, resp, 401d5afb2caSAndrew Geissler ethData, ipv4Data); 402d5afb2caSAndrew Geissler if (!found) 403d5afb2caSAndrew Geissler { 404d5afb2caSAndrew Geissler BMCWEB_LOG_INFO << "Hypervisor Interface not found"; 405d5afb2caSAndrew Geissler } 406d5afb2caSAndrew Geissler callback(found, ethData, ipv4Data); 407d5afb2caSAndrew Geissler }, 408d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", "/", 409d5afb2caSAndrew Geissler "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 410d5afb2caSAndrew Geissler } 411d5afb2caSAndrew Geissler 412d5afb2caSAndrew Geissler /** 413d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface IPAddress DBUS 414d5afb2caSAndrew Geissler * 415d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 416d5afb2caSAndrew Geissler * @param[in] ipv4Address Address from the incoming request 417d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 418d5afb2caSAndrew Geissler * 419d5afb2caSAndrew Geissler * @return None. 420d5afb2caSAndrew Geissler */ 421d5afb2caSAndrew Geissler inline void setHypervisorIPv4Address(const std::shared_ptr<AsyncResp>& aResp, 422d5afb2caSAndrew Geissler const std::string& ethIfaceId, 423d5afb2caSAndrew Geissler const std::string& ipv4Address) 424d5afb2caSAndrew Geissler { 425d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor IPaddress : " << ipv4Address 426d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 427d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 428d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 429d5afb2caSAndrew Geissler if (ec) 430d5afb2caSAndrew Geissler { 431d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 432d5afb2caSAndrew Geissler return; 433d5afb2caSAndrew Geissler } 434d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress is Set"; 435d5afb2caSAndrew Geissler }, 436d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 437d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 438d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 439d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Address", 440d5afb2caSAndrew Geissler std::variant<std::string>(ipv4Address)); 441d5afb2caSAndrew Geissler } 442d5afb2caSAndrew Geissler 443d5afb2caSAndrew Geissler /** 444d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface SubnetMask DBUS 445d5afb2caSAndrew Geissler * 446d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 447d5afb2caSAndrew Geissler * @param[in] subnet SubnetMask from the incoming request 448d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 449d5afb2caSAndrew Geissler * 450d5afb2caSAndrew Geissler * @return None. 451d5afb2caSAndrew Geissler */ 452d5afb2caSAndrew Geissler inline void setHypervisorIPv4Subnet(const std::shared_ptr<AsyncResp>& aResp, 453d5afb2caSAndrew Geissler const std::string& ethIfaceId, 454d5afb2caSAndrew Geissler const uint8_t subnet) 455d5afb2caSAndrew Geissler { 456d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Setting the Hypervisor subnet : " << subnet 457d5afb2caSAndrew Geissler << " on Iface: " << ethIfaceId; 458d5afb2caSAndrew Geissler 459d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 460d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 461d5afb2caSAndrew Geissler if (ec) 462d5afb2caSAndrew Geissler { 463d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 464d5afb2caSAndrew Geissler return; 465d5afb2caSAndrew Geissler } 466d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "SubnetMask is Set"; 467d5afb2caSAndrew Geissler }, 468d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 469d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ethIfaceId + "/ipv4/addr0", 470d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 471d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "PrefixLength", 472d5afb2caSAndrew Geissler std::variant<uint8_t>(subnet)); 473d5afb2caSAndrew Geissler } 474d5afb2caSAndrew Geissler 475d5afb2caSAndrew Geissler /** 476d5afb2caSAndrew Geissler * @brief Sets the Hypervisor Interface Gateway DBUS 477d5afb2caSAndrew Geissler * 478d5afb2caSAndrew Geissler * @param[in] aResp Shared pointer for generating response message. 479d5afb2caSAndrew Geissler * @param[in] gateway Gateway from the incoming request 480d5afb2caSAndrew Geissler * @param[in] ethIfaceId Hypervisor Interface Id 481d5afb2caSAndrew Geissler * 482d5afb2caSAndrew Geissler * @return None. 483d5afb2caSAndrew Geissler */ 484d5afb2caSAndrew Geissler inline void setHypervisorIPv4Gateway(const std::shared_ptr<AsyncResp>& aResp, 485d5afb2caSAndrew Geissler const std::string& gateway) 486d5afb2caSAndrew Geissler { 487d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG 488d5afb2caSAndrew Geissler << "Setting the DefaultGateway to the last configured gateway"; 489d5afb2caSAndrew Geissler 490d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 491d5afb2caSAndrew Geissler [aResp](const boost::system::error_code ec) { 492d5afb2caSAndrew Geissler if (ec) 493d5afb2caSAndrew Geissler { 494d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 495d5afb2caSAndrew Geissler return; 496d5afb2caSAndrew Geissler } 497d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Default Gateway is Set"; 498d5afb2caSAndrew Geissler }, 499d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 500d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 501d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 502d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "DefaultGateway", 503d5afb2caSAndrew Geissler std::variant<std::string>(gateway)); 504d5afb2caSAndrew Geissler } 505d5afb2caSAndrew Geissler 506d5afb2caSAndrew Geissler /** 507d5afb2caSAndrew Geissler * @brief Creates a static IPv4 entry 508d5afb2caSAndrew Geissler * 509d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface upon which to create the IPv4 entry 510d5afb2caSAndrew Geissler * @param[in] prefixLength IPv4 prefix syntax for the subnet mask 511d5afb2caSAndrew Geissler * @param[in] gateway IPv4 address of this interfaces gateway 512d5afb2caSAndrew Geissler * @param[in] address IPv4 address to assign to this interface 513d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 514d5afb2caSAndrew Geissler * 515d5afb2caSAndrew Geissler * @return None 516d5afb2caSAndrew Geissler */ 517d5afb2caSAndrew Geissler inline void createHypervisorIPv4(const std::string& ifaceId, 518d5afb2caSAndrew Geissler uint8_t prefixLength, 519d5afb2caSAndrew Geissler const std::string& gateway, 520d5afb2caSAndrew Geissler const std::string& address, 521d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 522d5afb2caSAndrew Geissler { 523d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 524d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 525d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 526d5afb2caSAndrew Geissler } 527d5afb2caSAndrew Geissler 528d5afb2caSAndrew Geissler /** 529d5afb2caSAndrew Geissler * @brief Deletes given IPv4 interface 530d5afb2caSAndrew Geissler * 531d5afb2caSAndrew Geissler * @param[in] ifaceId Id of interface whose IP should be deleted 532d5afb2caSAndrew Geissler * @param[io] asyncResp Response object that will be returned to client 533d5afb2caSAndrew Geissler * 534d5afb2caSAndrew Geissler * @return None 535d5afb2caSAndrew Geissler */ 536d5afb2caSAndrew Geissler inline void deleteHypervisorIPv4(const std::string& ifaceId, 537d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 538d5afb2caSAndrew Geissler { 539d5afb2caSAndrew Geissler std::string address = "0.0.0.0"; 540d5afb2caSAndrew Geissler std::string gateway = "0.0.0.0"; 541d5afb2caSAndrew Geissler const uint8_t prefixLength = 0; 542d5afb2caSAndrew Geissler setHypervisorIPv4Address(asyncResp, ifaceId, address); 543d5afb2caSAndrew Geissler setHypervisorIPv4Gateway(asyncResp, gateway); 544d5afb2caSAndrew Geissler setHypervisorIPv4Subnet(asyncResp, ifaceId, prefixLength); 545d5afb2caSAndrew Geissler } 546d5afb2caSAndrew Geissler 547d5afb2caSAndrew Geissler /** 548d5afb2caSAndrew Geissler * HypervisorInterface derived class for delivering Ethernet Schema 549d5afb2caSAndrew Geissler */ 550d5afb2caSAndrew Geissler class HypervisorInterface : public Node 551d5afb2caSAndrew Geissler { 552d5afb2caSAndrew Geissler public: 553d5afb2caSAndrew Geissler /* 554d5afb2caSAndrew Geissler * Default Constructor 555d5afb2caSAndrew Geissler */ 556d5afb2caSAndrew Geissler HypervisorInterface(App& app) : 557d5afb2caSAndrew Geissler Node(app, "/redfish/v1/Systems/hypervisor/EthernetInterfaces/<str>/", 558d5afb2caSAndrew Geissler std::string()) 559d5afb2caSAndrew Geissler { 560d5afb2caSAndrew Geissler entityPrivileges = { 561d5afb2caSAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 562d5afb2caSAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 563d5afb2caSAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}}; 564d5afb2caSAndrew Geissler } 565d5afb2caSAndrew Geissler 566d5afb2caSAndrew Geissler private: 567d5afb2caSAndrew Geissler void parseInterfaceData( 568d5afb2caSAndrew Geissler nlohmann::json& jsonResponse, const std::string& ifaceId, 569d5afb2caSAndrew Geissler const EthernetInterfaceData& ethData, 570d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) 571d5afb2caSAndrew Geissler { 572d5afb2caSAndrew Geissler jsonResponse["Id"] = ifaceId; 573d5afb2caSAndrew Geissler jsonResponse["@odata.id"] = 574d5afb2caSAndrew Geissler "/redfish/v1/Systems/hypervisor/EthernetInterfaces/" + ifaceId; 575d5afb2caSAndrew Geissler jsonResponse["InterfaceEnabled"] = true; 576d5afb2caSAndrew Geissler jsonResponse["MACAddress"] = ethData.mac_address; 577d5afb2caSAndrew Geissler 578d5afb2caSAndrew Geissler jsonResponse["HostName"] = ethData.hostname; 579d5afb2caSAndrew Geissler jsonResponse["DHCPv4"]["DHCPEnabled"] = 580d5afb2caSAndrew Geissler translateDHCPEnabledToBool(ethData.DHCPEnabled, true); 581d5afb2caSAndrew Geissler 582d5afb2caSAndrew Geissler nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"]; 583d5afb2caSAndrew Geissler nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"]; 584d5afb2caSAndrew Geissler ipv4Array = nlohmann::json::array(); 585d5afb2caSAndrew Geissler ipv4StaticArray = nlohmann::json::array(); 586d5afb2caSAndrew Geissler for (auto& ipv4Config : ipv4Data) 587d5afb2caSAndrew Geissler { 588d5afb2caSAndrew Geissler if (ipv4Config.isActive) 589d5afb2caSAndrew Geissler { 590d5afb2caSAndrew Geissler 591d5afb2caSAndrew Geissler ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin}, 592d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 593d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 594d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 595d5afb2caSAndrew Geissler if (ipv4Config.origin == "Static") 596d5afb2caSAndrew Geissler { 597d5afb2caSAndrew Geissler ipv4StaticArray.push_back( 598d5afb2caSAndrew Geissler {{"AddressOrigin", ipv4Config.origin}, 599d5afb2caSAndrew Geissler {"SubnetMask", ipv4Config.netmask}, 600d5afb2caSAndrew Geissler {"Address", ipv4Config.address}, 601d5afb2caSAndrew Geissler {"Gateway", ethData.default_gateway}}); 602d5afb2caSAndrew Geissler } 603d5afb2caSAndrew Geissler } 604d5afb2caSAndrew Geissler } 605d5afb2caSAndrew Geissler } 606d5afb2caSAndrew Geissler 607d5afb2caSAndrew Geissler void handleHypervisorIPv4StaticPatch( 608d5afb2caSAndrew Geissler const std::string& ifaceId, const nlohmann::json& input, 609d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 610d5afb2caSAndrew Geissler { 611d5afb2caSAndrew Geissler if ((!input.is_array()) || input.empty()) 612d5afb2caSAndrew Geissler { 613d5afb2caSAndrew Geissler messages::propertyValueTypeError(asyncResp->res, input.dump(), 614d5afb2caSAndrew Geissler "IPv4StaticAddresses"); 615d5afb2caSAndrew Geissler return; 616d5afb2caSAndrew Geissler } 617d5afb2caSAndrew Geissler 618d5afb2caSAndrew Geissler // Hypervisor considers the first IP address in the array list 619d5afb2caSAndrew Geissler // as the Hypervisor's virtual management interface supports single IPv4 620d5afb2caSAndrew Geissler // address 621d5afb2caSAndrew Geissler const nlohmann::json& thisJson = input[0]; 622d5afb2caSAndrew Geissler 623d5afb2caSAndrew Geissler // For the error string 624d5afb2caSAndrew Geissler std::string pathString = "IPv4StaticAddresses/1"; 625d5afb2caSAndrew Geissler 626d5afb2caSAndrew Geissler if (!thisJson.is_null() && !thisJson.empty()) 627d5afb2caSAndrew Geissler { 628d5afb2caSAndrew Geissler std::optional<std::string> address; 629d5afb2caSAndrew Geissler std::optional<std::string> subnetMask; 630d5afb2caSAndrew Geissler std::optional<std::string> gateway; 631d5afb2caSAndrew Geissler nlohmann::json thisJsonCopy = thisJson; 632d5afb2caSAndrew Geissler if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address", 633d5afb2caSAndrew Geissler address, "SubnetMask", subnetMask, 634d5afb2caSAndrew Geissler "Gateway", gateway)) 635d5afb2caSAndrew Geissler { 63671f52d96SEd Tanous messages::propertyValueFormatError( 63771f52d96SEd Tanous asyncResp->res, 63871f52d96SEd Tanous thisJson.dump(2, ' ', true, 63971f52d96SEd Tanous nlohmann::json::error_handler_t::replace), 64071f52d96SEd Tanous pathString); 641d5afb2caSAndrew Geissler return; 642d5afb2caSAndrew Geissler } 643d5afb2caSAndrew Geissler 644d5afb2caSAndrew Geissler uint8_t prefixLength = 0; 645d5afb2caSAndrew Geissler bool errorInEntry = false; 646d5afb2caSAndrew Geissler if (address) 647d5afb2caSAndrew Geissler { 648d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*address)) 649d5afb2caSAndrew Geissler { 650d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *address, 651d5afb2caSAndrew Geissler pathString + "/Address"); 652d5afb2caSAndrew Geissler errorInEntry = true; 653d5afb2caSAndrew Geissler } 654d5afb2caSAndrew Geissler } 655d5afb2caSAndrew Geissler else 656d5afb2caSAndrew Geissler { 657d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 658d5afb2caSAndrew Geissler pathString + "/Address"); 659d5afb2caSAndrew Geissler errorInEntry = true; 660d5afb2caSAndrew Geissler } 661d5afb2caSAndrew Geissler 662d5afb2caSAndrew Geissler if (subnetMask) 663d5afb2caSAndrew Geissler { 664d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 665d5afb2caSAndrew Geissler { 666d5afb2caSAndrew Geissler messages::propertyValueFormatError( 667d5afb2caSAndrew Geissler asyncResp->res, *subnetMask, 668d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 669d5afb2caSAndrew Geissler errorInEntry = true; 670d5afb2caSAndrew Geissler } 671d5afb2caSAndrew Geissler } 672d5afb2caSAndrew Geissler else 673d5afb2caSAndrew Geissler { 674d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 675d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 676d5afb2caSAndrew Geissler errorInEntry = true; 677d5afb2caSAndrew Geissler } 678d5afb2caSAndrew Geissler 679d5afb2caSAndrew Geissler if (gateway) 680d5afb2caSAndrew Geissler { 681d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*gateway)) 682d5afb2caSAndrew Geissler { 683d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *gateway, 684d5afb2caSAndrew Geissler pathString + "/Gateway"); 685d5afb2caSAndrew Geissler errorInEntry = true; 686d5afb2caSAndrew Geissler } 687d5afb2caSAndrew Geissler } 688d5afb2caSAndrew Geissler else 689d5afb2caSAndrew Geissler { 690d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 691d5afb2caSAndrew Geissler pathString + "/Gateway"); 692d5afb2caSAndrew Geissler errorInEntry = true; 693d5afb2caSAndrew Geissler } 694d5afb2caSAndrew Geissler 695d5afb2caSAndrew Geissler if (errorInEntry) 696d5afb2caSAndrew Geissler { 697d5afb2caSAndrew Geissler return; 698d5afb2caSAndrew Geissler } 699d5afb2caSAndrew Geissler 700d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Calling createHypervisorIPv4 on : " << ifaceId 701d5afb2caSAndrew Geissler << "," << *address; 702d5afb2caSAndrew Geissler createHypervisorIPv4(ifaceId, prefixLength, *gateway, *address, 703d5afb2caSAndrew Geissler asyncResp); 704d5afb2caSAndrew Geissler // Set the DHCPEnabled to false since the Static IPv4 is set 705d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, false, asyncResp); 706d5afb2caSAndrew Geissler } 707d5afb2caSAndrew Geissler else 708d5afb2caSAndrew Geissler { 709d5afb2caSAndrew Geissler if (thisJson.is_null()) 710d5afb2caSAndrew Geissler { 711d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 712d5afb2caSAndrew Geissler } 713d5afb2caSAndrew Geissler } 714d5afb2caSAndrew Geissler } 715d5afb2caSAndrew Geissler 716d5afb2caSAndrew Geissler bool isHostnameValid(const std::string& hostName) 717d5afb2caSAndrew Geissler { 718d5afb2caSAndrew Geissler // As per RFC 1123 719d5afb2caSAndrew Geissler // Allow up to 255 characters 720d5afb2caSAndrew Geissler if (hostName.length() > 255) 721d5afb2caSAndrew Geissler { 722d5afb2caSAndrew Geissler return false; 723d5afb2caSAndrew Geissler } 724d5afb2caSAndrew Geissler // Validate the regex 725d5afb2caSAndrew Geissler const std::regex pattern( 726d5afb2caSAndrew Geissler "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); 727d5afb2caSAndrew Geissler 728d5afb2caSAndrew Geissler return std::regex_match(hostName, pattern); 729d5afb2caSAndrew Geissler } 730d5afb2caSAndrew Geissler 731d5afb2caSAndrew Geissler void handleHostnamePatch(const std::string& hostName, 732d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 733d5afb2caSAndrew Geissler { 734d5afb2caSAndrew Geissler if (!isHostnameValid(hostName)) 735d5afb2caSAndrew Geissler { 736d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, hostName, 737d5afb2caSAndrew Geissler "HostName"); 738d5afb2caSAndrew Geissler return; 739d5afb2caSAndrew Geissler } 740d5afb2caSAndrew Geissler 741d5afb2caSAndrew Geissler asyncResp->res.jsonValue["HostName"] = hostName; 742d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 743d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 744d5afb2caSAndrew Geissler if (ec) 745d5afb2caSAndrew Geissler { 746d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 747d5afb2caSAndrew Geissler } 748d5afb2caSAndrew Geissler }, 749d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 750d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 751d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 752d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 753d5afb2caSAndrew Geissler std::variant<std::string>(hostName)); 754d5afb2caSAndrew Geissler } 755d5afb2caSAndrew Geissler 756d5afb2caSAndrew Geissler void setIPv4InterfaceEnabled(const std::string& ifaceId, 757d5afb2caSAndrew Geissler const bool& isActive, 758d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 759d5afb2caSAndrew Geissler { 760d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 761d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 762d5afb2caSAndrew Geissler if (ec) 763d5afb2caSAndrew Geissler { 764d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 765d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 766d5afb2caSAndrew Geissler return; 767d5afb2caSAndrew Geissler } 768d5afb2caSAndrew Geissler }, 769d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 770d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 771d5afb2caSAndrew Geissler "/ipv4/addr0", 772d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 773d5afb2caSAndrew Geissler "xyz.openbmc_project.Object.Enable", "Enabled", 774d5afb2caSAndrew Geissler std::variant<bool>(isActive)); 775d5afb2caSAndrew Geissler } 776d5afb2caSAndrew Geissler 777d5afb2caSAndrew Geissler void setDHCPEnabled(const std::string& ifaceId, const bool& ipv4DHCPEnabled, 778d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 779d5afb2caSAndrew Geissler { 780d5afb2caSAndrew Geissler const std::string dhcp = 781d5afb2caSAndrew Geissler getDhcpEnabledEnumeration(ipv4DHCPEnabled, false); 782d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 783d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 784d5afb2caSAndrew Geissler if (ec) 785d5afb2caSAndrew Geissler { 786d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 787d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 788d5afb2caSAndrew Geissler return; 789d5afb2caSAndrew Geissler } 790d5afb2caSAndrew Geissler }, 791d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 792d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId, 793d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 794d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface", "DHCPEnabled", 795d5afb2caSAndrew Geissler std::variant<std::string>{dhcp}); 796d5afb2caSAndrew Geissler 797d5afb2caSAndrew Geissler // Set the IPv4 address origin to the DHCP / Static as per the new value 798d5afb2caSAndrew Geissler // of the DHCPEnabled property 799d5afb2caSAndrew Geissler std::string origin; 800d5afb2caSAndrew Geissler if (ipv4DHCPEnabled == false) 801d5afb2caSAndrew Geissler { 802d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 803d5afb2caSAndrew Geissler } 804d5afb2caSAndrew Geissler else 805d5afb2caSAndrew Geissler { 806d5afb2caSAndrew Geissler // DHCPEnabled is set to true. Delete the current IPv4 settings 807d5afb2caSAndrew Geissler // to receive the new values from DHCP server. 808d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 809d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 810d5afb2caSAndrew Geissler } 811d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 812d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 813d5afb2caSAndrew Geissler if (ec) 814d5afb2caSAndrew Geissler { 815d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 816d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 817d5afb2caSAndrew Geissler return; 818d5afb2caSAndrew Geissler } 819d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress Origin is Set"; 820d5afb2caSAndrew Geissler }, 821d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 822d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 823d5afb2caSAndrew Geissler "/ipv4/addr0", 824d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 825d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Origin", 826d5afb2caSAndrew Geissler std::variant<std::string>(origin)); 827d5afb2caSAndrew Geissler } 828d5afb2caSAndrew Geissler 829d5afb2caSAndrew Geissler /** 830d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 831d5afb2caSAndrew Geissler */ 832d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 833d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 834d5afb2caSAndrew Geissler { 835d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 836d5afb2caSAndrew Geissler if (params.size() != 1) 837d5afb2caSAndrew Geissler { 838d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 839d5afb2caSAndrew Geissler return; 840d5afb2caSAndrew Geissler } 841d5afb2caSAndrew Geissler 842d5afb2caSAndrew Geissler getHypervisorIfaceData( 843d5afb2caSAndrew Geissler params[0], 844d5afb2caSAndrew Geissler [this, asyncResp, ifaceId{std::string(params[0])}]( 845d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 846d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) { 847d5afb2caSAndrew Geissler if (!success) 848d5afb2caSAndrew Geissler { 849d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 850d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 851d5afb2caSAndrew Geissler return; 852d5afb2caSAndrew Geissler } 853d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 854d5afb2caSAndrew Geissler "#EthernetInterface.v1_5_1.EthernetInterface"; 855d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = 856d5afb2caSAndrew Geissler "Hypervisor Ethernet Interface"; 857d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 858d5afb2caSAndrew Geissler "Hypervisor's Virtual Management Ethernet Interface"; 859d5afb2caSAndrew Geissler parseInterfaceData(asyncResp->res.jsonValue, ifaceId, ethData, 860d5afb2caSAndrew Geissler ipv4Data); 861d5afb2caSAndrew Geissler }); 862d5afb2caSAndrew Geissler } 863d5afb2caSAndrew Geissler 864d5afb2caSAndrew Geissler void doPatch(crow::Response& res, const crow::Request& req, 865d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 866d5afb2caSAndrew Geissler { 867d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 868d5afb2caSAndrew Geissler if (params.size() != 1) 869d5afb2caSAndrew Geissler { 870d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 871d5afb2caSAndrew Geissler return; 872d5afb2caSAndrew Geissler } 873d5afb2caSAndrew Geissler 874d5afb2caSAndrew Geissler const std::string& ifaceId = params[0]; 875d5afb2caSAndrew Geissler std::optional<std::string> hostName; 876d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4StaticAddresses; 877d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4Addresses; 878d5afb2caSAndrew Geissler std::optional<nlohmann::json> dhcpv4; 879d5afb2caSAndrew Geissler std::optional<bool> ipv4DHCPEnabled; 880d5afb2caSAndrew Geissler 881d5afb2caSAndrew Geissler if (!json_util::readJson(req, res, "HostName", hostName, 882d5afb2caSAndrew Geissler "IPv4StaticAddresses", ipv4StaticAddresses, 883d5afb2caSAndrew Geissler "IPv4Addresses", ipv4Addresses, "DHCPv4", 884d5afb2caSAndrew Geissler dhcpv4)) 885d5afb2caSAndrew Geissler { 886d5afb2caSAndrew Geissler return; 887d5afb2caSAndrew Geissler } 888d5afb2caSAndrew Geissler 889d5afb2caSAndrew Geissler if (ipv4Addresses) 890d5afb2caSAndrew Geissler { 891d5afb2caSAndrew Geissler messages::propertyNotWritable(asyncResp->res, "IPv4Addresses"); 892d5afb2caSAndrew Geissler } 893d5afb2caSAndrew Geissler 894d5afb2caSAndrew Geissler if (dhcpv4) 895d5afb2caSAndrew Geissler { 896d5afb2caSAndrew Geissler if (!json_util::readJson(*dhcpv4, res, "DHCPEnabled", 897d5afb2caSAndrew Geissler ipv4DHCPEnabled)) 898d5afb2caSAndrew Geissler { 899d5afb2caSAndrew Geissler return; 900d5afb2caSAndrew Geissler } 901d5afb2caSAndrew Geissler } 902d5afb2caSAndrew Geissler 903d5afb2caSAndrew Geissler getHypervisorIfaceData( 904d5afb2caSAndrew Geissler ifaceId, 905d5afb2caSAndrew Geissler [this, asyncResp, ifaceId, hostName = std::move(hostName), 906d5afb2caSAndrew Geissler ipv4StaticAddresses = std::move(ipv4StaticAddresses), 907d5afb2caSAndrew Geissler ipv4DHCPEnabled, dhcpv4 = std::move(dhcpv4)]( 908d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 909d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>&) { 910d5afb2caSAndrew Geissler if (!success) 911d5afb2caSAndrew Geissler { 912d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 913d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 914d5afb2caSAndrew Geissler return; 915d5afb2caSAndrew Geissler } 916d5afb2caSAndrew Geissler 917d5afb2caSAndrew Geissler if (ipv4StaticAddresses) 918d5afb2caSAndrew Geissler { 919d5afb2caSAndrew Geissler const nlohmann::json& ipv4Static = *ipv4StaticAddresses; 920d5afb2caSAndrew Geissler const nlohmann::json& ipv4Json = ipv4Static[0]; 921d5afb2caSAndrew Geissler // Check if the param is 'null'. If its null, it means that 922d5afb2caSAndrew Geissler // user wants to delete the IP address. Deleting the IP 923d5afb2caSAndrew Geissler // address is allowed only if its statically configured. 924d5afb2caSAndrew Geissler // Deleting the address originated from DHCP is not allowed. 925d5afb2caSAndrew Geissler if ((ipv4Json.is_null()) && 926d5afb2caSAndrew Geissler (translateDHCPEnabledToBool(ethData.DHCPEnabled, true))) 927d5afb2caSAndrew Geissler { 928d5afb2caSAndrew Geissler BMCWEB_LOG_INFO 929d5afb2caSAndrew Geissler << "Ignoring the delete on ipv4StaticAddresses " 930d5afb2caSAndrew Geissler "as the interface is DHCP enabled"; 931d5afb2caSAndrew Geissler } 932d5afb2caSAndrew Geissler else 933d5afb2caSAndrew Geissler { 934d5afb2caSAndrew Geissler handleHypervisorIPv4StaticPatch(ifaceId, ipv4Static, 935d5afb2caSAndrew Geissler asyncResp); 936d5afb2caSAndrew Geissler } 937d5afb2caSAndrew Geissler } 938d5afb2caSAndrew Geissler 939d5afb2caSAndrew Geissler if (hostName) 940d5afb2caSAndrew Geissler { 941d5afb2caSAndrew Geissler handleHostnamePatch(*hostName, asyncResp); 942d5afb2caSAndrew Geissler } 943d5afb2caSAndrew Geissler 944d5afb2caSAndrew Geissler if (dhcpv4) 945d5afb2caSAndrew Geissler { 946d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, *ipv4DHCPEnabled, asyncResp); 947d5afb2caSAndrew Geissler } 948d5afb2caSAndrew Geissler 949d5afb2caSAndrew Geissler // Set this interface to disabled/inactive. This will be set to 950d5afb2caSAndrew Geissler // enabled/active by the pldm once the hypervisor consumes the 951d5afb2caSAndrew Geissler // updated settings from the user. 952d5afb2caSAndrew Geissler setIPv4InterfaceEnabled(ifaceId, false, asyncResp); 953d5afb2caSAndrew Geissler }); 954d5afb2caSAndrew Geissler res.result(boost::beast::http::status::accepted); 955d5afb2caSAndrew Geissler } 956d5afb2caSAndrew Geissler }; 957d5afb2caSAndrew Geissler } // namespace redfish 958