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