xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 4a0cb85c101c3179251e5819052bab429d226640)
19391bb9cSRapkiewicz, Pawel /*
29391bb9cSRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation
39391bb9cSRapkiewicz, Pawel //
49391bb9cSRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License");
59391bb9cSRapkiewicz, Pawel // you may not use this file except in compliance with the License.
69391bb9cSRapkiewicz, Pawel // You may obtain a copy of the License at
79391bb9cSRapkiewicz, Pawel //
89391bb9cSRapkiewicz, Pawel //      http://www.apache.org/licenses/LICENSE-2.0
99391bb9cSRapkiewicz, Pawel //
109391bb9cSRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software
119391bb9cSRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS,
129391bb9cSRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139391bb9cSRapkiewicz, Pawel // See the License for the specific language governing permissions and
149391bb9cSRapkiewicz, Pawel // limitations under the License.
159391bb9cSRapkiewicz, Pawel */
169391bb9cSRapkiewicz, Pawel #pragma once
179391bb9cSRapkiewicz, Pawel 
181abe55efSEd Tanous #include <boost/container/flat_map.hpp>
19*4a0cb85cSEd Tanous #include <boost/container/flat_set.hpp>
20*4a0cb85cSEd Tanous #include <boost/optional.hpp>
21179db1d7SKowalski, Kamil #include <dbus_singleton.hpp>
22588c3f0dSKowalski, Kamil #include <error_messages.hpp>
23179db1d7SKowalski, Kamil #include <node.hpp>
24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp>
259391bb9cSRapkiewicz, Pawel 
261abe55efSEd Tanous namespace redfish
271abe55efSEd Tanous {
289391bb9cSRapkiewicz, Pawel 
299391bb9cSRapkiewicz, Pawel /**
309391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
319391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
329391bb9cSRapkiewicz, Pawel  */
33aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
34aa2e59c1SEd Tanous     std::string,
35aa2e59c1SEd Tanous     sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36aa2e59c1SEd Tanous                                 int32_t, uint32_t, int64_t, uint64_t, double>>;
379391bb9cSRapkiewicz, Pawel 
38*4a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair<
39aa2e59c1SEd Tanous     sdbusplus::message::object_path,
40*4a0cb85cSEd Tanous     std::vector<std::pair<
41aa2e59c1SEd Tanous         std::string,
42aa2e59c1SEd Tanous         boost::container::flat_map<
43aa2e59c1SEd Tanous             std::string, sdbusplus::message::variant<
44aa2e59c1SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
45*4a0cb85cSEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double>>>>>>;
46*4a0cb85cSEd Tanous 
47*4a0cb85cSEd Tanous enum class LinkType
48*4a0cb85cSEd Tanous {
49*4a0cb85cSEd Tanous     Local,
50*4a0cb85cSEd Tanous     Global
51*4a0cb85cSEd Tanous };
529391bb9cSRapkiewicz, Pawel 
539391bb9cSRapkiewicz, Pawel /**
549391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
559391bb9cSRapkiewicz, Pawel  */
561abe55efSEd Tanous struct IPv4AddressData
571abe55efSEd Tanous {
58179db1d7SKowalski, Kamil     std::string id;
59*4a0cb85cSEd Tanous     std::string address;
60*4a0cb85cSEd Tanous     std::string domain;
61*4a0cb85cSEd Tanous     std::string gateway;
629391bb9cSRapkiewicz, Pawel     std::string netmask;
639391bb9cSRapkiewicz, Pawel     std::string origin;
64*4a0cb85cSEd Tanous     LinkType linktype;
65*4a0cb85cSEd Tanous 
661abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
671abe55efSEd Tanous     {
68*4a0cb85cSEd Tanous         return id < obj.id;
691abe55efSEd Tanous     }
709391bb9cSRapkiewicz, Pawel };
719391bb9cSRapkiewicz, Pawel 
729391bb9cSRapkiewicz, Pawel /**
739391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
749391bb9cSRapkiewicz, Pawel  * available from DBus
759391bb9cSRapkiewicz, Pawel  */
761abe55efSEd Tanous struct EthernetInterfaceData
771abe55efSEd Tanous {
78*4a0cb85cSEd Tanous     uint32_t speed;
79*4a0cb85cSEd Tanous     bool auto_neg;
80*4a0cb85cSEd Tanous     std::string hostname;
81*4a0cb85cSEd Tanous     std::string default_gateway;
82*4a0cb85cSEd Tanous     std::string mac_address;
83*4a0cb85cSEd Tanous     boost::optional<uint32_t> vlan_id;
849391bb9cSRapkiewicz, Pawel };
859391bb9cSRapkiewicz, Pawel 
869391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
879391bb9cSRapkiewicz, Pawel // into full dot notation
881abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
891abe55efSEd Tanous {
909391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
919391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
929391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
939391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
949391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
959391bb9cSRapkiewicz, Pawel     return netmask;
969391bb9cSRapkiewicz, Pawel }
979391bb9cSRapkiewicz, Pawel 
98*4a0cb85cSEd Tanous inline std::string
99*4a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
100*4a0cb85cSEd Tanous                                         bool isIPv4)
1011abe55efSEd Tanous {
102*4a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1031abe55efSEd Tanous     {
104*4a0cb85cSEd Tanous         return "Static";
1059391bb9cSRapkiewicz, Pawel     }
106*4a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1071abe55efSEd Tanous     {
108*4a0cb85cSEd Tanous         if (isIPv4)
1091abe55efSEd Tanous         {
110*4a0cb85cSEd Tanous             return "IPv4LinkLocal";
1111abe55efSEd Tanous         }
1121abe55efSEd Tanous         else
1131abe55efSEd Tanous         {
114*4a0cb85cSEd Tanous             return "LinkLocal";
1159391bb9cSRapkiewicz, Pawel         }
1169391bb9cSRapkiewicz, Pawel     }
117*4a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1181abe55efSEd Tanous     {
119*4a0cb85cSEd Tanous         if (isIPv4)
120*4a0cb85cSEd Tanous         {
121*4a0cb85cSEd Tanous             return "DHCP";
122*4a0cb85cSEd Tanous         }
123*4a0cb85cSEd Tanous         else
124*4a0cb85cSEd Tanous         {
125*4a0cb85cSEd Tanous             return "DHCPv6";
126*4a0cb85cSEd Tanous         }
127*4a0cb85cSEd Tanous     }
128*4a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
129*4a0cb85cSEd Tanous     {
130*4a0cb85cSEd Tanous         return "SLAAC";
131*4a0cb85cSEd Tanous     }
132*4a0cb85cSEd Tanous     return "";
133*4a0cb85cSEd Tanous }
134*4a0cb85cSEd Tanous 
135*4a0cb85cSEd Tanous inline std::string
136*4a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
137*4a0cb85cSEd Tanous {
138*4a0cb85cSEd Tanous     if (inputOrigin == "Static")
139*4a0cb85cSEd Tanous     {
140*4a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
141*4a0cb85cSEd Tanous     }
142*4a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
143*4a0cb85cSEd Tanous     {
144*4a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
145*4a0cb85cSEd Tanous     }
146*4a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
147*4a0cb85cSEd Tanous     {
148*4a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
149*4a0cb85cSEd Tanous     }
150*4a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
151*4a0cb85cSEd Tanous     {
152*4a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
153*4a0cb85cSEd Tanous     }
154*4a0cb85cSEd Tanous     return "";
155*4a0cb85cSEd Tanous }
156*4a0cb85cSEd Tanous 
157*4a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
158*4a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
159*4a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
160*4a0cb85cSEd Tanous {
161*4a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
162*4a0cb85cSEd Tanous     {
163*4a0cb85cSEd Tanous         if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
164*4a0cb85cSEd Tanous         {
165*4a0cb85cSEd Tanous             for (const auto &ifacePair : objpath.second)
166*4a0cb85cSEd Tanous             {
167*4a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
168*4a0cb85cSEd Tanous                 {
169*4a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
170*4a0cb85cSEd Tanous                     {
171*4a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
172*4a0cb85cSEd Tanous                         {
173*4a0cb85cSEd Tanous                             const std::string *mac =
174*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
175*4a0cb85cSEd Tanous                                     propertyPair.second);
176*4a0cb85cSEd Tanous                             if (mac != nullptr)
177*4a0cb85cSEd Tanous                             {
178*4a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
179*4a0cb85cSEd Tanous                             }
180*4a0cb85cSEd Tanous                         }
181*4a0cb85cSEd Tanous                     }
182*4a0cb85cSEd Tanous                 }
183*4a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
184*4a0cb85cSEd Tanous                 {
185*4a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
186*4a0cb85cSEd Tanous                     {
187*4a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
188*4a0cb85cSEd Tanous                         {
189*4a0cb85cSEd Tanous                             const uint32_t *id = mapbox::getPtr<const uint32_t>(
190*4a0cb85cSEd Tanous                                 propertyPair.second);
191*4a0cb85cSEd Tanous                             if (id != nullptr)
192*4a0cb85cSEd Tanous                             {
193*4a0cb85cSEd Tanous                                 ethData.vlan_id = *id;
194*4a0cb85cSEd Tanous                             }
195*4a0cb85cSEd Tanous                         }
196*4a0cb85cSEd Tanous                     }
197*4a0cb85cSEd Tanous                 }
198*4a0cb85cSEd Tanous                 else if (ifacePair.first ==
199*4a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
200*4a0cb85cSEd Tanous                 {
201*4a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
202*4a0cb85cSEd Tanous                     {
203*4a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
204*4a0cb85cSEd Tanous                         {
205*4a0cb85cSEd Tanous                             const bool *auto_neg =
206*4a0cb85cSEd Tanous                                 mapbox::getPtr<const bool>(propertyPair.second);
207*4a0cb85cSEd Tanous                             if (auto_neg != nullptr)
208*4a0cb85cSEd Tanous                             {
209*4a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
210*4a0cb85cSEd Tanous                             }
211*4a0cb85cSEd Tanous                         }
212*4a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
213*4a0cb85cSEd Tanous                         {
214*4a0cb85cSEd Tanous                             const uint32_t *speed =
215*4a0cb85cSEd Tanous                                 mapbox::getPtr<const uint32_t>(
216*4a0cb85cSEd Tanous                                     propertyPair.second);
217*4a0cb85cSEd Tanous                             if (speed != nullptr)
218*4a0cb85cSEd Tanous                             {
219*4a0cb85cSEd Tanous                                 ethData.speed = *speed;
220*4a0cb85cSEd Tanous                             }
221*4a0cb85cSEd Tanous                         }
222*4a0cb85cSEd Tanous                     }
223*4a0cb85cSEd Tanous                 }
224*4a0cb85cSEd Tanous                 else if (ifacePair.first ==
225*4a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.SystemConfiguration")
226*4a0cb85cSEd Tanous                 {
227*4a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
228*4a0cb85cSEd Tanous                     {
229*4a0cb85cSEd Tanous                         if (propertyPair.first == "HostName")
230*4a0cb85cSEd Tanous                         {
231*4a0cb85cSEd Tanous                             const std::string *hostname =
232*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
233*4a0cb85cSEd Tanous                                     propertyPair.second);
234*4a0cb85cSEd Tanous                             if (hostname != nullptr)
235*4a0cb85cSEd Tanous                             {
236*4a0cb85cSEd Tanous                                 ethData.hostname = *hostname;
237*4a0cb85cSEd Tanous                             }
238*4a0cb85cSEd Tanous                         }
239*4a0cb85cSEd Tanous                         else if (propertyPair.first == "DefaultGateway")
240*4a0cb85cSEd Tanous                         {
241*4a0cb85cSEd Tanous                             const std::string *defaultGateway =
242*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
243*4a0cb85cSEd Tanous                                     propertyPair.second);
244*4a0cb85cSEd Tanous                             if (defaultGateway != nullptr)
245*4a0cb85cSEd Tanous                             {
246*4a0cb85cSEd Tanous                                 ethData.default_gateway = *defaultGateway;
247*4a0cb85cSEd Tanous                             }
248*4a0cb85cSEd Tanous                         }
249*4a0cb85cSEd Tanous                     }
250*4a0cb85cSEd Tanous                 }
251*4a0cb85cSEd Tanous             }
252*4a0cb85cSEd Tanous         }
253*4a0cb85cSEd Tanous     }
254*4a0cb85cSEd Tanous }
255*4a0cb85cSEd Tanous 
256*4a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
257*4a0cb85cSEd Tanous inline void
258*4a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
259*4a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
260*4a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
261*4a0cb85cSEd Tanous {
262*4a0cb85cSEd Tanous     const std::string ipv4PathStart =
263*4a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
264*4a0cb85cSEd Tanous 
265*4a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
266*4a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
267*4a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
268*4a0cb85cSEd Tanous     {
269*4a0cb85cSEd Tanous         // Check if proper pattern for object path appears
270*4a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
271*4a0cb85cSEd Tanous         {
272*4a0cb85cSEd Tanous             for (auto &interface : objpath.second)
273*4a0cb85cSEd Tanous             {
274*4a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
275*4a0cb85cSEd Tanous                 {
276*4a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
277*4a0cb85cSEd Tanous                     // appropriate
278*4a0cb85cSEd Tanous                     std::pair<
279*4a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
280*4a0cb85cSEd Tanous                         bool>
281*4a0cb85cSEd Tanous                         it = ipv4_config.insert(
282*4a0cb85cSEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
283*4a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
284*4a0cb85cSEd Tanous                     for (auto &property : interface.second)
285*4a0cb85cSEd Tanous                     {
286*4a0cb85cSEd Tanous                         if (property.first == "Address")
287*4a0cb85cSEd Tanous                         {
288*4a0cb85cSEd Tanous                             const std::string *address =
289*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
290*4a0cb85cSEd Tanous                                     property.second);
291*4a0cb85cSEd Tanous                             if (address != nullptr)
292*4a0cb85cSEd Tanous                             {
293*4a0cb85cSEd Tanous                                 ipv4_address.address = *address;
294*4a0cb85cSEd Tanous                             }
295*4a0cb85cSEd Tanous                         }
296*4a0cb85cSEd Tanous                         else if (property.first == "Gateway")
297*4a0cb85cSEd Tanous                         {
298*4a0cb85cSEd Tanous                             const std::string *gateway =
299*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
300*4a0cb85cSEd Tanous                                     property.second);
301*4a0cb85cSEd Tanous                             if (gateway != nullptr)
302*4a0cb85cSEd Tanous                             {
303*4a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
304*4a0cb85cSEd Tanous                             }
305*4a0cb85cSEd Tanous                         }
306*4a0cb85cSEd Tanous                         else if (property.first == "Origin")
307*4a0cb85cSEd Tanous                         {
308*4a0cb85cSEd Tanous                             const std::string *origin =
309*4a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
310*4a0cb85cSEd Tanous                                     property.second);
311*4a0cb85cSEd Tanous                             if (origin != nullptr)
312*4a0cb85cSEd Tanous                             {
313*4a0cb85cSEd Tanous                                 ipv4_address.origin =
314*4a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
315*4a0cb85cSEd Tanous                                                                         true);
316*4a0cb85cSEd Tanous                             }
317*4a0cb85cSEd Tanous                         }
318*4a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
319*4a0cb85cSEd Tanous                         {
320*4a0cb85cSEd Tanous                             const uint8_t *mask =
321*4a0cb85cSEd Tanous                                 mapbox::getPtr<uint8_t>(property.second);
322*4a0cb85cSEd Tanous                             if (mask != nullptr)
323*4a0cb85cSEd Tanous                             {
324*4a0cb85cSEd Tanous                                 // convert it to the string
325*4a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
326*4a0cb85cSEd Tanous                             }
327*4a0cb85cSEd Tanous                         }
328*4a0cb85cSEd Tanous                         else
329*4a0cb85cSEd Tanous                         {
330*4a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
331*4a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
332*4a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
333*4a0cb85cSEd Tanous                         }
334*4a0cb85cSEd Tanous                     }
335*4a0cb85cSEd Tanous                     // Check if given address is local, or global
336*4a0cb85cSEd Tanous                     ipv4_address.linktype =
337*4a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
338*4a0cb85cSEd Tanous                             ? LinkType::Global
339*4a0cb85cSEd Tanous                             : LinkType::Local;
340*4a0cb85cSEd Tanous                 }
341*4a0cb85cSEd Tanous             }
342*4a0cb85cSEd Tanous         }
343*4a0cb85cSEd Tanous     }
344*4a0cb85cSEd Tanous }
345588c3f0dSKowalski, Kamil 
346588c3f0dSKowalski, Kamil /**
347588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
348588c3f0dSKowalski, Kamil  *
349588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
350588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
351588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
352588c3f0dSKowalski, Kamil  *
353588c3f0dSKowalski, Kamil  * @return None.
354588c3f0dSKowalski, Kamil  */
355588c3f0dSKowalski, Kamil template <typename CallbackFunc>
356*4a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3571abe55efSEd Tanous                   CallbackFunc &&callback)
3581abe55efSEd Tanous {
35955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
360588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
361588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
362588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
363588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
364588c3f0dSKowalski, Kamil         sdbusplus::message::variant<uint32_t>(inputVlanId));
365*4a0cb85cSEd Tanous }
366588c3f0dSKowalski, Kamil 
367588c3f0dSKowalski, Kamil /**
368179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
369179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
370179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
371179db1d7SKowalski, Kamil  *
372179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
373179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
374179db1d7SKowalski, Kamil  *
375179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
376179db1d7SKowalski, Kamil  */
377*4a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
3781abe55efSEd Tanous                                        uint8_t *bits = nullptr)
3791abe55efSEd Tanous {
380179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
381179db1d7SKowalski, Kamil 
382179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
383179db1d7SKowalski, Kamil 
384*4a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
3851abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
3861abe55efSEd Tanous     {
387179db1d7SKowalski, Kamil         return false;
388179db1d7SKowalski, Kamil     }
389179db1d7SKowalski, Kamil 
3901abe55efSEd Tanous     if (bits != nullptr)
3911abe55efSEd Tanous     {
392179db1d7SKowalski, Kamil         *bits = 0;
393179db1d7SKowalski, Kamil     }
394179db1d7SKowalski, Kamil 
395179db1d7SKowalski, Kamil     char *endPtr;
396179db1d7SKowalski, Kamil     long previousValue = 255;
397179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
3981abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
3991abe55efSEd Tanous     {
4001abe55efSEd Tanous         if (byte.empty())
4011abe55efSEd Tanous         {
4021db9ca37SKowalski, Kamil             return false;
4031db9ca37SKowalski, Kamil         }
4041db9ca37SKowalski, Kamil 
405179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4061db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
407179db1d7SKowalski, Kamil 
408*4a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
409*4a0cb85cSEd Tanous         // is not 100% number
4101abe55efSEd Tanous         if (*endPtr != '\0')
4111abe55efSEd Tanous         {
412179db1d7SKowalski, Kamil             return false;
413179db1d7SKowalski, Kamil         }
414179db1d7SKowalski, Kamil 
415179db1d7SKowalski, Kamil         // Value should be contained in byte
4161abe55efSEd Tanous         if (value < 0 || value > 255)
4171abe55efSEd Tanous         {
418179db1d7SKowalski, Kamil             return false;
419179db1d7SKowalski, Kamil         }
420179db1d7SKowalski, Kamil 
4211abe55efSEd Tanous         if (bits != nullptr)
4221abe55efSEd Tanous         {
423179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4241abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4251abe55efSEd Tanous             {
426179db1d7SKowalski, Kamil                 return false;
427179db1d7SKowalski, Kamil             }
428179db1d7SKowalski, Kamil 
429179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
430179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
431179db1d7SKowalski, Kamil 
432179db1d7SKowalski, Kamil             // Count bits
4331abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4341abe55efSEd Tanous             {
4351abe55efSEd Tanous                 if (value & (1 << bitIdx))
4361abe55efSEd Tanous                 {
4371abe55efSEd Tanous                     if (firstZeroInByteHit)
4381abe55efSEd Tanous                     {
439179db1d7SKowalski, Kamil                         // Continuity not preserved
440179db1d7SKowalski, Kamil                         return false;
4411abe55efSEd Tanous                     }
4421abe55efSEd Tanous                     else
4431abe55efSEd Tanous                     {
444179db1d7SKowalski, Kamil                         (*bits)++;
445179db1d7SKowalski, Kamil                     }
4461abe55efSEd Tanous                 }
4471abe55efSEd Tanous                 else
4481abe55efSEd Tanous                 {
449179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
450179db1d7SKowalski, Kamil                 }
451179db1d7SKowalski, Kamil             }
452179db1d7SKowalski, Kamil         }
453179db1d7SKowalski, Kamil 
454179db1d7SKowalski, Kamil         previousValue = value;
455179db1d7SKowalski, Kamil     }
456179db1d7SKowalski, Kamil 
457179db1d7SKowalski, Kamil     return true;
458179db1d7SKowalski, Kamil }
459179db1d7SKowalski, Kamil 
460179db1d7SKowalski, Kamil /**
461179db1d7SKowalski, Kamil  * @brief Changes IPv4 address type property (Address, Gateway)
462179db1d7SKowalski, Kamil  *
463179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be modified
464*4a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
465179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of modified IP
466179db1d7SKowalski, Kamil  * @param[in] name        Name of field in JSON representation
467179db1d7SKowalski, Kamil  * @param[in] newValue    New value that should be written
468179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
469179db1d7SKowalski, Kamil  *
470179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
471179db1d7SKowalski, Kamil  * otherwise
472179db1d7SKowalski, Kamil  */
473*4a0cb85cSEd Tanous inline void changeIPv4AddressProperty(
474*4a0cb85cSEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
475*4a0cb85cSEd Tanous     const std::string &name, const std::string &newValue,
476*4a0cb85cSEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
4771abe55efSEd Tanous {
478*4a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
479*4a0cb85cSEd Tanous                      newValue{std::move(newValue)}](
4801abe55efSEd Tanous                         const boost::system::error_code ec) {
4811abe55efSEd Tanous         if (ec)
4821abe55efSEd Tanous         {
483179db1d7SKowalski, Kamil             messages::addMessageToJson(
48455c7b7a2SEd Tanous                 asyncResp->res.jsonValue, messages::internalError(),
485179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name);
4861abe55efSEd Tanous         }
4871abe55efSEd Tanous         else
4881abe55efSEd Tanous         {
489*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
490179db1d7SKowalski, Kamil         }
491179db1d7SKowalski, Kamil     };
492179db1d7SKowalski, Kamil 
49355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
494179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
495179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
496179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
497179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", name,
498179db1d7SKowalski, Kamil         sdbusplus::message::variant<std::string>(newValue));
499*4a0cb85cSEd Tanous }
500179db1d7SKowalski, Kamil 
501179db1d7SKowalski, Kamil /**
502179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
503179db1d7SKowalski, Kamil  *
504179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
505*4a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5061abe55efSEd Tanous  * modified
507179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
508179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
509179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
510179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
511179db1d7SKowalski, Kamil  *
512179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
513179db1d7SKowalski, Kamil  * otherwise
514179db1d7SKowalski, Kamil  */
515*4a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5161abe55efSEd Tanous                              const std::string &ipHash,
5171abe55efSEd Tanous                              const std::string &newValue,
518179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
519*4a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5201abe55efSEd Tanous {
521*4a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5221abe55efSEd Tanous                         const boost::system::error_code ec) {
5231abe55efSEd Tanous         if (ec)
5241abe55efSEd Tanous         {
525179db1d7SKowalski, Kamil             messages::addMessageToJson(
52655c7b7a2SEd Tanous                 asyncResp->res.jsonValue, messages::internalError(),
527*4a0cb85cSEd Tanous                 "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin");
5281abe55efSEd Tanous         }
5291abe55efSEd Tanous         else
5301abe55efSEd Tanous         {
531*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
532179db1d7SKowalski, Kamil                 newValue;
533179db1d7SKowalski, Kamil         }
534179db1d7SKowalski, Kamil     };
535179db1d7SKowalski, Kamil 
53655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
537179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
538179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
539179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
540179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
541179db1d7SKowalski, Kamil         sdbusplus::message::variant<std::string>(newValueDbus));
542*4a0cb85cSEd Tanous }
543179db1d7SKowalski, Kamil 
544179db1d7SKowalski, Kamil /**
545179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
546179db1d7SKowalski, Kamil  *
547179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
548*4a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5491abe55efSEd Tanous  * modified
550179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
551179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
552179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
553179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
554179db1d7SKowalski, Kamil  *
555179db1d7SKowalski, Kamil  * @return None
556179db1d7SKowalski, Kamil  */
557*4a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
558*4a0cb85cSEd Tanous                                          const std::string &ipHash,
559*4a0cb85cSEd Tanous                                          const std::string &newValueStr,
560*4a0cb85cSEd Tanous                                          uint8_t &newValue,
561*4a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5621abe55efSEd Tanous {
563*4a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5641abe55efSEd Tanous                         const boost::system::error_code ec) {
5651abe55efSEd Tanous         if (ec)
5661abe55efSEd Tanous         {
567179db1d7SKowalski, Kamil             messages::addMessageToJson(
56855c7b7a2SEd Tanous                 asyncResp->res.jsonValue, messages::internalError(),
569179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask");
5701abe55efSEd Tanous         }
5711abe55efSEd Tanous         else
5721abe55efSEd Tanous         {
57355c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
574179db1d7SKowalski, Kamil                 newValueStr;
575179db1d7SKowalski, Kamil         }
576179db1d7SKowalski, Kamil     };
577179db1d7SKowalski, Kamil 
57855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
579179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
580179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
581179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
582179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
583179db1d7SKowalski, Kamil         sdbusplus::message::variant<uint8_t>(newValue));
584*4a0cb85cSEd Tanous }
585588c3f0dSKowalski, Kamil 
586588c3f0dSKowalski, Kamil /**
587588c3f0dSKowalski, Kamil  * @brief Sets given HostName of the machine through D-Bus
588588c3f0dSKowalski, Kamil  *
589588c3f0dSKowalski, Kamil  * @param[in] newHostname   New name that HostName will be changed to
590588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
591588c3f0dSKowalski, Kamil  *
592588c3f0dSKowalski, Kamil  * @return None.
593588c3f0dSKowalski, Kamil  */
594588c3f0dSKowalski, Kamil template <typename CallbackFunc>
5951abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback)
5961abe55efSEd Tanous {
59755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
598588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
599588c3f0dSKowalski, Kamil         "/xyz/openbmc_project/network/config",
600588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
601588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
602588c3f0dSKowalski, Kamil         sdbusplus::message::variant<std::string>(newHostname));
603*4a0cb85cSEd Tanous }
604588c3f0dSKowalski, Kamil 
605588c3f0dSKowalski, Kamil /**
606179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
607179db1d7SKowalski, Kamil  *
608179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
609*4a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
610179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
611179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
612179db1d7SKowalski, Kamil  *
613179db1d7SKowalski, Kamil  * @return None
614179db1d7SKowalski, Kamil  */
615*4a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
616179db1d7SKowalski, Kamil                        unsigned int ipIdx,
617*4a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6181abe55efSEd Tanous {
61955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
620*4a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6211abe55efSEd Tanous             if (ec)
6221abe55efSEd Tanous             {
623179db1d7SKowalski, Kamil                 messages::addMessageToJson(
62455c7b7a2SEd Tanous                     asyncResp->res.jsonValue, messages::internalError(),
625179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
6261abe55efSEd Tanous             }
6271abe55efSEd Tanous             else
6281abe55efSEd Tanous             {
62955c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
630179db1d7SKowalski, Kamil             }
631179db1d7SKowalski, Kamil         },
632179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
633179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
634179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
635179db1d7SKowalski, Kamil }
636179db1d7SKowalski, Kamil 
637179db1d7SKowalski, Kamil /**
638179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
639179db1d7SKowalski, Kamil  *
640179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
641*4a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
642179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
643179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
644179db1d7SKowalski, Kamil  *
645179db1d7SKowalski, Kamil  * @return None
646179db1d7SKowalski, Kamil  */
647*4a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
648179db1d7SKowalski, Kamil                        uint8_t subnetMask, const std::string &gateway,
649179db1d7SKowalski, Kamil                        const std::string &address,
650*4a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6511abe55efSEd Tanous {
652*4a0cb85cSEd Tanous     auto createIpHandler = [ipIdx,
653*4a0cb85cSEd Tanous                             asyncResp](const boost::system::error_code ec) {
6541abe55efSEd Tanous         if (ec)
6551abe55efSEd Tanous         {
656179db1d7SKowalski, Kamil             messages::addMessageToJson(
65755c7b7a2SEd Tanous                 asyncResp->res.jsonValue, messages::internalError(),
658179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
659179db1d7SKowalski, Kamil         }
660179db1d7SKowalski, Kamil     };
661179db1d7SKowalski, Kamil 
66255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
663179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
664179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
665179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
666179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
667179db1d7SKowalski, Kamil         gateway);
668179db1d7SKowalski, Kamil }
669179db1d7SKowalski, Kamil 
670179db1d7SKowalski, Kamil /**
671179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
672179db1d7SKowalski, Kamil  * Object
673179db1d7SKowalski, Kamil  * from EntityManager Network Manager
674*4a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
675179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
676179db1d7SKowalski, Kamil  * into JSON
677179db1d7SKowalski, Kamil  */
678179db1d7SKowalski, Kamil template <typename CallbackFunc>
679*4a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
6801abe55efSEd Tanous                           CallbackFunc &&callback)
6811abe55efSEd Tanous {
68255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
683*4a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
6841abe55efSEd Tanous             const boost::system::error_code error_code,
685*4a0cb85cSEd Tanous             const GetManagedObjects &resp) {
68655c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
687*4a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
688179db1d7SKowalski, Kamil 
6891abe55efSEd Tanous             if (error_code)
6901abe55efSEd Tanous             {
69155c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
692179db1d7SKowalski, Kamil                 return;
693179db1d7SKowalski, Kamil             }
694179db1d7SKowalski, Kamil 
695*4a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
696*4a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
697179db1d7SKowalski, Kamil 
698179db1d7SKowalski, Kamil             // Fix global GW
6991abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
7001abe55efSEd Tanous             {
701*4a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
702*4a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
7031abe55efSEd Tanous                 {
704*4a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
705179db1d7SKowalski, Kamil                 }
706179db1d7SKowalski, Kamil             }
707179db1d7SKowalski, Kamil 
708*4a0cb85cSEd Tanous             // Finally make a callback with usefull data
70955c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
710179db1d7SKowalski, Kamil         },
711179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
712179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
713179db1d7SKowalski, Kamil };
714179db1d7SKowalski, Kamil 
715179db1d7SKowalski, Kamil /**
7169391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
7179391bb9cSRapkiewicz, Pawel  * Manager
7181abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
7191abe55efSEd Tanous  * into JSON.
7209391bb9cSRapkiewicz, Pawel  */
7219391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7221abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7231abe55efSEd Tanous {
72455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
725*4a0cb85cSEd Tanous         [callback{std::move(callback)}](
7269391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
727*4a0cb85cSEd Tanous             GetManagedObjects &resp) {
7281abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7291abe55efSEd Tanous             // ethernet interfaces
730*4a0cb85cSEd Tanous             std::vector<std::string> iface_list;
731*4a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7321abe55efSEd Tanous             if (error_code)
7331abe55efSEd Tanous             {
734*4a0cb85cSEd Tanous                 callback(false, iface_list);
7359391bb9cSRapkiewicz, Pawel                 return;
7369391bb9cSRapkiewicz, Pawel             }
7379391bb9cSRapkiewicz, Pawel 
7389391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
739*4a0cb85cSEd Tanous             for (const auto &objpath : resp)
7401abe55efSEd Tanous             {
7419391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
742*4a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7431abe55efSEd Tanous                 {
7441abe55efSEd Tanous                     // If interface is
745*4a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
746*4a0cb85cSEd Tanous                     // what we're looking for.
7479391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7481abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7491abe55efSEd Tanous                     {
750*4a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
751*4a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
752*4a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
753*4a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7541abe55efSEd Tanous                         {
7559391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
756*4a0cb85cSEd Tanous                             iface_list.emplace_back(
757*4a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
7589391bb9cSRapkiewicz, Pawel                         }
7599391bb9cSRapkiewicz, Pawel                     }
7609391bb9cSRapkiewicz, Pawel                 }
7619391bb9cSRapkiewicz, Pawel             }
762a434f2bdSEd Tanous             // Finally make a callback with useful data
763*4a0cb85cSEd Tanous             callback(true, iface_list);
7649391bb9cSRapkiewicz, Pawel         },
765aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
766aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7679391bb9cSRapkiewicz, Pawel };
7689391bb9cSRapkiewicz, Pawel 
7699391bb9cSRapkiewicz, Pawel /**
7709391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
7719391bb9cSRapkiewicz, Pawel  */
7721abe55efSEd Tanous class EthernetCollection : public Node
7731abe55efSEd Tanous {
7749391bb9cSRapkiewicz, Pawel   public:
775*4a0cb85cSEd Tanous     template <typename CrowApp>
7761abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
777*4a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
7781abe55efSEd Tanous     {
7799391bb9cSRapkiewicz, Pawel         Node::json["@odata.type"] =
7809391bb9cSRapkiewicz, Pawel             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
7819391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
7829391bb9cSRapkiewicz, Pawel             "/redfish/v1/"
7839391bb9cSRapkiewicz, Pawel             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
784*4a0cb85cSEd Tanous         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces";
7859391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Ethernet Network Interface Collection";
7869391bb9cSRapkiewicz, Pawel         Node::json["Description"] =
7879391bb9cSRapkiewicz, Pawel             "Collection of EthernetInterfaces for this Manager";
7889391bb9cSRapkiewicz, Pawel 
789588c3f0dSKowalski, Kamil         entityPrivileges = {
790588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
791e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
792e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
793e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
794e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
795e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
7969391bb9cSRapkiewicz, Pawel     }
7979391bb9cSRapkiewicz, Pawel 
7989391bb9cSRapkiewicz, Pawel   private:
7999391bb9cSRapkiewicz, Pawel     /**
8009391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8019391bb9cSRapkiewicz, Pawel      */
80255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
8031abe55efSEd Tanous                const std::vector<std::string> &params) override
8041abe55efSEd Tanous     {
805*4a0cb85cSEd Tanous         res.jsonValue = Node::json;
806*4a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
8071abe55efSEd Tanous         // preparation
808*4a0cb85cSEd Tanous         getEthernetIfaceList([&res](
8091abe55efSEd Tanous                                  const bool &success,
8101abe55efSEd Tanous                                  const std::vector<std::string> &iface_list) {
811*4a0cb85cSEd Tanous             if (!success)
8121abe55efSEd Tanous             {
813*4a0cb85cSEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
814*4a0cb85cSEd Tanous                 res.end();
815*4a0cb85cSEd Tanous                 return;
816*4a0cb85cSEd Tanous             }
817*4a0cb85cSEd Tanous 
818*4a0cb85cSEd Tanous             nlohmann::json &iface_array = res.jsonValue["Members"];
819*4a0cb85cSEd Tanous             iface_array = nlohmann::json::array();
820*4a0cb85cSEd Tanous             for (const std::string &iface_item : iface_list)
8211abe55efSEd Tanous             {
822*4a0cb85cSEd Tanous                 iface_array.push_back(
823*4a0cb85cSEd Tanous                     {{"@odata.id",
824*4a0cb85cSEd Tanous                       "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
825*4a0cb85cSEd Tanous                           iface_item}});
8269391bb9cSRapkiewicz, Pawel             }
827*4a0cb85cSEd Tanous 
828*4a0cb85cSEd Tanous             res.jsonValue["Members@odata.count"] = iface_array.size();
829*4a0cb85cSEd Tanous             res.jsonValue["@odata.id"] =
830*4a0cb85cSEd Tanous                 "/redfish/v1/Managers/bmc/EthernetInterfaces";
8319391bb9cSRapkiewicz, Pawel             res.end();
8329391bb9cSRapkiewicz, Pawel         });
8339391bb9cSRapkiewicz, Pawel     }
8349391bb9cSRapkiewicz, Pawel };
8359391bb9cSRapkiewicz, Pawel 
8369391bb9cSRapkiewicz, Pawel /**
8379391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8389391bb9cSRapkiewicz, Pawel  */
8391abe55efSEd Tanous class EthernetInterface : public Node
8401abe55efSEd Tanous {
8419391bb9cSRapkiewicz, Pawel   public:
8429391bb9cSRapkiewicz, Pawel     /*
8439391bb9cSRapkiewicz, Pawel      * Default Constructor
8449391bb9cSRapkiewicz, Pawel      */
845*4a0cb85cSEd Tanous     template <typename CrowApp>
8461abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
847*4a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8481abe55efSEd Tanous              std::string())
8491abe55efSEd Tanous     {
8501abe55efSEd Tanous         Node::json["@odata.type"] =
8511abe55efSEd Tanous             "#EthernetInterface.v1_2_0.EthernetInterface";
8529391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
8539391bb9cSRapkiewicz, Pawel             "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
8549391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Manager Ethernet Interface";
8559391bb9cSRapkiewicz, Pawel         Node::json["Description"] = "Management Network Interface";
8569391bb9cSRapkiewicz, Pawel 
857588c3f0dSKowalski, Kamil         entityPrivileges = {
858588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
859e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
860e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
861e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
862e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
863e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8649391bb9cSRapkiewicz, Pawel     }
8659391bb9cSRapkiewicz, Pawel 
866e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
867e439f0f8SKowalski, Kamil     static void handleVlanPatch(const std::string &ifaceId,
868e439f0f8SKowalski, Kamil                                 const nlohmann::json &input,
869*4a0cb85cSEd Tanous                                 const EthernetInterfaceData &ethData,
870*4a0cb85cSEd Tanous                                 const std::shared_ptr<AsyncResp> asyncResp)
8711abe55efSEd Tanous     {
8721abe55efSEd Tanous         if (!input.is_object())
8731abe55efSEd Tanous         {
874588c3f0dSKowalski, Kamil             messages::addMessageToJson(
87555c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
876*4a0cb85cSEd Tanous                 messages::propertyValueTypeError(input.dump(), "VLAN"), "/");
877588c3f0dSKowalski, Kamil             return;
878588c3f0dSKowalski, Kamil         }
879588c3f0dSKowalski, Kamil 
880*4a0cb85cSEd Tanous         nlohmann::json::const_iterator vlanEnable = input.find("VLANEnable");
881*4a0cb85cSEd Tanous         if (vlanEnable == input.end())
8821abe55efSEd Tanous         {
883*4a0cb85cSEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
884*4a0cb85cSEd Tanous                                        messages::propertyMissing("VLANEnable"),
885*4a0cb85cSEd Tanous                                        "/VLANEnable");
886*4a0cb85cSEd Tanous             return;
887*4a0cb85cSEd Tanous         }
888*4a0cb85cSEd Tanous         const bool *vlanEnableBool = vlanEnable->get_ptr<const bool *>();
889*4a0cb85cSEd Tanous         if (vlanEnableBool == nullptr)
890*4a0cb85cSEd Tanous         {
891*4a0cb85cSEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
892*4a0cb85cSEd Tanous                                        messages::propertyValueTypeError(
893*4a0cb85cSEd Tanous                                            vlanEnable->dump(), "VLANEnable"),
894*4a0cb85cSEd Tanous                                        "/VLANEnable");
895588c3f0dSKowalski, Kamil             return;
896588c3f0dSKowalski, Kamil         }
897588c3f0dSKowalski, Kamil 
898*4a0cb85cSEd Tanous         nlohmann::json::const_iterator vlanId = input.find("VLANId");
899*4a0cb85cSEd Tanous         if (vlanId == input.end())
900*4a0cb85cSEd Tanous         {
901*4a0cb85cSEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
902*4a0cb85cSEd Tanous                                        messages::propertyMissing("VLANId"),
903*4a0cb85cSEd Tanous                                        "/VLANId");
904*4a0cb85cSEd Tanous             return;
905*4a0cb85cSEd Tanous         }
906*4a0cb85cSEd Tanous         const uint64_t *vlanIdUint = vlanId->get_ptr<const uint64_t *>();
907*4a0cb85cSEd Tanous         if (vlanIdUint == nullptr)
908*4a0cb85cSEd Tanous         {
909*4a0cb85cSEd Tanous             messages::addMessageToJson(
910*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue,
911*4a0cb85cSEd Tanous                 messages::propertyValueTypeError(vlanId->dump(), "VLANId"),
912*4a0cb85cSEd Tanous                 "/VLANId");
913*4a0cb85cSEd Tanous             return;
914*4a0cb85cSEd Tanous         }
915*4a0cb85cSEd Tanous 
916*4a0cb85cSEd Tanous         if (!ethData.vlan_id)
9171abe55efSEd Tanous         {
918e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
919e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
920*4a0cb85cSEd Tanous             messages::addMessageToJson(
921*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue,
922*4a0cb85cSEd Tanous                 messages::propertyNotWritable("VLANEnable"), "/VLANEnable");
923588c3f0dSKowalski, Kamil 
924588c3f0dSKowalski, Kamil             return;
925588c3f0dSKowalski, Kamil         }
926588c3f0dSKowalski, Kamil 
927588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
928*4a0cb85cSEd Tanous         if (*vlanEnableBool == true)
9291abe55efSEd Tanous         {
930588c3f0dSKowalski, Kamil             // Change VLAN Id
931*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["VLANId"] = *vlanIdUint;
932*4a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9331abe55efSEd Tanous                 if (ec)
9341abe55efSEd Tanous                 {
93555c7b7a2SEd Tanous                     messages::addMessageToJson(asyncResp->res.jsonValue,
936*4a0cb85cSEd Tanous                                                messages::internalError(), "/");
9371abe55efSEd Tanous                 }
9381abe55efSEd Tanous                 else
9391abe55efSEd Tanous                 {
940*4a0cb85cSEd Tanous                     asyncResp->res.jsonValue["VLANEnable"] = true;
941e439f0f8SKowalski, Kamil                 }
942*4a0cb85cSEd Tanous             };
943*4a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
944*4a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
945*4a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
946*4a0cb85cSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
947*4a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.VLAN", "Id",
948*4a0cb85cSEd Tanous                 sdbusplus::message::variant<uint32_t>(*vlanIdUint));
9491abe55efSEd Tanous         }
950*4a0cb85cSEd Tanous         else
9511abe55efSEd Tanous         {
952*4a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9531abe55efSEd Tanous                 if (ec)
9541abe55efSEd Tanous                 {
95555c7b7a2SEd Tanous                     messages::addMessageToJson(asyncResp->res.jsonValue,
956*4a0cb85cSEd Tanous                                                messages::internalError(), "/");
957*4a0cb85cSEd Tanous                     return;
9581abe55efSEd Tanous                 }
959*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue["VLANEnable"] = false;
960*4a0cb85cSEd Tanous             };
961*4a0cb85cSEd Tanous 
962*4a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
963*4a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
964*4a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
965*4a0cb85cSEd Tanous                 "xyz.openbmc_project.Object.Delete", "Delete");
966588c3f0dSKowalski, Kamil         }
967588c3f0dSKowalski, Kamil     }
968588c3f0dSKowalski, Kamil 
969e439f0f8SKowalski, Kamil   private:
970588c3f0dSKowalski, Kamil     void handleHostnamePatch(const nlohmann::json &input,
971*4a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
9721abe55efSEd Tanous     {
973*4a0cb85cSEd Tanous         const std::string *newHostname = input.get_ptr<const std::string *>();
974*4a0cb85cSEd Tanous         if (newHostname == nullptr)
9751abe55efSEd Tanous         {
9761abe55efSEd Tanous             messages::addMessageToJson(
9771abe55efSEd Tanous                 asyncResp->res.jsonValue,
978*4a0cb85cSEd Tanous                 messages::propertyValueTypeError(input.dump(), "HostName"),
979*4a0cb85cSEd Tanous                 "/HostName");
980*4a0cb85cSEd Tanous             return;
981*4a0cb85cSEd Tanous         }
982*4a0cb85cSEd Tanous 
983*4a0cb85cSEd Tanous         // Change hostname
984*4a0cb85cSEd Tanous         setHostName(
985*4a0cb85cSEd Tanous             *newHostname, [asyncResp, newHostname{std::string(*newHostname)}](
986*4a0cb85cSEd Tanous                               const boost::system::error_code ec) {
987*4a0cb85cSEd Tanous                 if (ec)
988*4a0cb85cSEd Tanous                 {
989*4a0cb85cSEd Tanous                     messages::addMessageToJson(asyncResp->res.jsonValue,
990*4a0cb85cSEd Tanous                                                messages::internalError(),
991*4a0cb85cSEd Tanous                                                "/HostName");
9921abe55efSEd Tanous                 }
9931abe55efSEd Tanous                 else
9941abe55efSEd Tanous                 {
99555c7b7a2SEd Tanous                     asyncResp->res.jsonValue["HostName"] = newHostname;
996588c3f0dSKowalski, Kamil                 }
997588c3f0dSKowalski, Kamil             });
998588c3f0dSKowalski, Kamil     }
999588c3f0dSKowalski, Kamil 
1000*4a0cb85cSEd Tanous     void handleIPv4Patch(
1001*4a0cb85cSEd Tanous         const std::string &ifaceId, const nlohmann::json &input,
1002*4a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1003*4a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
10041abe55efSEd Tanous     {
10051abe55efSEd Tanous         if (!input.is_array())
10061abe55efSEd Tanous         {
1007179db1d7SKowalski, Kamil             messages::addMessageToJson(
100855c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1009179db1d7SKowalski, Kamil                 messages::propertyValueTypeError(input.dump(), "IPv4Addresses"),
1010179db1d7SKowalski, Kamil                 "/IPv4Addresses");
1011179db1d7SKowalski, Kamil             return;
1012179db1d7SKowalski, Kamil         }
1013179db1d7SKowalski, Kamil 
1014179db1d7SKowalski, Kamil         // According to Redfish PATCH definition, size must be at least equal
1015*4a0cb85cSEd Tanous         if (input.size() < ipv4Data.size())
10161abe55efSEd Tanous         {
10171abe55efSEd Tanous             // TODO(kkowalsk) This should be a message indicating that not
10181abe55efSEd Tanous             // enough data has been provided
101955c7b7a2SEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
10201abe55efSEd Tanous                                        messages::internalError(),
10211abe55efSEd Tanous                                        "/IPv4Addresses");
1022179db1d7SKowalski, Kamil             return;
1023179db1d7SKowalski, Kamil         }
1024179db1d7SKowalski, Kamil 
1025*4a0cb85cSEd Tanous         int entryIdx = 0;
1026*4a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1027*4a0cb85cSEd Tanous             ipv4Data.begin();
1028*4a0cb85cSEd Tanous         for (const nlohmann::json &thisJson : input)
10291abe55efSEd Tanous         {
1030*4a0cb85cSEd Tanous             std::string pathString =
1031*4a0cb85cSEd Tanous                 "/IPv4Addresses/" + std::to_string(entryIdx);
1032179db1d7SKowalski, Kamil             // Check that entry is not of some unexpected type
1033*4a0cb85cSEd Tanous             if (!thisJson.is_object() && !thisJson.is_null())
10341abe55efSEd Tanous             {
1035*4a0cb85cSEd Tanous                 messages::addMessageToJson(asyncResp->res.jsonValue,
1036*4a0cb85cSEd Tanous                                            messages::propertyValueTypeError(
1037*4a0cb85cSEd Tanous                                                thisJson.dump(), "IPv4Address"),
1038*4a0cb85cSEd Tanous                                            pathString);
1039179db1d7SKowalski, Kamil 
1040179db1d7SKowalski, Kamil                 continue;
1041179db1d7SKowalski, Kamil             }
1042179db1d7SKowalski, Kamil 
1043*4a0cb85cSEd Tanous             nlohmann::json::const_iterator addressFieldIt =
1044*4a0cb85cSEd Tanous                 thisJson.find("Address");
1045*4a0cb85cSEd Tanous             const std::string *addressField = nullptr;
1046*4a0cb85cSEd Tanous             if (addressFieldIt != thisJson.end())
10471abe55efSEd Tanous             {
1048*4a0cb85cSEd Tanous                 addressField = addressFieldIt->get_ptr<const std::string *>();
1049*4a0cb85cSEd Tanous                 if (addressField == nullptr)
10501abe55efSEd Tanous                 {
1051179db1d7SKowalski, Kamil                     messages::addMessageToJson(
105255c7b7a2SEd Tanous                         asyncResp->res.jsonValue,
1053*4a0cb85cSEd Tanous                         messages::propertyValueFormatError(
1054*4a0cb85cSEd Tanous                             addressFieldIt->dump(), "Address"),
1055*4a0cb85cSEd Tanous                         pathString + "/Address");
1056179db1d7SKowalski, Kamil                     continue;
1057179db1d7SKowalski, Kamil                 }
10581abe55efSEd Tanous                 else
10591abe55efSEd Tanous                 {
1060*4a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*addressField))
1061*4a0cb85cSEd Tanous                     {
1062*4a0cb85cSEd Tanous                         messages::addMessageToJson(
1063*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue,
1064*4a0cb85cSEd Tanous                             messages::propertyValueFormatError(*addressField,
1065*4a0cb85cSEd Tanous                                                                "Address"),
1066*4a0cb85cSEd Tanous                             pathString + "/Address");
1067*4a0cb85cSEd Tanous                         continue;
1068*4a0cb85cSEd Tanous                     }
1069*4a0cb85cSEd Tanous                 }
1070*4a0cb85cSEd Tanous             }
1071*4a0cb85cSEd Tanous 
1072*4a0cb85cSEd Tanous             boost::optional<uint8_t> prefixLength;
1073*4a0cb85cSEd Tanous             const std::string *subnetField = nullptr;
1074*4a0cb85cSEd Tanous             nlohmann::json::const_iterator subnetFieldIt =
1075*4a0cb85cSEd Tanous                 thisJson.find("SubnetMask");
1076*4a0cb85cSEd Tanous             if (subnetFieldIt != thisJson.end())
1077*4a0cb85cSEd Tanous             {
1078*4a0cb85cSEd Tanous                 subnetField = subnetFieldIt->get_ptr<const std::string *>();
1079*4a0cb85cSEd Tanous                 if (subnetField == nullptr)
1080*4a0cb85cSEd Tanous                 {
1081*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1082*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1083*4a0cb85cSEd Tanous                         messages::propertyValueFormatError(*subnetField,
1084*4a0cb85cSEd Tanous                                                            "SubnetMask"),
1085*4a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1086*4a0cb85cSEd Tanous                     continue;
1087*4a0cb85cSEd Tanous                 }
1088*4a0cb85cSEd Tanous                 else
1089*4a0cb85cSEd Tanous                 {
1090*4a0cb85cSEd Tanous                     prefixLength = 0;
1091*4a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*subnetField,
1092*4a0cb85cSEd Tanous                                                     &*prefixLength))
1093*4a0cb85cSEd Tanous                     {
1094*4a0cb85cSEd Tanous                         messages::addMessageToJson(
1095*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue,
1096*4a0cb85cSEd Tanous                             messages::propertyValueFormatError(*subnetField,
1097*4a0cb85cSEd Tanous                                                                "SubnetMask"),
1098*4a0cb85cSEd Tanous                             pathString + "/SubnetMask");
1099*4a0cb85cSEd Tanous                         continue;
1100*4a0cb85cSEd Tanous                     }
1101*4a0cb85cSEd Tanous                 }
1102*4a0cb85cSEd Tanous             }
1103*4a0cb85cSEd Tanous 
1104*4a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
1105*4a0cb85cSEd Tanous             const std::string *addressOriginField = nullptr;
1106*4a0cb85cSEd Tanous             nlohmann::json::const_iterator addressOriginFieldIt =
1107*4a0cb85cSEd Tanous                 thisJson.find("AddressOrigin");
1108*4a0cb85cSEd Tanous             if (addressOriginFieldIt != thisJson.end())
1109*4a0cb85cSEd Tanous             {
1110*4a0cb85cSEd Tanous                 const std::string *addressOriginField =
1111*4a0cb85cSEd Tanous                     addressOriginFieldIt->get_ptr<const std::string *>();
1112*4a0cb85cSEd Tanous                 if (addressOriginField == nullptr)
1113*4a0cb85cSEd Tanous                 {
1114*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1115*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1116*4a0cb85cSEd Tanous                         messages::propertyValueFormatError(*addressOriginField,
1117*4a0cb85cSEd Tanous                                                            "AddressOrigin"),
1118*4a0cb85cSEd Tanous                         pathString + "/AddressOrigin");
1119*4a0cb85cSEd Tanous                     continue;
1120*4a0cb85cSEd Tanous                 }
1121*4a0cb85cSEd Tanous                 else
1122*4a0cb85cSEd Tanous                 {
1123*4a0cb85cSEd Tanous                     // Get Address origin in proper format
1124*4a0cb85cSEd Tanous                     addressOriginInDBusFormat =
1125*4a0cb85cSEd Tanous                         translateAddressOriginRedfishToDbus(
1126*4a0cb85cSEd Tanous                             *addressOriginField);
1127*4a0cb85cSEd Tanous                     if (addressOriginInDBusFormat.empty())
1128*4a0cb85cSEd Tanous                     {
1129*4a0cb85cSEd Tanous                         messages::addMessageToJson(
1130*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue,
1131*4a0cb85cSEd Tanous                             messages::propertyValueNotInList(
1132*4a0cb85cSEd Tanous                                 *addressOriginField, "AddressOrigin"),
1133*4a0cb85cSEd Tanous                             pathString + "/AddressOrigin");
1134*4a0cb85cSEd Tanous                         continue;
1135*4a0cb85cSEd Tanous                     }
1136*4a0cb85cSEd Tanous                 }
1137*4a0cb85cSEd Tanous             }
1138*4a0cb85cSEd Tanous 
1139*4a0cb85cSEd Tanous             nlohmann::json::const_iterator gatewayFieldIt =
1140*4a0cb85cSEd Tanous                 thisJson.find("Gateway");
1141*4a0cb85cSEd Tanous             const std::string *gatewayField = nullptr;
1142*4a0cb85cSEd Tanous             if (gatewayFieldIt != thisJson.end())
1143*4a0cb85cSEd Tanous             {
1144*4a0cb85cSEd Tanous                 const std::string *gatewayField =
1145*4a0cb85cSEd Tanous                     gatewayFieldIt->get_ptr<const std::string *>();
1146*4a0cb85cSEd Tanous                 if (gatewayField == nullptr ||
1147*4a0cb85cSEd Tanous                     !ipv4VerifyIpAndGetBitcount(*gatewayField))
1148*4a0cb85cSEd Tanous                 {
1149*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1150*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1151*4a0cb85cSEd Tanous                         messages::propertyValueFormatError(*gatewayField,
1152*4a0cb85cSEd Tanous                                                            "Gateway"),
1153*4a0cb85cSEd Tanous                         pathString + "/Gateway");
1154*4a0cb85cSEd Tanous                     continue;
1155*4a0cb85cSEd Tanous                 }
1156*4a0cb85cSEd Tanous             }
1157*4a0cb85cSEd Tanous 
1158*4a0cb85cSEd Tanous             // if a vlan already exists, modify the existing
1159*4a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
1160*4a0cb85cSEd Tanous             {
11611abe55efSEd Tanous                 // Existing object that should be modified/deleted/remain
11621abe55efSEd Tanous                 // unchanged
1163*4a0cb85cSEd Tanous                 if (thisJson.is_null())
11641abe55efSEd Tanous                 {
1165*4a0cb85cSEd Tanous                     auto callback = [entryIdx{std::to_string(entryIdx)},
1166*4a0cb85cSEd Tanous                                      asyncResp](
1167*4a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
1168*4a0cb85cSEd Tanous                         if (ec)
1169*4a0cb85cSEd Tanous                         {
1170*4a0cb85cSEd Tanous                             messages::addMessageToJson(
1171*4a0cb85cSEd Tanous                                 asyncResp->res.jsonValue,
1172*4a0cb85cSEd Tanous                                 messages::internalError(),
1173*4a0cb85cSEd Tanous                                 "/IPv4Addresses/" + entryIdx + "/");
1174*4a0cb85cSEd Tanous                             return;
11751abe55efSEd Tanous                         }
1176*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
1177*4a0cb85cSEd Tanous                             nullptr;
1178*4a0cb85cSEd Tanous                     };
1179*4a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
1180*4a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1181*4a0cb85cSEd Tanous                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1182*4a0cb85cSEd Tanous                             thisData->id,
1183*4a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
1184179db1d7SKowalski, Kamil                 }
1185*4a0cb85cSEd Tanous                 else if (thisJson.is_object())
1186*4a0cb85cSEd Tanous                 {
1187179db1d7SKowalski, Kamil                     // Apply changes
1188*4a0cb85cSEd Tanous                     if (addressField != nullptr)
11891abe55efSEd Tanous                     {
1190*4a0cb85cSEd Tanous                         auto callback =
1191*4a0cb85cSEd Tanous                             [asyncResp, entryIdx,
1192*4a0cb85cSEd Tanous                              addressField{std::string(*addressField)}](
1193*4a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
1194*4a0cb85cSEd Tanous                                 if (ec)
11951abe55efSEd Tanous                                 {
1196*4a0cb85cSEd Tanous                                     messages::addMessageToJson(
1197*4a0cb85cSEd Tanous                                         asyncResp->res.jsonValue,
1198*4a0cb85cSEd Tanous                                         messages::internalError(),
1199*4a0cb85cSEd Tanous                                         "/IPv4Addresses/" +
1200*4a0cb85cSEd Tanous                                             std::to_string(entryIdx) +
1201*4a0cb85cSEd Tanous                                             "/Address");
1202*4a0cb85cSEd Tanous                                     return;
1203*4a0cb85cSEd Tanous                                 }
1204*4a0cb85cSEd Tanous                                 asyncResp->res
1205*4a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
1206*4a0cb85cSEd Tanous                                         entryIdx)]["Address"] = addressField;
1207*4a0cb85cSEd Tanous                             };
1208*4a0cb85cSEd Tanous 
1209*4a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
1210*4a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
1211*4a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
1212*4a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
1213*4a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
1214*4a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Address",
1215*4a0cb85cSEd Tanous                             sdbusplus::message::variant<std::string>(
1216*4a0cb85cSEd Tanous                                 *addressField));
1217179db1d7SKowalski, Kamil                     }
1218179db1d7SKowalski, Kamil 
1219*4a0cb85cSEd Tanous                     if (prefixLength && subnetField != nullptr)
12201abe55efSEd Tanous                     {
1221*4a0cb85cSEd Tanous                         changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1222*4a0cb85cSEd Tanous                                                      thisData->id, *subnetField,
1223*4a0cb85cSEd Tanous                                                      *prefixLength, asyncResp);
1224179db1d7SKowalski, Kamil                     }
1225179db1d7SKowalski, Kamil 
1226*4a0cb85cSEd Tanous                     if (!addressOriginInDBusFormat.empty() &&
1227*4a0cb85cSEd Tanous                         addressOriginField != nullptr)
12281abe55efSEd Tanous                     {
1229*4a0cb85cSEd Tanous                         changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1230*4a0cb85cSEd Tanous                                          *addressOriginField,
1231*4a0cb85cSEd Tanous                                          addressOriginInDBusFormat, asyncResp);
1232179db1d7SKowalski, Kamil                     }
1233179db1d7SKowalski, Kamil 
1234*4a0cb85cSEd Tanous                     if (gatewayField != nullptr)
12351abe55efSEd Tanous                     {
1236*4a0cb85cSEd Tanous                         auto callback =
1237*4a0cb85cSEd Tanous                             [asyncResp, entryIdx,
1238*4a0cb85cSEd Tanous                              gatewayField{std::string(*gatewayField)}](
1239*4a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
1240*4a0cb85cSEd Tanous                                 if (ec)
12411abe55efSEd Tanous                                 {
1242*4a0cb85cSEd Tanous                                     messages::addMessageToJson(
1243*4a0cb85cSEd Tanous                                         asyncResp->res.jsonValue,
1244*4a0cb85cSEd Tanous                                         messages::internalError(),
1245*4a0cb85cSEd Tanous                                         "/IPv4Addresses/" +
1246*4a0cb85cSEd Tanous                                             std::to_string(entryIdx) +
1247*4a0cb85cSEd Tanous                                             "/Gateway");
1248*4a0cb85cSEd Tanous                                     return;
1249*4a0cb85cSEd Tanous                                 }
1250*4a0cb85cSEd Tanous                                 asyncResp->res
1251*4a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
1252*4a0cb85cSEd Tanous                                         entryIdx)]["Gateway"] =
1253*4a0cb85cSEd Tanous                                     std::move(gatewayField);
1254*4a0cb85cSEd Tanous                             };
1255*4a0cb85cSEd Tanous 
1256*4a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
1257*4a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
1258*4a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
1259*4a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
1260*4a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
1261*4a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Gateway",
1262*4a0cb85cSEd Tanous                             sdbusplus::message::variant<std::string>(
1263*4a0cb85cSEd Tanous                                 *gatewayField));
1264*4a0cb85cSEd Tanous                     }
1265*4a0cb85cSEd Tanous                 }
1266*4a0cb85cSEd Tanous                 thisData++;
12671abe55efSEd Tanous             }
12681abe55efSEd Tanous             else
12691abe55efSEd Tanous             {
1270*4a0cb85cSEd Tanous                 // Create IPv4 with provided data
1271*4a0cb85cSEd Tanous                 if (gatewayField == nullptr)
12721abe55efSEd Tanous                 {
1273*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1274*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1275*4a0cb85cSEd Tanous                         messages::propertyMissing("Gateway"),
1276*4a0cb85cSEd Tanous                         pathString + "/Gateway");
1277*4a0cb85cSEd Tanous                     continue;
1278*4a0cb85cSEd Tanous                 }
1279*4a0cb85cSEd Tanous 
1280*4a0cb85cSEd Tanous                 if (addressField == nullptr)
12811abe55efSEd Tanous                 {
1282*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1283*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1284*4a0cb85cSEd Tanous                         messages::propertyMissing("Address"),
1285*4a0cb85cSEd Tanous                         pathString + "/Address");
1286*4a0cb85cSEd Tanous                     continue;
1287*4a0cb85cSEd Tanous                 }
1288*4a0cb85cSEd Tanous 
1289*4a0cb85cSEd Tanous                 if (!prefixLength)
12901abe55efSEd Tanous                 {
1291*4a0cb85cSEd Tanous                     messages::addMessageToJson(
1292*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1293*4a0cb85cSEd Tanous                         messages::propertyMissing("SubnetMask"),
1294*4a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1295*4a0cb85cSEd Tanous                     continue;
1296588c3f0dSKowalski, Kamil                 }
1297588c3f0dSKowalski, Kamil 
1298*4a0cb85cSEd Tanous                 createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField,
1299*4a0cb85cSEd Tanous                            *addressField, asyncResp);
1300*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
1301*4a0cb85cSEd Tanous             }
1302*4a0cb85cSEd Tanous             entryIdx++;
1303*4a0cb85cSEd Tanous         }
1304*4a0cb85cSEd Tanous     }
1305*4a0cb85cSEd Tanous 
1306*4a0cb85cSEd Tanous     nlohmann::json parseInterfaceData(
1307*4a0cb85cSEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
1308*4a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
1309*4a0cb85cSEd Tanous     {
1310*4a0cb85cSEd Tanous         // Copy JSON object to avoid race condition
1311*4a0cb85cSEd Tanous         nlohmann::json json_response(Node::json);
1312*4a0cb85cSEd Tanous 
1313*4a0cb85cSEd Tanous         json_response["Id"] = iface_id;
1314*4a0cb85cSEd Tanous         json_response["@odata.id"] =
1315*4a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1316*4a0cb85cSEd Tanous 
1317*4a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
1318*4a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1319*4a0cb85cSEd Tanous         if (!ethData.hostname.empty())
1320*4a0cb85cSEd Tanous         {
1321*4a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
1322*4a0cb85cSEd Tanous         }
1323*4a0cb85cSEd Tanous 
1324*4a0cb85cSEd Tanous         nlohmann::json &vlanObj = json_response["VLAN"];
1325*4a0cb85cSEd Tanous         if (ethData.vlan_id)
1326*4a0cb85cSEd Tanous         {
1327*4a0cb85cSEd Tanous             vlanObj["VLANEnable"] = true;
1328*4a0cb85cSEd Tanous             vlanObj["VLANId"] = *ethData.vlan_id;
1329*4a0cb85cSEd Tanous         }
1330*4a0cb85cSEd Tanous         else
1331*4a0cb85cSEd Tanous         {
1332*4a0cb85cSEd Tanous             vlanObj["VLANEnable"] = false;
1333*4a0cb85cSEd Tanous             vlanObj["VLANId"] = 0;
1334*4a0cb85cSEd Tanous         }
1335*4a0cb85cSEd Tanous 
1336*4a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
1337*4a0cb85cSEd Tanous         {
1338*4a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
1339*4a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
1340*4a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
1341*4a0cb85cSEd Tanous             {
1342*4a0cb85cSEd Tanous                 if (!ipv4_config.address.empty())
1343*4a0cb85cSEd Tanous                 {
1344*4a0cb85cSEd Tanous                     ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
1345*4a0cb85cSEd Tanous                                           {"SubnetMask", ipv4_config.netmask},
1346*4a0cb85cSEd Tanous                                           {"Address", ipv4_config.address}});
1347*4a0cb85cSEd Tanous 
1348*4a0cb85cSEd Tanous                     if (!ipv4_config.gateway.empty())
1349*4a0cb85cSEd Tanous                     {
1350*4a0cb85cSEd Tanous                         ipv4_array.back()["Gateway"] = ipv4_config.gateway;
1351*4a0cb85cSEd Tanous                     }
1352*4a0cb85cSEd Tanous                 }
1353*4a0cb85cSEd Tanous             }
1354*4a0cb85cSEd Tanous         }
1355*4a0cb85cSEd Tanous 
1356*4a0cb85cSEd Tanous         return json_response;
1357588c3f0dSKowalski, Kamil     }
1358588c3f0dSKowalski, Kamil 
13599391bb9cSRapkiewicz, Pawel     /**
13609391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
13619391bb9cSRapkiewicz, Pawel      */
136255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
13631abe55efSEd Tanous                const std::vector<std::string> &params) override
13641abe55efSEd Tanous     {
1365*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13661abe55efSEd Tanous         if (params.size() != 1)
13671abe55efSEd Tanous         {
1368*4a0cb85cSEd Tanous             asyncResp->res.result(
1369*4a0cb85cSEd Tanous                 boost::beast::http::status::internal_server_error);
13709391bb9cSRapkiewicz, Pawel             return;
13719391bb9cSRapkiewicz, Pawel         }
13729391bb9cSRapkiewicz, Pawel 
1373*4a0cb85cSEd Tanous         getEthernetIfaceData(
1374*4a0cb85cSEd Tanous             params[0],
1375*4a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
1376*4a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1377*4a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1378*4a0cb85cSEd Tanous                 if (!success)
13791abe55efSEd Tanous                 {
13801abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13811abe55efSEd Tanous                     // object, and other errors
1382e439f0f8SKowalski, Kamil                     messages::addMessageToErrorJson(
1383*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1384*4a0cb85cSEd Tanous                         messages::resourceNotFound("EthernetInterface",
1385*4a0cb85cSEd Tanous                                                    iface_id));
1386*4a0cb85cSEd Tanous                     asyncResp->res.result(
1387*4a0cb85cSEd Tanous                         boost::beast::http::status::not_found);
1388*4a0cb85cSEd Tanous                     return;
13899391bb9cSRapkiewicz, Pawel                 }
1390*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue =
1391*4a0cb85cSEd Tanous                     parseInterfaceData(iface_id, ethData, ipv4Data);
13929391bb9cSRapkiewicz, Pawel             });
13939391bb9cSRapkiewicz, Pawel     }
13949391bb9cSRapkiewicz, Pawel 
139555c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
13961abe55efSEd Tanous                  const std::vector<std::string> &params) override
13971abe55efSEd Tanous     {
1398*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13991abe55efSEd Tanous         if (params.size() != 1)
14001abe55efSEd Tanous         {
1401588c3f0dSKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1402588c3f0dSKowalski, Kamil             return;
1403588c3f0dSKowalski, Kamil         }
1404588c3f0dSKowalski, Kamil 
1405*4a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1406588c3f0dSKowalski, Kamil 
1407179db1d7SKowalski, Kamil         nlohmann::json patchReq;
14081abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
14091abe55efSEd Tanous         {
1410588c3f0dSKowalski, Kamil             return;
1411588c3f0dSKowalski, Kamil         }
1412588c3f0dSKowalski, Kamil 
1413*4a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1414588c3f0dSKowalski, Kamil         // preparation
1415*4a0cb85cSEd Tanous         getEthernetIfaceData(
1416*4a0cb85cSEd Tanous             iface_id,
1417*4a0cb85cSEd Tanous             [this, asyncResp, iface_id, patchReq = std::move(patchReq)](
1418*4a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1419*4a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14201abe55efSEd Tanous                 if (!success)
14211abe55efSEd Tanous                 {
1422588c3f0dSKowalski, Kamil                     // ... otherwise return error
14231abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14241abe55efSEd Tanous                     // object, and other errors
1425927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1426*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1427*4a0cb85cSEd Tanous                         messages::resourceNotFound("VLAN Network Interface",
1428*4a0cb85cSEd Tanous                                                    iface_id));
1429*4a0cb85cSEd Tanous                     asyncResp->res.result(
1430*4a0cb85cSEd Tanous                         boost::beast::http::status::not_found);
1431*4a0cb85cSEd Tanous                     asyncResp->res.end();
1432588c3f0dSKowalski, Kamil 
1433588c3f0dSKowalski, Kamil                     return;
1434588c3f0dSKowalski, Kamil                 }
1435588c3f0dSKowalski, Kamil 
1436*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue =
1437*4a0cb85cSEd Tanous                     parseInterfaceData(iface_id, ethData, ipv4Data);
1438588c3f0dSKowalski, Kamil 
1439*4a0cb85cSEd Tanous                 for (auto propertyIt : patchReq.items())
14401abe55efSEd Tanous                 {
14411abe55efSEd Tanous                     if (propertyIt.key() == "VLAN")
14421abe55efSEd Tanous                     {
1443*4a0cb85cSEd Tanous                         handleVlanPatch(iface_id, propertyIt.value(), ethData,
1444*4a0cb85cSEd Tanous                                         asyncResp);
14451abe55efSEd Tanous                     }
14461abe55efSEd Tanous                     else if (propertyIt.key() == "HostName")
14471abe55efSEd Tanous                     {
1448*4a0cb85cSEd Tanous                         handleHostnamePatch(propertyIt.value(), asyncResp);
14491abe55efSEd Tanous                     }
14501abe55efSEd Tanous                     else if (propertyIt.key() == "IPv4Addresses")
14511abe55efSEd Tanous                     {
1452*4a0cb85cSEd Tanous                         handleIPv4Patch(iface_id, propertyIt.value(), ipv4Data,
1453179db1d7SKowalski, Kamil                                         asyncResp);
14541abe55efSEd Tanous                     }
14551abe55efSEd Tanous                     else if (propertyIt.key() == "IPv6Addresses")
14561abe55efSEd Tanous                     {
1457179db1d7SKowalski, Kamil                         // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1458179db1d7SKowalski, Kamil                         messages::addMessageToJsonRoot(
1459*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue,
1460179db1d7SKowalski, Kamil                             messages::propertyNotWritable(propertyIt.key()));
14611abe55efSEd Tanous                     }
14621abe55efSEd Tanous                     else
14631abe55efSEd Tanous                     {
14641abe55efSEd Tanous                         auto fieldInJsonIt =
1465*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue.find(propertyIt.key());
1466588c3f0dSKowalski, Kamil 
1467*4a0cb85cSEd Tanous                         if (fieldInJsonIt == asyncResp->res.jsonValue.end())
14681abe55efSEd Tanous                         {
1469588c3f0dSKowalski, Kamil                             // Field not in scope of defined fields
1470588c3f0dSKowalski, Kamil                             messages::addMessageToJsonRoot(
1471*4a0cb85cSEd Tanous                                 asyncResp->res.jsonValue,
14721abe55efSEd Tanous                                 messages::propertyUnknown(propertyIt.key()));
14731abe55efSEd Tanous                         }
1474*4a0cb85cSEd Tanous                         else
14751abe55efSEd Tanous                         {
1476588c3f0dSKowalski, Kamil                             // User attempted to modify non-writable field
1477588c3f0dSKowalski, Kamil                             messages::addMessageToJsonRoot(
1478*4a0cb85cSEd Tanous                                 asyncResp->res.jsonValue,
1479*4a0cb85cSEd Tanous                                 messages::propertyNotWritable(
14801abe55efSEd Tanous                                     propertyIt.key()));
1481588c3f0dSKowalski, Kamil                         }
1482588c3f0dSKowalski, Kamil                     }
1483588c3f0dSKowalski, Kamil                 }
1484588c3f0dSKowalski, Kamil             });
1485588c3f0dSKowalski, Kamil     }
14869391bb9cSRapkiewicz, Pawel };
14879391bb9cSRapkiewicz, Pawel 
1488e439f0f8SKowalski, Kamil /**
1489*4a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
1490*4a0cb85cSEd Tanous  * Schema
1491e439f0f8SKowalski, Kamil  */
14921abe55efSEd Tanous class VlanNetworkInterface : public Node
14931abe55efSEd Tanous {
1494e439f0f8SKowalski, Kamil   public:
1495e439f0f8SKowalski, Kamil     /*
1496e439f0f8SKowalski, Kamil      * Default Constructor
1497e439f0f8SKowalski, Kamil      */
1498e439f0f8SKowalski, Kamil     template <typename CrowApp>
14991abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
1500*4a0cb85cSEd Tanous     // one manager called openbmc.  This shall be generic, but requires to
1501*4a0cb85cSEd Tanous     // update GetSubroutes method
15021abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
1503*4a0cb85cSEd Tanous         Node(app,
1504*4a0cb85cSEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>>/VLANs/"
1505*4a0cb85cSEd Tanous              "<str>",
15061abe55efSEd Tanous              std::string(), std::string())
15071abe55efSEd Tanous     {
1508e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1509e439f0f8SKowalski, Kamil             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1510e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1511e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1512e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface";
1513e439f0f8SKowalski, Kamil 
1514e439f0f8SKowalski, Kamil         entityPrivileges = {
1515e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1516e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1517e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1518e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1519e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1520e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1521e439f0f8SKowalski, Kamil     }
1522e439f0f8SKowalski, Kamil 
1523e439f0f8SKowalski, Kamil   private:
1524*4a0cb85cSEd Tanous     nlohmann::json parseInterfaceData(
1525*4a0cb85cSEd Tanous         const std::string &parent_iface_id, const std::string &iface_id,
1526*4a0cb85cSEd Tanous         const EthernetInterfaceData &ethData,
1527*4a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
15281abe55efSEd Tanous     {
1529e439f0f8SKowalski, Kamil         // Copy JSON object to avoid race condition
1530*4a0cb85cSEd Tanous         nlohmann::json json_response(Node::json);
1531e439f0f8SKowalski, Kamil 
1532e439f0f8SKowalski, Kamil         // Fill out obvious data...
1533*4a0cb85cSEd Tanous         json_response["Id"] = iface_id;
1534*4a0cb85cSEd Tanous         json_response["@odata.id"] =
1535*4a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
1536*4a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1537e439f0f8SKowalski, Kamil 
1538*4a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1539*4a0cb85cSEd Tanous         if (ethData.vlan_id)
1540*4a0cb85cSEd Tanous         {
1541*4a0cb85cSEd Tanous             json_response["VLANId"] = *ethData.vlan_id;
1542*4a0cb85cSEd Tanous         }
1543*4a0cb85cSEd Tanous         return json_response;
1544e439f0f8SKowalski, Kamil     }
1545e439f0f8SKowalski, Kamil 
154655c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
15471abe55efSEd Tanous                      const std::string &iface)
15481abe55efSEd Tanous     {
15491abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
15501abe55efSEd Tanous         {
1551927a505aSKowalski, Kamil             messages::addMessageToErrorJson(
155255c7b7a2SEd Tanous                 res.jsonValue,
1553927a505aSKowalski, Kamil                 messages::resourceNotFound("VLAN Network Interface", iface));
1554927a505aSKowalski, Kamil             res.result(boost::beast::http::status::not_found);
1555927a505aSKowalski, Kamil             res.end();
1556927a505aSKowalski, Kamil 
1557927a505aSKowalski, Kamil             return false;
15581abe55efSEd Tanous         }
15591abe55efSEd Tanous         else
15601abe55efSEd Tanous         {
1561927a505aSKowalski, Kamil             return true;
1562927a505aSKowalski, Kamil         }
1563927a505aSKowalski, Kamil     }
1564927a505aSKowalski, Kamil 
1565e439f0f8SKowalski, Kamil     /**
1566e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1567e439f0f8SKowalski, Kamil      */
156855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15691abe55efSEd Tanous                const std::vector<std::string> &params) override
15701abe55efSEd Tanous     {
1571*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1572*4a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1573e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1574e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1575e439f0f8SKowalski, Kamil         // impossible.
15761abe55efSEd Tanous         if (params.size() != 2)
15771abe55efSEd Tanous         {
1578e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1579e439f0f8SKowalski, Kamil             res.end();
1580e439f0f8SKowalski, Kamil             return;
1581e439f0f8SKowalski, Kamil         }
1582e439f0f8SKowalski, Kamil 
1583*4a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
1584*4a0cb85cSEd Tanous         const std::string &iface_id = params[1];
1585e439f0f8SKowalski, Kamil 
1586*4a0cb85cSEd Tanous         if (!verifyNames(res, parent_iface_id, iface_id))
15871abe55efSEd Tanous         {
1588a434f2bdSEd Tanous             return;
1589a434f2bdSEd Tanous         }
1590a434f2bdSEd Tanous 
1591e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1592e439f0f8SKowalski, Kamil         // preparation
1593*4a0cb85cSEd Tanous         getEthernetIfaceData(
1594*4a0cb85cSEd Tanous             iface_id,
1595*4a0cb85cSEd Tanous             [this, asyncResp, parent_iface_id, iface_id](
1596*4a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1597*4a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1598*4a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
15991abe55efSEd Tanous                 {
1600*4a0cb85cSEd Tanous                     asyncResp->res.jsonValue = parseInterfaceData(
1601*4a0cb85cSEd Tanous                         parent_iface_id, iface_id, ethData, ipv4Data);
16021abe55efSEd Tanous                 }
16031abe55efSEd Tanous                 else
16041abe55efSEd Tanous                 {
1605e439f0f8SKowalski, Kamil                     // ... otherwise return error
16061abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16071abe55efSEd Tanous                     // object, and other errors
1608927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1609*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1610*4a0cb85cSEd Tanous                         messages::resourceNotFound("VLAN Network Interface",
1611*4a0cb85cSEd Tanous                                                    iface_id));
1612*4a0cb85cSEd Tanous                     asyncResp->res.result(
1613*4a0cb85cSEd Tanous                         boost::beast::http::status::not_found);
1614e439f0f8SKowalski, Kamil                 }
1615e439f0f8SKowalski, Kamil             });
1616e439f0f8SKowalski, Kamil     }
1617e439f0f8SKowalski, Kamil 
161855c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
16191abe55efSEd Tanous                  const std::vector<std::string> &params) override
16201abe55efSEd Tanous     {
1621*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16221abe55efSEd Tanous         if (params.size() != 2)
16231abe55efSEd Tanous         {
1624*4a0cb85cSEd Tanous             asyncResp->res.result(
1625*4a0cb85cSEd Tanous                 boost::beast::http::status::internal_server_error);
1626e439f0f8SKowalski, Kamil             return;
1627e439f0f8SKowalski, Kamil         }
1628e439f0f8SKowalski, Kamil 
1629d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
163055c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1631927a505aSKowalski, Kamil 
16321abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
16331abe55efSEd Tanous         {
1634927a505aSKowalski, Kamil             return;
1635927a505aSKowalski, Kamil         }
1636927a505aSKowalski, Kamil 
1637927a505aSKowalski, Kamil         nlohmann::json patchReq;
16381abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
16391abe55efSEd Tanous         {
1640927a505aSKowalski, Kamil             return;
1641927a505aSKowalski, Kamil         }
1642927a505aSKowalski, Kamil 
1643927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1644927a505aSKowalski, Kamil         // preparation
1645*4a0cb85cSEd Tanous         getEthernetIfaceData(
16461abe55efSEd Tanous             ifaceId,
1647*4a0cb85cSEd Tanous             [this, asyncResp, parentIfaceId, ifaceId,
1648*4a0cb85cSEd Tanous              patchReq{std::move(patchReq)}](
1649*4a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1650*4a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
16511abe55efSEd Tanous                 if (!success)
16521abe55efSEd Tanous                 {
16531abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16541abe55efSEd Tanous                     // object, and other errors
1655927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1656*4a0cb85cSEd Tanous                         asyncResp->res.jsonValue,
1657*4a0cb85cSEd Tanous                         messages::resourceNotFound("VLAN Network Interface",
1658*4a0cb85cSEd Tanous                                                    ifaceId));
1659*4a0cb85cSEd Tanous                     asyncResp->res.result(
1660*4a0cb85cSEd Tanous                         boost::beast::http::status::not_found);
1661*4a0cb85cSEd Tanous                     asyncResp->res.end();
1662927a505aSKowalski, Kamil 
1663927a505aSKowalski, Kamil                     return;
1664927a505aSKowalski, Kamil                 }
1665927a505aSKowalski, Kamil 
1666*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue = parseInterfaceData(
1667*4a0cb85cSEd Tanous                     parentIfaceId, ifaceId, ethData, ipv4Data);
1668927a505aSKowalski, Kamil 
1669*4a0cb85cSEd Tanous                 for (auto propertyIt : patchReq.items())
16701abe55efSEd Tanous                 {
1671927a505aSKowalski, Kamil                     if (propertyIt.key() != "VLANEnable" &&
16721abe55efSEd Tanous                         propertyIt.key() != "VLANId")
16731abe55efSEd Tanous                     {
16741abe55efSEd Tanous                         auto fieldInJsonIt =
1675*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue.find(propertyIt.key());
1676*4a0cb85cSEd Tanous                         if (fieldInJsonIt == asyncResp->res.jsonValue.end())
16771abe55efSEd Tanous                         {
1678927a505aSKowalski, Kamil                             // Field not in scope of defined fields
1679927a505aSKowalski, Kamil                             messages::addMessageToJsonRoot(
1680*4a0cb85cSEd Tanous                                 asyncResp->res.jsonValue,
16811abe55efSEd Tanous                                 messages::propertyUnknown(propertyIt.key()));
16821abe55efSEd Tanous                         }
1683*4a0cb85cSEd Tanous                         else
16841abe55efSEd Tanous                         {
1685927a505aSKowalski, Kamil                             // User attempted to modify non-writable field
1686927a505aSKowalski, Kamil                             messages::addMessageToJsonRoot(
1687*4a0cb85cSEd Tanous                                 asyncResp->res.jsonValue,
1688*4a0cb85cSEd Tanous                                 messages::propertyNotWritable(
16891abe55efSEd Tanous                                     propertyIt.key()));
1690927a505aSKowalski, Kamil                         }
1691927a505aSKowalski, Kamil                     }
1692927a505aSKowalski, Kamil                 }
1693927a505aSKowalski, Kamil 
1694*4a0cb85cSEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, patchReq, ethData,
1695*4a0cb85cSEd Tanous                                                    asyncResp);
1696927a505aSKowalski, Kamil             });
1697e439f0f8SKowalski, Kamil     }
1698e439f0f8SKowalski, Kamil 
169955c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
17001abe55efSEd Tanous                   const std::vector<std::string> &params) override
17011abe55efSEd Tanous     {
1702*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17031abe55efSEd Tanous         if (params.size() != 2)
17041abe55efSEd Tanous         {
1705*4a0cb85cSEd Tanous             asyncResp->res.result(
1706*4a0cb85cSEd Tanous                 boost::beast::http::status::internal_server_error);
1707e439f0f8SKowalski, Kamil             return;
1708e439f0f8SKowalski, Kamil         }
1709e439f0f8SKowalski, Kamil 
1710d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
171155c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1712927a505aSKowalski, Kamil 
1713*4a0cb85cSEd Tanous         if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
17141abe55efSEd Tanous         {
1715927a505aSKowalski, Kamil             return;
1716927a505aSKowalski, Kamil         }
1717927a505aSKowalski, Kamil 
1718927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1719927a505aSKowalski, Kamil         // preparation
1720*4a0cb85cSEd Tanous         getEthernetIfaceData(ifaceId, [this, asyncResp,
1721*4a0cb85cSEd Tanous                                        parentIfaceId{
1722*4a0cb85cSEd Tanous                                            std::string(parentIfaceId)},
1723*4a0cb85cSEd Tanous                                        ifaceId{std::string(ifaceId)}](
1724*4a0cb85cSEd Tanous                                           const bool &success,
1725*4a0cb85cSEd Tanous                                           const EthernetInterfaceData &ethData,
1726*4a0cb85cSEd Tanous                                           const boost::container::flat_set<
1727*4a0cb85cSEd Tanous                                               IPv4AddressData> &ipv4Data) {
1728*4a0cb85cSEd Tanous             if (success && ethData.vlan_id)
17291abe55efSEd Tanous             {
1730*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue = parseInterfaceData(
1731*4a0cb85cSEd Tanous                     parentIfaceId, ifaceId, ethData, ipv4Data);
1732927a505aSKowalski, Kamil 
1733*4a0cb85cSEd Tanous                 auto callback = [asyncResp](
1734*4a0cb85cSEd Tanous                                     const boost::system::error_code ec) {
17351abe55efSEd Tanous                     if (ec)
17361abe55efSEd Tanous                     {
17371abe55efSEd Tanous                         messages::addMessageToErrorJson(
1738*4a0cb85cSEd Tanous                             asyncResp->res.jsonValue,
1739*4a0cb85cSEd Tanous                             messages::internalError());
1740*4a0cb85cSEd Tanous                         asyncResp->res.result(
1741*4a0cb85cSEd Tanous                             boost::beast::http::status::internal_server_error);
1742927a505aSKowalski, Kamil                     }
1743*4a0cb85cSEd Tanous                 };
1744*4a0cb85cSEd Tanous                 crow::connections::systemBus->async_method_call(
1745*4a0cb85cSEd Tanous                     std::move(callback), "xyz.openbmc_project.Network",
1746*4a0cb85cSEd Tanous                     std::string("/xyz/openbmc_project/network/") + ifaceId,
1747*4a0cb85cSEd Tanous                     "xyz.openbmc_project.Object.Delete", "Delete");
17481abe55efSEd Tanous             }
17491abe55efSEd Tanous             else
17501abe55efSEd Tanous             {
1751927a505aSKowalski, Kamil                 // ... otherwise return error
1752*4a0cb85cSEd Tanous                 // TODO(Pawel)consider distinguish between non existing object,
1753*4a0cb85cSEd Tanous                 // and
1754*4a0cb85cSEd Tanous                 // other errors
1755927a505aSKowalski, Kamil                 messages::addMessageToErrorJson(
1756*4a0cb85cSEd Tanous                     asyncResp->res.jsonValue,
1757*4a0cb85cSEd Tanous                     messages::resourceNotFound("VLAN Network Interface",
1758*4a0cb85cSEd Tanous                                                ifaceId));
1759*4a0cb85cSEd Tanous                 asyncResp->res.result(boost::beast::http::status::not_found);
1760*4a0cb85cSEd Tanous                 asyncResp->res.end();
1761927a505aSKowalski, Kamil             }
1762927a505aSKowalski, Kamil         });
1763e439f0f8SKowalski, Kamil     }
1764e439f0f8SKowalski, Kamil };
1765e439f0f8SKowalski, Kamil 
1766e439f0f8SKowalski, Kamil /**
1767e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1768e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1769e439f0f8SKowalski, Kamil  */
17701abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
17711abe55efSEd Tanous {
1772e439f0f8SKowalski, Kamil   public:
1773e439f0f8SKowalski, Kamil     template <typename CrowApp>
17741abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
1775*4a0cb85cSEd Tanous     // one manager called openbmc.  This shall be generic, but requires to
1776*4a0cb85cSEd Tanous     // update GetSubroutes method
17771abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
1778*4a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
1779*4a0cb85cSEd Tanous              std::string())
17801abe55efSEd Tanous     {
1781e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1782e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1783e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1784e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata"
1785e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1786e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface Collection";
1787e439f0f8SKowalski, Kamil 
1788e439f0f8SKowalski, Kamil         entityPrivileges = {
1789e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1790e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1791e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1792e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1793e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1794e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1795e439f0f8SKowalski, Kamil     }
1796e439f0f8SKowalski, Kamil 
1797e439f0f8SKowalski, Kamil   private:
1798e439f0f8SKowalski, Kamil     /**
1799e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1800e439f0f8SKowalski, Kamil      */
180155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
18021abe55efSEd Tanous                const std::vector<std::string> &params) override
18031abe55efSEd Tanous     {
1804*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18051abe55efSEd Tanous         if (params.size() != 1)
18061abe55efSEd Tanous         {
1807e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1808*4a0cb85cSEd Tanous             asyncResp->res.result(
1809*4a0cb85cSEd Tanous                 boost::beast::http::status::internal_server_error);
1810e439f0f8SKowalski, Kamil             return;
1811e439f0f8SKowalski, Kamil         }
1812e439f0f8SKowalski, Kamil 
1813*4a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1814e439f0f8SKowalski, Kamil 
1815*4a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
18161abe55efSEd Tanous         // preparation
1817*4a0cb85cSEd Tanous         getEthernetIfaceList([this, asyncResp,
1818*4a0cb85cSEd Tanous                               rootInterfaceName{
1819*4a0cb85cSEd Tanous                                   std::string(rootInterfaceName)}](
18201abe55efSEd Tanous                                  const bool &success,
18211abe55efSEd Tanous                                  const std::vector<std::string> &iface_list) {
1822*4a0cb85cSEd Tanous             if (!success)
18231abe55efSEd Tanous             {
1824*4a0cb85cSEd Tanous                 asyncResp->res.result(
1825*4a0cb85cSEd Tanous                     boost::beast::http::status::internal_server_error);
1826*4a0cb85cSEd Tanous                 return;
18271abe55efSEd Tanous             }
1828*4a0cb85cSEd Tanous             asyncResp->res.jsonValue = Node::json;
1829*4a0cb85cSEd Tanous 
1830*4a0cb85cSEd Tanous             nlohmann::json iface_array = nlohmann::json::array();
1831*4a0cb85cSEd Tanous 
1832*4a0cb85cSEd Tanous             for (const std::string &iface_item : iface_list)
18331abe55efSEd Tanous             {
1834*4a0cb85cSEd Tanous                 if (boost::starts_with(iface_item, rootInterfaceName + "_"))
1835*4a0cb85cSEd Tanous                 {
1836*4a0cb85cSEd Tanous                     iface_array.push_back(
1837*4a0cb85cSEd Tanous                         {{"@odata.id",
1838*4a0cb85cSEd Tanous                           "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1839*4a0cb85cSEd Tanous                               rootInterfaceName + "/VLANs/" + iface_item}});
1840e439f0f8SKowalski, Kamil                 }
1841e439f0f8SKowalski, Kamil             }
1842e439f0f8SKowalski, Kamil 
1843*4a0cb85cSEd Tanous             if (iface_array.empty())
18441abe55efSEd Tanous             {
1845e439f0f8SKowalski, Kamil                 messages::addMessageToErrorJson(
1846*4a0cb85cSEd Tanous                     asyncResp->res.jsonValue,
18471abe55efSEd Tanous                     messages::resourceNotFound("EthernetInterface",
1848e439f0f8SKowalski, Kamil                                                rootInterfaceName));
1849*4a0cb85cSEd Tanous                 asyncResp->res.result(boost::beast::http::status::not_found);
1850*4a0cb85cSEd Tanous                 return;
1851e439f0f8SKowalski, Kamil             }
1852*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["Members@odata.count"] =
1853*4a0cb85cSEd Tanous                 iface_array.size();
1854*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["Members"] = std::move(iface_array);
1855*4a0cb85cSEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
1856*4a0cb85cSEd Tanous                 "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1857*4a0cb85cSEd Tanous                 rootInterfaceName + "/VLANs";
1858e439f0f8SKowalski, Kamil         });
1859e439f0f8SKowalski, Kamil     }
1860e439f0f8SKowalski, Kamil 
186155c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
18621abe55efSEd Tanous                 const std::vector<std::string> &params) override
18631abe55efSEd Tanous     {
1864*4a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18651abe55efSEd Tanous         if (params.size() != 1)
18661abe55efSEd Tanous         {
1867*4a0cb85cSEd Tanous             asyncResp->res.result(
1868*4a0cb85cSEd Tanous                 boost::beast::http::status::internal_server_error);
1869e439f0f8SKowalski, Kamil             return;
1870e439f0f8SKowalski, Kamil         }
1871e439f0f8SKowalski, Kamil 
1872e439f0f8SKowalski, Kamil         nlohmann::json postReq;
18731abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, postReq))
18741abe55efSEd Tanous         {
1875e439f0f8SKowalski, Kamil             return;
1876e439f0f8SKowalski, Kamil         }
1877e439f0f8SKowalski, Kamil 
1878*4a0cb85cSEd Tanous         auto vlanIdJson = json.find("VLANId");
1879*4a0cb85cSEd Tanous         if (vlanIdJson == json.end())
18801abe55efSEd Tanous         {
1881*4a0cb85cSEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
1882*4a0cb85cSEd Tanous                                        messages::propertyMissing("VLANId"),
1883*4a0cb85cSEd Tanous                                        "/VLANId");
1884e439f0f8SKowalski, Kamil             return;
1885e439f0f8SKowalski, Kamil         }
1886e439f0f8SKowalski, Kamil 
1887*4a0cb85cSEd Tanous         const uint64_t *vlanId = vlanIdJson->get_ptr<const uint64_t *>();
1888*4a0cb85cSEd Tanous         if (vlanId == nullptr)
18891abe55efSEd Tanous         {
1890*4a0cb85cSEd Tanous             messages::addMessageToJson(
1891*4a0cb85cSEd Tanous                 asyncResp->res.jsonValue,
1892*4a0cb85cSEd Tanous                 messages::propertyValueTypeError(vlanIdJson->dump(), "VLANId"),
1893*4a0cb85cSEd Tanous                 "/VLANId");
1894*4a0cb85cSEd Tanous             return;
1895e439f0f8SKowalski, Kamil         }
1896*4a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1897e439f0f8SKowalski, Kamil 
1898*4a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
18991abe55efSEd Tanous             if (ec)
19001abe55efSEd Tanous             {
1901*4a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
1902*4a0cb85cSEd Tanous                 // phosphor-network responses
1903*4a0cb85cSEd Tanous                 messages::addMessageToErrorJson(asyncResp->res.jsonValue,
19048ceb2ecaSEd Tanous                                                 messages::internalError());
1905*4a0cb85cSEd Tanous                 return;
19061abe55efSEd Tanous             }
1907*4a0cb85cSEd Tanous             asyncResp->res.result(boost::beast::http::status::created);
1908*4a0cb85cSEd Tanous             messages::addMessageToErrorJson(asyncResp->res.jsonValue,
1909*4a0cb85cSEd Tanous                                             messages::created());
1910e439f0f8SKowalski, Kamil         };
1911*4a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
1912*4a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
1913*4a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
1914*4a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
1915*4a0cb85cSEd Tanous             rootInterfaceName, static_cast<uint32_t>(*vlanId));
1916*4a0cb85cSEd Tanous     }
1917*4a0cb85cSEd Tanous };
19189391bb9cSRapkiewicz, Pawel } // namespace redfish
1919