xref: /openbmc/bmcweb/features/redfish/lib/hypervisor_system.hpp (revision d5afb2caeb6e797f0f0920eaf857a6d63f194cbe)
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