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