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