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 { 126*2dfd18efSEd Tanous sdbusplus::message::object_path path(iface); 127*2dfd18efSEd Tanous std::string name = path.filename(); 128*2dfd18efSEd Tanous if (name.empty()) 129d5afb2caSAndrew Geissler { 130*2dfd18efSEd Tanous continue; 131*2dfd18efSEd Tanous } 132*2dfd18efSEd Tanous 133d5afb2caSAndrew Geissler ifaceArray.push_back( 134d5afb2caSAndrew Geissler {{"@odata.id", "/redfish/v1/Systems/hypervisor/" 135d5afb2caSAndrew Geissler "EthernetInterfaces/" + 136*2dfd18efSEd 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 { 556d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, 557d5afb2caSAndrew Geissler thisJson.dump(), pathString); 558d5afb2caSAndrew Geissler return; 559d5afb2caSAndrew Geissler } 560d5afb2caSAndrew Geissler 561d5afb2caSAndrew Geissler uint8_t prefixLength = 0; 562d5afb2caSAndrew Geissler bool errorInEntry = false; 563d5afb2caSAndrew Geissler if (address) 564d5afb2caSAndrew Geissler { 565d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*address)) 566d5afb2caSAndrew Geissler { 567d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *address, 568d5afb2caSAndrew Geissler pathString + "/Address"); 569d5afb2caSAndrew Geissler errorInEntry = true; 570d5afb2caSAndrew Geissler } 571d5afb2caSAndrew Geissler } 572d5afb2caSAndrew Geissler else 573d5afb2caSAndrew Geissler { 574d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 575d5afb2caSAndrew Geissler pathString + "/Address"); 576d5afb2caSAndrew Geissler errorInEntry = true; 577d5afb2caSAndrew Geissler } 578d5afb2caSAndrew Geissler 579d5afb2caSAndrew Geissler if (subnetMask) 580d5afb2caSAndrew Geissler { 581d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 582d5afb2caSAndrew Geissler { 583d5afb2caSAndrew Geissler messages::propertyValueFormatError( 584d5afb2caSAndrew Geissler asyncResp->res, *subnetMask, 585d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 586d5afb2caSAndrew Geissler errorInEntry = true; 587d5afb2caSAndrew Geissler } 588d5afb2caSAndrew Geissler } 589d5afb2caSAndrew Geissler else 590d5afb2caSAndrew Geissler { 591d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 592d5afb2caSAndrew Geissler pathString + "/SubnetMask"); 593d5afb2caSAndrew Geissler errorInEntry = true; 594d5afb2caSAndrew Geissler } 595d5afb2caSAndrew Geissler 596d5afb2caSAndrew Geissler if (gateway) 597d5afb2caSAndrew Geissler { 598d5afb2caSAndrew Geissler if (!ipv4VerifyIpAndGetBitcount(*gateway)) 599d5afb2caSAndrew Geissler { 600d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, *gateway, 601d5afb2caSAndrew Geissler pathString + "/Gateway"); 602d5afb2caSAndrew Geissler errorInEntry = true; 603d5afb2caSAndrew Geissler } 604d5afb2caSAndrew Geissler } 605d5afb2caSAndrew Geissler else 606d5afb2caSAndrew Geissler { 607d5afb2caSAndrew Geissler messages::propertyMissing(asyncResp->res, 608d5afb2caSAndrew Geissler pathString + "/Gateway"); 609d5afb2caSAndrew Geissler errorInEntry = true; 610d5afb2caSAndrew Geissler } 611d5afb2caSAndrew Geissler 612d5afb2caSAndrew Geissler if (errorInEntry) 613d5afb2caSAndrew Geissler { 614d5afb2caSAndrew Geissler return; 615d5afb2caSAndrew Geissler } 616d5afb2caSAndrew Geissler 617d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Calling createHypervisorIPv4 on : " << ifaceId 618d5afb2caSAndrew Geissler << "," << *address; 619d5afb2caSAndrew Geissler createHypervisorIPv4(ifaceId, prefixLength, *gateway, *address, 620d5afb2caSAndrew Geissler asyncResp); 621d5afb2caSAndrew Geissler // Set the DHCPEnabled to false since the Static IPv4 is set 622d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, false, asyncResp); 623d5afb2caSAndrew Geissler } 624d5afb2caSAndrew Geissler else 625d5afb2caSAndrew Geissler { 626d5afb2caSAndrew Geissler if (thisJson.is_null()) 627d5afb2caSAndrew Geissler { 628d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 629d5afb2caSAndrew Geissler } 630d5afb2caSAndrew Geissler } 631d5afb2caSAndrew Geissler } 632d5afb2caSAndrew Geissler 633d5afb2caSAndrew Geissler bool isHostnameValid(const std::string& hostName) 634d5afb2caSAndrew Geissler { 635d5afb2caSAndrew Geissler // As per RFC 1123 636d5afb2caSAndrew Geissler // Allow up to 255 characters 637d5afb2caSAndrew Geissler if (hostName.length() > 255) 638d5afb2caSAndrew Geissler { 639d5afb2caSAndrew Geissler return false; 640d5afb2caSAndrew Geissler } 641d5afb2caSAndrew Geissler // Validate the regex 642d5afb2caSAndrew Geissler const std::regex pattern( 643d5afb2caSAndrew Geissler "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); 644d5afb2caSAndrew Geissler 645d5afb2caSAndrew Geissler return std::regex_match(hostName, pattern); 646d5afb2caSAndrew Geissler } 647d5afb2caSAndrew Geissler 648d5afb2caSAndrew Geissler void handleHostnamePatch(const std::string& hostName, 649d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 650d5afb2caSAndrew Geissler { 651d5afb2caSAndrew Geissler if (!isHostnameValid(hostName)) 652d5afb2caSAndrew Geissler { 653d5afb2caSAndrew Geissler messages::propertyValueFormatError(asyncResp->res, hostName, 654d5afb2caSAndrew Geissler "HostName"); 655d5afb2caSAndrew Geissler return; 656d5afb2caSAndrew Geissler } 657d5afb2caSAndrew Geissler 658d5afb2caSAndrew Geissler asyncResp->res.jsonValue["HostName"] = hostName; 659d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 660d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 661d5afb2caSAndrew Geissler if (ec) 662d5afb2caSAndrew Geissler { 663d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 664d5afb2caSAndrew Geissler } 665d5afb2caSAndrew Geissler }, 666d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 667d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor", 668d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 669d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 670d5afb2caSAndrew Geissler std::variant<std::string>(hostName)); 671d5afb2caSAndrew Geissler } 672d5afb2caSAndrew Geissler 673d5afb2caSAndrew Geissler void setIPv4InterfaceEnabled(const std::string& ifaceId, 674d5afb2caSAndrew Geissler const bool& isActive, 675d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 676d5afb2caSAndrew Geissler { 677d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 678d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 679d5afb2caSAndrew Geissler if (ec) 680d5afb2caSAndrew Geissler { 681d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 682d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 683d5afb2caSAndrew Geissler return; 684d5afb2caSAndrew Geissler } 685d5afb2caSAndrew Geissler }, 686d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 687d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 688d5afb2caSAndrew Geissler "/ipv4/addr0", 689d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 690d5afb2caSAndrew Geissler "xyz.openbmc_project.Object.Enable", "Enabled", 691d5afb2caSAndrew Geissler std::variant<bool>(isActive)); 692d5afb2caSAndrew Geissler } 693d5afb2caSAndrew Geissler 694d5afb2caSAndrew Geissler void setDHCPEnabled(const std::string& ifaceId, const bool& ipv4DHCPEnabled, 695d5afb2caSAndrew Geissler const std::shared_ptr<AsyncResp>& asyncResp) 696d5afb2caSAndrew Geissler { 697d5afb2caSAndrew Geissler const std::string dhcp = 698d5afb2caSAndrew Geissler getDhcpEnabledEnumeration(ipv4DHCPEnabled, false); 699d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 700d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 701d5afb2caSAndrew Geissler if (ec) 702d5afb2caSAndrew Geissler { 703d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 704d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 705d5afb2caSAndrew Geissler return; 706d5afb2caSAndrew Geissler } 707d5afb2caSAndrew Geissler }, 708d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 709d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId, 710d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 711d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.EthernetInterface", "DHCPEnabled", 712d5afb2caSAndrew Geissler std::variant<std::string>{dhcp}); 713d5afb2caSAndrew Geissler 714d5afb2caSAndrew Geissler // Set the IPv4 address origin to the DHCP / Static as per the new value 715d5afb2caSAndrew Geissler // of the DHCPEnabled property 716d5afb2caSAndrew Geissler std::string origin; 717d5afb2caSAndrew Geissler if (ipv4DHCPEnabled == false) 718d5afb2caSAndrew Geissler { 719d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 720d5afb2caSAndrew Geissler } 721d5afb2caSAndrew Geissler else 722d5afb2caSAndrew Geissler { 723d5afb2caSAndrew Geissler // DHCPEnabled is set to true. Delete the current IPv4 settings 724d5afb2caSAndrew Geissler // to receive the new values from DHCP server. 725d5afb2caSAndrew Geissler deleteHypervisorIPv4(ifaceId, asyncResp); 726d5afb2caSAndrew Geissler origin = "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 727d5afb2caSAndrew Geissler } 728d5afb2caSAndrew Geissler crow::connections::systemBus->async_method_call( 729d5afb2caSAndrew Geissler [asyncResp](const boost::system::error_code ec) { 730d5afb2caSAndrew Geissler if (ec) 731d5afb2caSAndrew Geissler { 732d5afb2caSAndrew Geissler BMCWEB_LOG_ERROR << "DBUS response error " << ec; 733d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 734d5afb2caSAndrew Geissler return; 735d5afb2caSAndrew Geissler } 736d5afb2caSAndrew Geissler BMCWEB_LOG_DEBUG << "Hypervisor IPaddress Origin is Set"; 737d5afb2caSAndrew Geissler }, 738d5afb2caSAndrew Geissler "xyz.openbmc_project.Settings", 739d5afb2caSAndrew Geissler "/xyz/openbmc_project/network/hypervisor/" + ifaceId + 740d5afb2caSAndrew Geissler "/ipv4/addr0", 741d5afb2caSAndrew Geissler "org.freedesktop.DBus.Properties", "Set", 742d5afb2caSAndrew Geissler "xyz.openbmc_project.Network.IP", "Origin", 743d5afb2caSAndrew Geissler std::variant<std::string>(origin)); 744d5afb2caSAndrew Geissler } 745d5afb2caSAndrew Geissler 746d5afb2caSAndrew Geissler /** 747d5afb2caSAndrew Geissler * Functions triggers appropriate requests on DBus 748d5afb2caSAndrew Geissler */ 749d5afb2caSAndrew Geissler void doGet(crow::Response& res, const crow::Request&, 750d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 751d5afb2caSAndrew Geissler { 752d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 753d5afb2caSAndrew Geissler if (params.size() != 1) 754d5afb2caSAndrew Geissler { 755d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 756d5afb2caSAndrew Geissler return; 757d5afb2caSAndrew Geissler } 758d5afb2caSAndrew Geissler 759d5afb2caSAndrew Geissler getHypervisorIfaceData( 760d5afb2caSAndrew Geissler params[0], 761d5afb2caSAndrew Geissler [this, asyncResp, ifaceId{std::string(params[0])}]( 762d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 763d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>& ipv4Data) { 764d5afb2caSAndrew Geissler if (!success) 765d5afb2caSAndrew Geissler { 766d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 767d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 768d5afb2caSAndrew Geissler return; 769d5afb2caSAndrew Geissler } 770d5afb2caSAndrew Geissler asyncResp->res.jsonValue["@odata.type"] = 771d5afb2caSAndrew Geissler "#EthernetInterface.v1_5_1.EthernetInterface"; 772d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Name"] = 773d5afb2caSAndrew Geissler "Hypervisor Ethernet Interface"; 774d5afb2caSAndrew Geissler asyncResp->res.jsonValue["Description"] = 775d5afb2caSAndrew Geissler "Hypervisor's Virtual Management Ethernet Interface"; 776d5afb2caSAndrew Geissler parseInterfaceData(asyncResp->res.jsonValue, ifaceId, ethData, 777d5afb2caSAndrew Geissler ipv4Data); 778d5afb2caSAndrew Geissler }); 779d5afb2caSAndrew Geissler } 780d5afb2caSAndrew Geissler 781d5afb2caSAndrew Geissler void doPatch(crow::Response& res, const crow::Request& req, 782d5afb2caSAndrew Geissler const std::vector<std::string>& params) override 783d5afb2caSAndrew Geissler { 784d5afb2caSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 785d5afb2caSAndrew Geissler if (params.size() != 1) 786d5afb2caSAndrew Geissler { 787d5afb2caSAndrew Geissler messages::internalError(asyncResp->res); 788d5afb2caSAndrew Geissler return; 789d5afb2caSAndrew Geissler } 790d5afb2caSAndrew Geissler 791d5afb2caSAndrew Geissler const std::string& ifaceId = params[0]; 792d5afb2caSAndrew Geissler std::optional<std::string> hostName; 793d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4StaticAddresses; 794d5afb2caSAndrew Geissler std::optional<nlohmann::json> ipv4Addresses; 795d5afb2caSAndrew Geissler std::optional<nlohmann::json> dhcpv4; 796d5afb2caSAndrew Geissler std::optional<bool> ipv4DHCPEnabled; 797d5afb2caSAndrew Geissler 798d5afb2caSAndrew Geissler if (!json_util::readJson(req, res, "HostName", hostName, 799d5afb2caSAndrew Geissler "IPv4StaticAddresses", ipv4StaticAddresses, 800d5afb2caSAndrew Geissler "IPv4Addresses", ipv4Addresses, "DHCPv4", 801d5afb2caSAndrew Geissler dhcpv4)) 802d5afb2caSAndrew Geissler { 803d5afb2caSAndrew Geissler return; 804d5afb2caSAndrew Geissler } 805d5afb2caSAndrew Geissler 806d5afb2caSAndrew Geissler if (ipv4Addresses) 807d5afb2caSAndrew Geissler { 808d5afb2caSAndrew Geissler messages::propertyNotWritable(asyncResp->res, "IPv4Addresses"); 809d5afb2caSAndrew Geissler } 810d5afb2caSAndrew Geissler 811d5afb2caSAndrew Geissler if (dhcpv4) 812d5afb2caSAndrew Geissler { 813d5afb2caSAndrew Geissler if (!json_util::readJson(*dhcpv4, res, "DHCPEnabled", 814d5afb2caSAndrew Geissler ipv4DHCPEnabled)) 815d5afb2caSAndrew Geissler { 816d5afb2caSAndrew Geissler return; 817d5afb2caSAndrew Geissler } 818d5afb2caSAndrew Geissler } 819d5afb2caSAndrew Geissler 820d5afb2caSAndrew Geissler getHypervisorIfaceData( 821d5afb2caSAndrew Geissler ifaceId, 822d5afb2caSAndrew Geissler [this, asyncResp, ifaceId, hostName = std::move(hostName), 823d5afb2caSAndrew Geissler ipv4StaticAddresses = std::move(ipv4StaticAddresses), 824d5afb2caSAndrew Geissler ipv4DHCPEnabled, dhcpv4 = std::move(dhcpv4)]( 825d5afb2caSAndrew Geissler const bool& success, const EthernetInterfaceData& ethData, 826d5afb2caSAndrew Geissler const boost::container::flat_set<IPv4AddressData>&) { 827d5afb2caSAndrew Geissler if (!success) 828d5afb2caSAndrew Geissler { 829d5afb2caSAndrew Geissler messages::resourceNotFound(asyncResp->res, 830d5afb2caSAndrew Geissler "EthernetInterface", ifaceId); 831d5afb2caSAndrew Geissler return; 832d5afb2caSAndrew Geissler } 833d5afb2caSAndrew Geissler 834d5afb2caSAndrew Geissler if (ipv4StaticAddresses) 835d5afb2caSAndrew Geissler { 836d5afb2caSAndrew Geissler const nlohmann::json& ipv4Static = *ipv4StaticAddresses; 837d5afb2caSAndrew Geissler const nlohmann::json& ipv4Json = ipv4Static[0]; 838d5afb2caSAndrew Geissler // Check if the param is 'null'. If its null, it means that 839d5afb2caSAndrew Geissler // user wants to delete the IP address. Deleting the IP 840d5afb2caSAndrew Geissler // address is allowed only if its statically configured. 841d5afb2caSAndrew Geissler // Deleting the address originated from DHCP is not allowed. 842d5afb2caSAndrew Geissler if ((ipv4Json.is_null()) && 843d5afb2caSAndrew Geissler (translateDHCPEnabledToBool(ethData.DHCPEnabled, true))) 844d5afb2caSAndrew Geissler { 845d5afb2caSAndrew Geissler BMCWEB_LOG_INFO 846d5afb2caSAndrew Geissler << "Ignoring the delete on ipv4StaticAddresses " 847d5afb2caSAndrew Geissler "as the interface is DHCP enabled"; 848d5afb2caSAndrew Geissler } 849d5afb2caSAndrew Geissler else 850d5afb2caSAndrew Geissler { 851d5afb2caSAndrew Geissler handleHypervisorIPv4StaticPatch(ifaceId, ipv4Static, 852d5afb2caSAndrew Geissler asyncResp); 853d5afb2caSAndrew Geissler } 854d5afb2caSAndrew Geissler } 855d5afb2caSAndrew Geissler 856d5afb2caSAndrew Geissler if (hostName) 857d5afb2caSAndrew Geissler { 858d5afb2caSAndrew Geissler handleHostnamePatch(*hostName, asyncResp); 859d5afb2caSAndrew Geissler } 860d5afb2caSAndrew Geissler 861d5afb2caSAndrew Geissler if (dhcpv4) 862d5afb2caSAndrew Geissler { 863d5afb2caSAndrew Geissler setDHCPEnabled(ifaceId, *ipv4DHCPEnabled, asyncResp); 864d5afb2caSAndrew Geissler } 865d5afb2caSAndrew Geissler 866d5afb2caSAndrew Geissler // Set this interface to disabled/inactive. This will be set to 867d5afb2caSAndrew Geissler // enabled/active by the pldm once the hypervisor consumes the 868d5afb2caSAndrew Geissler // updated settings from the user. 869d5afb2caSAndrew Geissler setIPv4InterfaceEnabled(ifaceId, false, asyncResp); 870d5afb2caSAndrew Geissler }); 871d5afb2caSAndrew Geissler res.result(boost::beast::http::status::accepted); 872d5afb2caSAndrew Geissler } 873d5afb2caSAndrew Geissler }; 874d5afb2caSAndrew Geissler } // namespace redfish 875