xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 95f8646e9c27d6c3e3e549b0f1b0073f05caeb8b)
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>
194a0cb85cSEd Tanous #include <boost/container/flat_set.hpp>
20179db1d7SKowalski, Kamil #include <dbus_singleton.hpp>
21588c3f0dSKowalski, Kamil #include <error_messages.hpp>
22179db1d7SKowalski, Kamil #include <node.hpp>
23a24526dcSEd Tanous #include <optional>
24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp>
25abf2add6SEd Tanous #include <variant>
269391bb9cSRapkiewicz, Pawel 
271abe55efSEd Tanous namespace redfish
281abe55efSEd Tanous {
299391bb9cSRapkiewicz, Pawel 
309391bb9cSRapkiewicz, Pawel /**
319391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
329391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
339391bb9cSRapkiewicz, Pawel  */
34aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
35abf2add6SEd Tanous     std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36aa2e59c1SEd Tanous                               int32_t, uint32_t, int64_t, uint64_t, double>>;
379391bb9cSRapkiewicz, Pawel 
384a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair<
39aa2e59c1SEd Tanous     sdbusplus::message::object_path,
404a0cb85cSEd Tanous     std::vector<std::pair<
41aa2e59c1SEd Tanous         std::string,
42aa2e59c1SEd Tanous         boost::container::flat_map<
43029573d4SEd Tanous             std::string, sdbusplus::message::variant<
44029573d4SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
45029573d4SEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double,
46029573d4SEd Tanous                              std::vector<std::string>>>>>>>;
474a0cb85cSEd Tanous 
484a0cb85cSEd Tanous enum class LinkType
494a0cb85cSEd Tanous {
504a0cb85cSEd Tanous     Local,
514a0cb85cSEd Tanous     Global
524a0cb85cSEd Tanous };
539391bb9cSRapkiewicz, Pawel 
549391bb9cSRapkiewicz, Pawel /**
559391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
569391bb9cSRapkiewicz, Pawel  */
571abe55efSEd Tanous struct IPv4AddressData
581abe55efSEd Tanous {
59179db1d7SKowalski, Kamil     std::string id;
604a0cb85cSEd Tanous     std::string address;
614a0cb85cSEd Tanous     std::string domain;
624a0cb85cSEd Tanous     std::string gateway;
639391bb9cSRapkiewicz, Pawel     std::string netmask;
649391bb9cSRapkiewicz, Pawel     std::string origin;
654a0cb85cSEd Tanous     LinkType linktype;
664a0cb85cSEd Tanous 
671abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
681abe55efSEd Tanous     {
694a0cb85cSEd Tanous         return id < obj.id;
701abe55efSEd Tanous     }
719391bb9cSRapkiewicz, Pawel };
729391bb9cSRapkiewicz, Pawel 
739391bb9cSRapkiewicz, Pawel /**
74e48c0fc5SRavi Teja  * Structure for keeping IPv6 data required by Redfish
75e48c0fc5SRavi Teja  */
76e48c0fc5SRavi Teja struct IPv6AddressData
77e48c0fc5SRavi Teja {
78e48c0fc5SRavi Teja     std::string id;
79e48c0fc5SRavi Teja     std::string address;
80e48c0fc5SRavi Teja     std::string origin;
81e48c0fc5SRavi Teja     uint8_t prefixLength;
82e48c0fc5SRavi Teja 
83e48c0fc5SRavi Teja     bool operator<(const IPv6AddressData &obj) const
84e48c0fc5SRavi Teja     {
85e48c0fc5SRavi Teja         return id < obj.id;
86e48c0fc5SRavi Teja     }
87e48c0fc5SRavi Teja };
88e48c0fc5SRavi Teja /**
899391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
909391bb9cSRapkiewicz, Pawel  * available from DBus
919391bb9cSRapkiewicz, Pawel  */
921abe55efSEd Tanous struct EthernetInterfaceData
931abe55efSEd Tanous {
944a0cb85cSEd Tanous     uint32_t speed;
954a0cb85cSEd Tanous     bool auto_neg;
962a133282Smanojkiraneda     bool DHCPEnabled;
974a0cb85cSEd Tanous     std::string hostname;
984a0cb85cSEd Tanous     std::string default_gateway;
999a6fc6feSRavi Teja     std::string ipv6_default_gateway;
1004a0cb85cSEd Tanous     std::string mac_address;
101fda13ad2SSunitha Harish     std::vector<std::uint32_t> vlan_id;
102029573d4SEd Tanous     std::vector<std::string> nameservers;
103d24bfc7aSJennifer Lee     std::vector<std::string> domainnames;
1049391bb9cSRapkiewicz, Pawel };
1059391bb9cSRapkiewicz, Pawel 
1069391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
1079391bb9cSRapkiewicz, Pawel // into full dot notation
1081abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
1091abe55efSEd Tanous {
1109391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
1119391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
1129391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
1139391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
1149391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
1159391bb9cSRapkiewicz, Pawel     return netmask;
1169391bb9cSRapkiewicz, Pawel }
1179391bb9cSRapkiewicz, Pawel 
1184a0cb85cSEd Tanous inline std::string
1194a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1204a0cb85cSEd Tanous                                         bool isIPv4)
1211abe55efSEd Tanous {
1224a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1231abe55efSEd Tanous     {
1244a0cb85cSEd Tanous         return "Static";
1259391bb9cSRapkiewicz, Pawel     }
1264a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1271abe55efSEd Tanous     {
1284a0cb85cSEd Tanous         if (isIPv4)
1291abe55efSEd Tanous         {
1304a0cb85cSEd Tanous             return "IPv4LinkLocal";
1311abe55efSEd Tanous         }
1321abe55efSEd Tanous         else
1331abe55efSEd Tanous         {
1344a0cb85cSEd Tanous             return "LinkLocal";
1359391bb9cSRapkiewicz, Pawel         }
1369391bb9cSRapkiewicz, Pawel     }
1374a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1381abe55efSEd Tanous     {
1394a0cb85cSEd Tanous         if (isIPv4)
1404a0cb85cSEd Tanous         {
1414a0cb85cSEd Tanous             return "DHCP";
1424a0cb85cSEd Tanous         }
1434a0cb85cSEd Tanous         else
1444a0cb85cSEd Tanous         {
1454a0cb85cSEd Tanous             return "DHCPv6";
1464a0cb85cSEd Tanous         }
1474a0cb85cSEd Tanous     }
1484a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1494a0cb85cSEd Tanous     {
1504a0cb85cSEd Tanous         return "SLAAC";
1514a0cb85cSEd Tanous     }
1524a0cb85cSEd Tanous     return "";
1534a0cb85cSEd Tanous }
1544a0cb85cSEd Tanous 
1554c9afe43SEd Tanous inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
1564a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1574a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1584a0cb85cSEd Tanous {
1594c9afe43SEd Tanous     bool idFound = false;
1604a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1614a0cb85cSEd Tanous     {
1624a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1634a0cb85cSEd Tanous         {
164029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
165029573d4SEd Tanous             {
1664c9afe43SEd Tanous                 idFound = true;
1674a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1684a0cb85cSEd Tanous                 {
1694a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1704a0cb85cSEd Tanous                     {
1714a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1724a0cb85cSEd Tanous                         {
1734a0cb85cSEd Tanous                             const std::string *mac =
174abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1754a0cb85cSEd Tanous                             if (mac != nullptr)
1764a0cb85cSEd Tanous                             {
1774a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1784a0cb85cSEd Tanous                             }
1794a0cb85cSEd Tanous                         }
1804a0cb85cSEd Tanous                     }
1814a0cb85cSEd Tanous                 }
1824a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1834a0cb85cSEd Tanous                 {
1844a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1854a0cb85cSEd Tanous                     {
1864a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1874a0cb85cSEd Tanous                         {
1881b6b96c5SEd Tanous                             const uint32_t *id =
189abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1904a0cb85cSEd Tanous                             if (id != nullptr)
1914a0cb85cSEd Tanous                             {
192fda13ad2SSunitha Harish                                 ethData.vlan_id.push_back(*id);
1934a0cb85cSEd Tanous                             }
1944a0cb85cSEd Tanous                         }
1954a0cb85cSEd Tanous                     }
1964a0cb85cSEd Tanous                 }
1974a0cb85cSEd Tanous                 else if (ifacePair.first ==
1984a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
1994a0cb85cSEd Tanous                 {
2004a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2014a0cb85cSEd Tanous                     {
2024a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2034a0cb85cSEd Tanous                         {
2044a0cb85cSEd Tanous                             const bool *auto_neg =
205abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2064a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2074a0cb85cSEd Tanous                             {
2084a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2094a0cb85cSEd Tanous                             }
2104a0cb85cSEd Tanous                         }
2114a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2124a0cb85cSEd Tanous                         {
2134a0cb85cSEd Tanous                             const uint32_t *speed =
214abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2154a0cb85cSEd Tanous                             if (speed != nullptr)
2164a0cb85cSEd Tanous                             {
2174a0cb85cSEd Tanous                                 ethData.speed = *speed;
2184a0cb85cSEd Tanous                             }
2194a0cb85cSEd Tanous                         }
220f85837bfSRAJESWARAN THILLAIGOVINDAN                         else if (propertyPair.first == "Nameservers")
221029573d4SEd Tanous                         {
222029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
223029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
224029573d4SEd Tanous                                     std::vector<std::string>>(
225029573d4SEd Tanous                                     &propertyPair.second);
226029573d4SEd Tanous                             if (nameservers != nullptr)
227029573d4SEd Tanous                             {
228029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2294a0cb85cSEd Tanous                             }
2304a0cb85cSEd Tanous                         }
2312a133282Smanojkiraneda                         else if (propertyPair.first == "DHCPEnabled")
2322a133282Smanojkiraneda                         {
2332a133282Smanojkiraneda                             const bool *DHCPEnabled =
2342a133282Smanojkiraneda                                 std::get_if<bool>(&propertyPair.second);
2352a133282Smanojkiraneda                             if (DHCPEnabled != nullptr)
2362a133282Smanojkiraneda                             {
2372a133282Smanojkiraneda                                 ethData.DHCPEnabled = *DHCPEnabled;
2382a133282Smanojkiraneda                             }
2392a133282Smanojkiraneda                         }
240d24bfc7aSJennifer Lee                         else if (propertyPair.first == "DomainName")
241d24bfc7aSJennifer Lee                         {
242d24bfc7aSJennifer Lee                             const std::vector<std::string> *domainNames =
243d24bfc7aSJennifer Lee                                 sdbusplus::message::variant_ns::get_if<
244d24bfc7aSJennifer Lee                                     std::vector<std::string>>(
245d24bfc7aSJennifer Lee                                     &propertyPair.second);
246d24bfc7aSJennifer Lee                             if (domainNames != nullptr)
247d24bfc7aSJennifer Lee                             {
248d24bfc7aSJennifer Lee                                 ethData.domainnames = std::move(*domainNames);
249d24bfc7aSJennifer Lee                             }
250d24bfc7aSJennifer Lee                         }
251029573d4SEd Tanous                     }
252029573d4SEd Tanous                 }
253029573d4SEd Tanous             }
254029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
255029573d4SEd Tanous             // to check eth number
256029573d4SEd Tanous             if (ifacePair.first ==
2574a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2584a0cb85cSEd Tanous             {
2594a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2604a0cb85cSEd Tanous                 {
2614a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2624a0cb85cSEd Tanous                     {
2634a0cb85cSEd Tanous                         const std::string *hostname =
264029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
265029573d4SEd Tanous                                 &propertyPair.second);
2664a0cb85cSEd Tanous                         if (hostname != nullptr)
2674a0cb85cSEd Tanous                         {
2684a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2694a0cb85cSEd Tanous                         }
2704a0cb85cSEd Tanous                     }
2714a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2724a0cb85cSEd Tanous                     {
2734a0cb85cSEd Tanous                         const std::string *defaultGateway =
274029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
275029573d4SEd Tanous                                 &propertyPair.second);
2764a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2774a0cb85cSEd Tanous                         {
2784a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2794a0cb85cSEd Tanous                         }
2804a0cb85cSEd Tanous                     }
2819a6fc6feSRavi Teja                     else if (propertyPair.first == "DefaultGateway6")
2829a6fc6feSRavi Teja                     {
2839a6fc6feSRavi Teja                         const std::string *defaultGateway6 =
2849a6fc6feSRavi Teja                             sdbusplus::message::variant_ns::get_if<std::string>(
2859a6fc6feSRavi Teja                                 &propertyPair.second);
2869a6fc6feSRavi Teja                         if (defaultGateway6 != nullptr)
2879a6fc6feSRavi Teja                         {
2889a6fc6feSRavi Teja                             ethData.ipv6_default_gateway = *defaultGateway6;
2899a6fc6feSRavi Teja                         }
2909a6fc6feSRavi Teja                     }
2914a0cb85cSEd Tanous                 }
2924a0cb85cSEd Tanous             }
2934a0cb85cSEd Tanous         }
2944a0cb85cSEd Tanous     }
2954c9afe43SEd Tanous     return idFound;
2964a0cb85cSEd Tanous }
2974a0cb85cSEd Tanous 
298e48c0fc5SRavi Teja // Helper function that extracts data for single ethernet ipv6 address
299e48c0fc5SRavi Teja inline void extractIPV6Data(
300e48c0fc5SRavi Teja     const std::string &ethiface_id, const GetManagedObjects &dbus_data,
301e48c0fc5SRavi Teja     boost::container::flat_set<IPv6AddressData> &ipv6_config,
302e48c0fc5SRavi Teja     boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
303e48c0fc5SRavi Teja {
304e48c0fc5SRavi Teja     const std::string ipv6PathStart =
305e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
306e48c0fc5SRavi Teja 
307e48c0fc5SRavi Teja     // Since there might be several IPv6 configurations aligned with
308e48c0fc5SRavi Teja     // single ethernet interface, loop over all of them
309e48c0fc5SRavi Teja     for (const auto &objpath : dbus_data)
310e48c0fc5SRavi Teja     {
311e48c0fc5SRavi Teja         // Check if proper pattern for object path appears
312e48c0fc5SRavi Teja         if (boost::starts_with(objpath.first.str, ipv6PathStart))
313e48c0fc5SRavi Teja         {
314e48c0fc5SRavi Teja             for (auto &interface : objpath.second)
315e48c0fc5SRavi Teja             {
316e48c0fc5SRavi Teja                 if (interface.first == "xyz.openbmc_project.Network.IP")
317e48c0fc5SRavi Teja                 {
318e48c0fc5SRavi Teja                     // Instance IPv6AddressData structure, and set as
319e48c0fc5SRavi Teja                     // appropriate
320e48c0fc5SRavi Teja                     std::pair<
321e48c0fc5SRavi Teja                         boost::container::flat_set<IPv6AddressData>::iterator,
322e48c0fc5SRavi Teja                         bool>
323e48c0fc5SRavi Teja                         it = ipv6_config.insert(
324e48c0fc5SRavi Teja                             {objpath.first.str.substr(ipv6PathStart.size())});
325e48c0fc5SRavi Teja                     IPv6AddressData &ipv6_address = *it.first;
326e48c0fc5SRavi Teja                     for (auto &property : interface.second)
327e48c0fc5SRavi Teja                     {
328e48c0fc5SRavi Teja                         if (property.first == "Address")
329e48c0fc5SRavi Teja                         {
330e48c0fc5SRavi Teja                             const std::string *address =
331e48c0fc5SRavi Teja                                 std::get_if<std::string>(&property.second);
332e48c0fc5SRavi Teja                             if (address != nullptr)
333e48c0fc5SRavi Teja                             {
334e48c0fc5SRavi Teja                                 ipv6_address.address = *address;
335e48c0fc5SRavi Teja                             }
336e48c0fc5SRavi Teja                         }
337e48c0fc5SRavi Teja                         else if (property.first == "Origin")
338e48c0fc5SRavi Teja                         {
339e48c0fc5SRavi Teja                             const std::string *origin =
340e48c0fc5SRavi Teja                                 std::get_if<std::string>(&property.second);
341e48c0fc5SRavi Teja                             if (origin != nullptr)
342e48c0fc5SRavi Teja                             {
343e48c0fc5SRavi Teja                                 ipv6_address.origin =
344e48c0fc5SRavi Teja                                     translateAddressOriginDbusToRedfish(*origin,
345e48c0fc5SRavi Teja                                                                         false);
346e48c0fc5SRavi Teja                             }
347e48c0fc5SRavi Teja                         }
348e48c0fc5SRavi Teja                         else if (property.first == "PrefixLength")
349e48c0fc5SRavi Teja                         {
350e48c0fc5SRavi Teja                             const uint8_t *prefix =
351e48c0fc5SRavi Teja                                 std::get_if<uint8_t>(&property.second);
352e48c0fc5SRavi Teja                             if (prefix != nullptr)
353e48c0fc5SRavi Teja                             {
354e48c0fc5SRavi Teja                                 ipv6_address.prefixLength = *prefix;
355e48c0fc5SRavi Teja                             }
356e48c0fc5SRavi Teja                         }
357e48c0fc5SRavi Teja                         else
358e48c0fc5SRavi Teja                         {
359e48c0fc5SRavi Teja                             BMCWEB_LOG_ERROR
360e48c0fc5SRavi Teja                                 << "Got extra property: " << property.first
361e48c0fc5SRavi Teja                                 << " on the " << objpath.first.str << " object";
362e48c0fc5SRavi Teja                         }
363e48c0fc5SRavi Teja                     }
364e48c0fc5SRavi Teja                     if (ipv6_address.origin == "Static")
365e48c0fc5SRavi Teja                     {
366e48c0fc5SRavi Teja                         std::pair<boost::container::flat_set<
367e48c0fc5SRavi Teja                                       IPv6AddressData>::iterator,
368e48c0fc5SRavi Teja                                   bool>
369e48c0fc5SRavi Teja                             iter = ipv6_static_config.insert(
370e48c0fc5SRavi Teja                                 {objpath.first.str.substr(
371e48c0fc5SRavi Teja                                     ipv6PathStart.size())});
372e48c0fc5SRavi Teja                         IPv6AddressData &ipv6_static_address = *iter.first;
373e48c0fc5SRavi Teja 
374e48c0fc5SRavi Teja                         ipv6_static_address.address = ipv6_address.address;
375e48c0fc5SRavi Teja                         ipv6_static_address.prefixLength =
376e48c0fc5SRavi Teja                             ipv6_address.prefixLength;
377e48c0fc5SRavi Teja                     }
378e48c0fc5SRavi Teja                 }
379e48c0fc5SRavi Teja             }
380e48c0fc5SRavi Teja         }
381e48c0fc5SRavi Teja     }
382e48c0fc5SRavi Teja }
383e48c0fc5SRavi Teja 
3844a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
385d1d50814SRavi Teja inline void extractIPData(
386d1d50814SRavi Teja     const std::string &ethiface_id, const GetManagedObjects &dbus_data,
387d1d50814SRavi Teja     boost::container::flat_set<IPv4AddressData> &ipv4_config,
388d1d50814SRavi Teja     boost::container::flat_set<IPv4AddressData> &ipv4_static_config)
3894a0cb85cSEd Tanous {
3904a0cb85cSEd Tanous     const std::string ipv4PathStart =
3914a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
3924a0cb85cSEd Tanous 
3934a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
3944a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
3954a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
3964a0cb85cSEd Tanous     {
3974a0cb85cSEd Tanous         // Check if proper pattern for object path appears
3984a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
3994a0cb85cSEd Tanous         {
4004a0cb85cSEd Tanous             for (auto &interface : objpath.second)
4014a0cb85cSEd Tanous             {
4024a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
4034a0cb85cSEd Tanous                 {
4044a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
4054a0cb85cSEd Tanous                     // appropriate
4064a0cb85cSEd Tanous                     std::pair<
4074a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
4084a0cb85cSEd Tanous                         bool>
4094a0cb85cSEd Tanous                         it = ipv4_config.insert(
410b01bf299SEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
4114a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
4124a0cb85cSEd Tanous                     for (auto &property : interface.second)
4134a0cb85cSEd Tanous                     {
4144a0cb85cSEd Tanous                         if (property.first == "Address")
4154a0cb85cSEd Tanous                         {
4164a0cb85cSEd Tanous                             const std::string *address =
417abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4184a0cb85cSEd Tanous                             if (address != nullptr)
4194a0cb85cSEd Tanous                             {
4204a0cb85cSEd Tanous                                 ipv4_address.address = *address;
4214a0cb85cSEd Tanous                             }
4224a0cb85cSEd Tanous                         }
4234a0cb85cSEd Tanous                         else if (property.first == "Gateway")
4244a0cb85cSEd Tanous                         {
4254a0cb85cSEd Tanous                             const std::string *gateway =
426abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4274a0cb85cSEd Tanous                             if (gateway != nullptr)
4284a0cb85cSEd Tanous                             {
4294a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
4304a0cb85cSEd Tanous                             }
4314a0cb85cSEd Tanous                         }
4324a0cb85cSEd Tanous                         else if (property.first == "Origin")
4334a0cb85cSEd Tanous                         {
4344a0cb85cSEd Tanous                             const std::string *origin =
435abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4364a0cb85cSEd Tanous                             if (origin != nullptr)
4374a0cb85cSEd Tanous                             {
4384a0cb85cSEd Tanous                                 ipv4_address.origin =
4394a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
4404a0cb85cSEd Tanous                                                                         true);
4414a0cb85cSEd Tanous                             }
4424a0cb85cSEd Tanous                         }
4434a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
4444a0cb85cSEd Tanous                         {
4454a0cb85cSEd Tanous                             const uint8_t *mask =
446abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
4474a0cb85cSEd Tanous                             if (mask != nullptr)
4484a0cb85cSEd Tanous                             {
4494a0cb85cSEd Tanous                                 // convert it to the string
4504a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
4514a0cb85cSEd Tanous                             }
4524a0cb85cSEd Tanous                         }
4534a0cb85cSEd Tanous                         else
4544a0cb85cSEd Tanous                         {
4554a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
4564a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
4574a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
4584a0cb85cSEd Tanous                         }
4594a0cb85cSEd Tanous                     }
460d1d50814SRavi Teja 
461d1d50814SRavi Teja                     if (ipv4_address.origin == "Static")
462d1d50814SRavi Teja                     {
463d1d50814SRavi Teja                         IPv4AddressData ipv4_static_address = {
464d1d50814SRavi Teja                             objpath.first.str.substr(ipv4PathStart.size())};
465d1d50814SRavi Teja                         ipv4_static_address.address = ipv4_address.address;
466d1d50814SRavi Teja                         ipv4_static_address.gateway = ipv4_address.gateway;
467d1d50814SRavi Teja                         ipv4_static_address.netmask = ipv4_address.netmask;
468d1d50814SRavi Teja                         ipv4_static_config.emplace(ipv4_static_address);
469d1d50814SRavi Teja                     }
470d1d50814SRavi Teja 
4714a0cb85cSEd Tanous                     // Check if given address is local, or global
4724a0cb85cSEd Tanous                     ipv4_address.linktype =
4734a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
47418659d10SJohnathan Mantey                             ? LinkType::Local
47518659d10SJohnathan Mantey                             : LinkType::Global;
4764a0cb85cSEd Tanous                 }
4774a0cb85cSEd Tanous             }
4784a0cb85cSEd Tanous         }
4794a0cb85cSEd Tanous     }
4804a0cb85cSEd Tanous }
481588c3f0dSKowalski, Kamil 
482588c3f0dSKowalski, Kamil /**
483588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
484588c3f0dSKowalski, Kamil  *
485588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
486588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
487588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
488588c3f0dSKowalski, Kamil  *
489588c3f0dSKowalski, Kamil  * @return None.
490588c3f0dSKowalski, Kamil  */
491588c3f0dSKowalski, Kamil template <typename CallbackFunc>
4924a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
4931abe55efSEd Tanous                   CallbackFunc &&callback)
4941abe55efSEd Tanous {
49555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
496588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
497588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
498588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
499588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
500abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
5014a0cb85cSEd Tanous }
502588c3f0dSKowalski, Kamil 
503588c3f0dSKowalski, Kamil /**
504179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
505179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
506179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
507179db1d7SKowalski, Kamil  *
508179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
509179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
510179db1d7SKowalski, Kamil  *
511179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
512179db1d7SKowalski, Kamil  */
5134a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
5141abe55efSEd Tanous                                        uint8_t *bits = nullptr)
5151abe55efSEd Tanous {
516179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
517179db1d7SKowalski, Kamil 
518179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
519179db1d7SKowalski, Kamil 
5204a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
5211abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
5221abe55efSEd Tanous     {
523179db1d7SKowalski, Kamil         return false;
524179db1d7SKowalski, Kamil     }
525179db1d7SKowalski, Kamil 
5261abe55efSEd Tanous     if (bits != nullptr)
5271abe55efSEd Tanous     {
528179db1d7SKowalski, Kamil         *bits = 0;
529179db1d7SKowalski, Kamil     }
530179db1d7SKowalski, Kamil 
531179db1d7SKowalski, Kamil     char *endPtr;
532179db1d7SKowalski, Kamil     long previousValue = 255;
533179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
5341abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
5351abe55efSEd Tanous     {
5361abe55efSEd Tanous         if (byte.empty())
5371abe55efSEd Tanous         {
5381db9ca37SKowalski, Kamil             return false;
5391db9ca37SKowalski, Kamil         }
5401db9ca37SKowalski, Kamil 
541179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
5421db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
543179db1d7SKowalski, Kamil 
5444a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
5454a0cb85cSEd Tanous         // is not 100% number
5461abe55efSEd Tanous         if (*endPtr != '\0')
5471abe55efSEd Tanous         {
548179db1d7SKowalski, Kamil             return false;
549179db1d7SKowalski, Kamil         }
550179db1d7SKowalski, Kamil 
551179db1d7SKowalski, Kamil         // Value should be contained in byte
5521abe55efSEd Tanous         if (value < 0 || value > 255)
5531abe55efSEd Tanous         {
554179db1d7SKowalski, Kamil             return false;
555179db1d7SKowalski, Kamil         }
556179db1d7SKowalski, Kamil 
5571abe55efSEd Tanous         if (bits != nullptr)
5581abe55efSEd Tanous         {
559179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
5601abe55efSEd Tanous             if (previousValue != 255 && value != 0)
5611abe55efSEd Tanous             {
562179db1d7SKowalski, Kamil                 return false;
563179db1d7SKowalski, Kamil             }
564179db1d7SKowalski, Kamil 
565179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
566179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
567179db1d7SKowalski, Kamil 
568179db1d7SKowalski, Kamil             // Count bits
5691abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
5701abe55efSEd Tanous             {
5711abe55efSEd Tanous                 if (value & (1 << bitIdx))
5721abe55efSEd Tanous                 {
5731abe55efSEd Tanous                     if (firstZeroInByteHit)
5741abe55efSEd Tanous                     {
575179db1d7SKowalski, Kamil                         // Continuity not preserved
576179db1d7SKowalski, Kamil                         return false;
5771abe55efSEd Tanous                     }
5781abe55efSEd Tanous                     else
5791abe55efSEd Tanous                     {
580179db1d7SKowalski, Kamil                         (*bits)++;
581179db1d7SKowalski, Kamil                     }
5821abe55efSEd Tanous                 }
5831abe55efSEd Tanous                 else
5841abe55efSEd Tanous                 {
585179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
586179db1d7SKowalski, Kamil                 }
587179db1d7SKowalski, Kamil             }
588179db1d7SKowalski, Kamil         }
589179db1d7SKowalski, Kamil 
590179db1d7SKowalski, Kamil         previousValue = value;
591179db1d7SKowalski, Kamil     }
592179db1d7SKowalski, Kamil 
593179db1d7SKowalski, Kamil     return true;
594179db1d7SKowalski, Kamil }
595179db1d7SKowalski, Kamil 
596179db1d7SKowalski, Kamil /**
597b01bf299SEd Tanous  * @brief Changes IPv4 address type property (Address, Gateway)
598b01bf299SEd Tanous  *
599b01bf299SEd Tanous  * @param[in] ifaceId     Id of interface whose IP should be modified
600b01bf299SEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
601b01bf299SEd Tanous  * @param[in] ipHash      DBus Hash id of modified IP
602b01bf299SEd Tanous  * @param[in] name        Name of field in JSON representation
603b01bf299SEd Tanous  * @param[in] newValue    New value that should be written
604b01bf299SEd Tanous  * @param[io] asyncResp   Response object that will be returned to client
605b01bf299SEd Tanous  *
606b01bf299SEd Tanous  * @return true if give IP is valid and has been sent do D-Bus, false
607b01bf299SEd Tanous  * otherwise
608b01bf299SEd Tanous  */
609b01bf299SEd Tanous inline void changeIPv4AddressProperty(
610b01bf299SEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
611b01bf299SEd Tanous     const std::string &name, const std::string &newValue,
612b01bf299SEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
613b01bf299SEd Tanous {
614286b9118SJohnathan Mantey     auto callback =
615286b9118SJohnathan Mantey         [asyncResp, ipIdx, name{std::string(name)},
616286b9118SJohnathan Mantey          newValue{std::move(newValue)}](const boost::system::error_code ec) {
617b01bf299SEd Tanous             if (ec)
618b01bf299SEd Tanous             {
619b01bf299SEd Tanous                 messages::internalError(asyncResp->res);
620b01bf299SEd Tanous             }
621b01bf299SEd Tanous         };
622b01bf299SEd Tanous 
623b01bf299SEd Tanous     crow::connections::systemBus->async_method_call(
624b01bf299SEd Tanous         std::move(callback), "xyz.openbmc_project.Network",
625b01bf299SEd Tanous         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
626b01bf299SEd Tanous         "org.freedesktop.DBus.Properties", "Set",
627b01bf299SEd Tanous         "xyz.openbmc_project.Network.IP", name,
628b01bf299SEd Tanous         std::variant<std::string>(newValue));
629b01bf299SEd Tanous }
630b01bf299SEd Tanous 
631b01bf299SEd Tanous /**
632179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
633179db1d7SKowalski, Kamil  *
634179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
6354a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
6361abe55efSEd Tanous  * modified
637179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
638179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
639179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
640179db1d7SKowalski, Kamil  *
641179db1d7SKowalski, Kamil  * @return None
642179db1d7SKowalski, Kamil  */
643b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
6444a0cb85cSEd Tanous                                          const std::string &ipHash,
6454a0cb85cSEd Tanous                                          uint8_t &newValue,
6464a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
6471abe55efSEd Tanous {
648286b9118SJohnathan Mantey     auto callback = [asyncResp, ipIdx](const boost::system::error_code ec) {
6491abe55efSEd Tanous         if (ec)
6501abe55efSEd Tanous         {
651a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
6521abe55efSEd Tanous         }
653179db1d7SKowalski, Kamil     };
654179db1d7SKowalski, Kamil 
65555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
656179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
657179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
658179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
659179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
660abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
6614a0cb85cSEd Tanous }
662588c3f0dSKowalski, Kamil 
663588c3f0dSKowalski, Kamil /**
664179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
665179db1d7SKowalski, Kamil  *
666179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
667179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
668179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
669179db1d7SKowalski, Kamil  *
670179db1d7SKowalski, Kamil  * @return None
671179db1d7SKowalski, Kamil  */
6724a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
6734a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6741abe55efSEd Tanous {
67555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
676286b9118SJohnathan Mantey         [asyncResp](const boost::system::error_code ec) {
6771abe55efSEd Tanous             if (ec)
6781abe55efSEd Tanous             {
679a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6801abe55efSEd Tanous             }
681179db1d7SKowalski, Kamil         },
682179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
683179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
684179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
685179db1d7SKowalski, Kamil }
686179db1d7SKowalski, Kamil 
687179db1d7SKowalski, Kamil /**
688179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
689179db1d7SKowalski, Kamil  *
690179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6914a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
692179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
693179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
694179db1d7SKowalski, Kamil  *
695179db1d7SKowalski, Kamil  * @return None
696179db1d7SKowalski, Kamil  */
697b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
698b01bf299SEd Tanous                        uint8_t subnetMask, const std::string &gateway,
699b01bf299SEd Tanous                        const std::string &address,
7004a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
7011abe55efSEd Tanous {
70243b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
7031abe55efSEd Tanous         if (ec)
7041abe55efSEd Tanous         {
705a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
706179db1d7SKowalski, Kamil         }
707179db1d7SKowalski, Kamil     };
708179db1d7SKowalski, Kamil 
70955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
710179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
711179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
712179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
713179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
714179db1d7SKowalski, Kamil         gateway);
715179db1d7SKowalski, Kamil }
716e48c0fc5SRavi Teja 
717e48c0fc5SRavi Teja /**
718e48c0fc5SRavi Teja  * @brief Deletes given IPv6
719e48c0fc5SRavi Teja  *
720e48c0fc5SRavi Teja  * @param[in] ifaceId     Id of interface whose IP should be deleted
721e48c0fc5SRavi Teja  * @param[in] ipHash      DBus Hash id of IP that should be deleted
722e48c0fc5SRavi Teja  * @param[io] asyncResp   Response object that will be returned to client
723e48c0fc5SRavi Teja  *
724e48c0fc5SRavi Teja  * @return None
725e48c0fc5SRavi Teja  */
726e48c0fc5SRavi Teja inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
727e48c0fc5SRavi Teja                        const std::shared_ptr<AsyncResp> asyncResp)
728e48c0fc5SRavi Teja {
729e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
730286b9118SJohnathan Mantey         [asyncResp](const boost::system::error_code ec) {
731e48c0fc5SRavi Teja             if (ec)
732e48c0fc5SRavi Teja             {
733e48c0fc5SRavi Teja                 messages::internalError(asyncResp->res);
734e48c0fc5SRavi Teja             }
735e48c0fc5SRavi Teja         },
736e48c0fc5SRavi Teja         "xyz.openbmc_project.Network",
737e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
738e48c0fc5SRavi Teja         "xyz.openbmc_project.Object.Delete", "Delete");
739e48c0fc5SRavi Teja }
740e48c0fc5SRavi Teja 
741e48c0fc5SRavi Teja /**
742e48c0fc5SRavi Teja  * @brief Creates IPv6 with given data
743e48c0fc5SRavi Teja  *
744e48c0fc5SRavi Teja  * @param[in] ifaceId      Id of interface whose IP should be added
745e48c0fc5SRavi Teja  * @param[in] ipIdx        Index of IP in input array that should be added
746e48c0fc5SRavi Teja  * @param[in] prefixLength Prefix length that needs to be added
747e48c0fc5SRavi Teja  * @param[in] address      IP address that needs to be added
748e48c0fc5SRavi Teja  * @param[io] asyncResp    Response object that will be returned to client
749e48c0fc5SRavi Teja  *
750e48c0fc5SRavi Teja  * @return None
751e48c0fc5SRavi Teja  */
752e48c0fc5SRavi Teja inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
753e48c0fc5SRavi Teja                        uint8_t prefixLength, const std::string &address,
754e48c0fc5SRavi Teja                        std::shared_ptr<AsyncResp> asyncResp)
755e48c0fc5SRavi Teja {
756e48c0fc5SRavi Teja     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
757e48c0fc5SRavi Teja         if (ec)
758e48c0fc5SRavi Teja         {
759e48c0fc5SRavi Teja             messages::internalError(asyncResp->res);
760e48c0fc5SRavi Teja         }
761e48c0fc5SRavi Teja     };
762e48c0fc5SRavi Teja     // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
763e48c0fc5SRavi Teja     // does not have assosiated gateway property
764e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
765e48c0fc5SRavi Teja         std::move(createIpHandler), "xyz.openbmc_project.Network",
766e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId,
767e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Create", "IP",
768e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
769e48c0fc5SRavi Teja         "");
770e48c0fc5SRavi Teja }
771e48c0fc5SRavi Teja 
7722a133282Smanojkiraneda using GetAllPropertiesType =
7732a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
7742a133282Smanojkiraneda 
7752a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
7762a133282Smanojkiraneda {
7772a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
7782a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
7792a133282Smanojkiraneda         if (error_code)
7802a133282Smanojkiraneda         {
7812a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
7822a133282Smanojkiraneda             messages::internalError(asyncResp->res);
7832a133282Smanojkiraneda             return;
7842a133282Smanojkiraneda         }
785fda13ad2SSunitha Harish         nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
7862a133282Smanojkiraneda         for (const auto &property : dbus_data)
7872a133282Smanojkiraneda         {
7882a133282Smanojkiraneda             auto value =
7892a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
7902a133282Smanojkiraneda 
7912a133282Smanojkiraneda             if (value == nullptr)
7922a133282Smanojkiraneda             {
7932a133282Smanojkiraneda                 continue;
7942a133282Smanojkiraneda             }
7952a133282Smanojkiraneda             if (property.first == "DNSEnabled")
7962a133282Smanojkiraneda             {
7972a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
7982a133282Smanojkiraneda             }
7992a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
8002a133282Smanojkiraneda             {
8012a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
8022a133282Smanojkiraneda             }
8032a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
8042a133282Smanojkiraneda             {
8052a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
8062a133282Smanojkiraneda             }
8072a133282Smanojkiraneda         }
8082a133282Smanojkiraneda     };
8092a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
8102a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
8112a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
8122a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
8132a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
8142a133282Smanojkiraneda }
815179db1d7SKowalski, Kamil 
816179db1d7SKowalski, Kamil /**
817179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
818179db1d7SKowalski, Kamil  * Object
819179db1d7SKowalski, Kamil  * from EntityManager Network Manager
8204a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
821179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
822179db1d7SKowalski, Kamil  * into JSON
823179db1d7SKowalski, Kamil  */
824179db1d7SKowalski, Kamil template <typename CallbackFunc>
8254a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
8261abe55efSEd Tanous                           CallbackFunc &&callback)
8271abe55efSEd Tanous {
82855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
8294a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
8301abe55efSEd Tanous             const boost::system::error_code error_code,
8314a0cb85cSEd Tanous             const GetManagedObjects &resp) {
83255c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
8334a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
834d1d50814SRavi Teja             boost::container::flat_set<IPv4AddressData> ipv4StaticData;
835e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6Data;
836e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6StaticData;
837179db1d7SKowalski, Kamil 
8381abe55efSEd Tanous             if (error_code)
8391abe55efSEd Tanous             {
840d1d50814SRavi Teja                 callback(false, ethData, ipv4Data, ipv4StaticData, ipv6Data,
841d1d50814SRavi Teja                          ipv6StaticData);
842179db1d7SKowalski, Kamil                 return;
843179db1d7SKowalski, Kamil             }
844179db1d7SKowalski, Kamil 
8454c9afe43SEd Tanous             bool found =
8464a0cb85cSEd Tanous                 extractEthernetInterfaceData(ethiface_id, resp, ethData);
8474c9afe43SEd Tanous             if (!found)
8484c9afe43SEd Tanous             {
849d1d50814SRavi Teja                 callback(false, ethData, ipv4Data, ipv4StaticData, ipv6Data,
850d1d50814SRavi Teja                          ipv6StaticData);
8514c9afe43SEd Tanous                 return;
8524c9afe43SEd Tanous             }
8534c9afe43SEd Tanous 
854d1d50814SRavi Teja             extractIPData(ethiface_id, resp, ipv4Data, ipv4StaticData);
855179db1d7SKowalski, Kamil             // Fix global GW
8561abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
8571abe55efSEd Tanous             {
858c619141bSRavi Teja                 if (((ipv4.linktype == LinkType::Global) &&
859c619141bSRavi Teja                      (ipv4.gateway == "0.0.0.0")) ||
860c619141bSRavi Teja                     (ipv4.origin == "DHCP"))
8611abe55efSEd Tanous                 {
8624a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
863179db1d7SKowalski, Kamil                 }
864179db1d7SKowalski, Kamil             }
865179db1d7SKowalski, Kamil 
866e48c0fc5SRavi Teja             extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
8674a0cb85cSEd Tanous             // Finally make a callback with usefull data
868d1d50814SRavi Teja             callback(true, ethData, ipv4Data, ipv4StaticData, ipv6Data,
869d1d50814SRavi Teja                      ipv6StaticData);
870179db1d7SKowalski, Kamil         },
871179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
872179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
873179db1d7SKowalski, Kamil };
874179db1d7SKowalski, Kamil 
875179db1d7SKowalski, Kamil /**
8769391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
8779391bb9cSRapkiewicz, Pawel  * Manager
8781abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
8791abe55efSEd Tanous  * into JSON.
8809391bb9cSRapkiewicz, Pawel  */
8819391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
8821abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
8831abe55efSEd Tanous {
88455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
8854a0cb85cSEd Tanous         [callback{std::move(callback)}](
8869391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
8874a0cb85cSEd Tanous             GetManagedObjects &resp) {
8881abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
8891abe55efSEd Tanous             // ethernet interfaces
8904c9afe43SEd Tanous             boost::container::flat_set<std::string> iface_list;
8914a0cb85cSEd Tanous             iface_list.reserve(resp.size());
8921abe55efSEd Tanous             if (error_code)
8931abe55efSEd Tanous             {
8944a0cb85cSEd Tanous                 callback(false, iface_list);
8959391bb9cSRapkiewicz, Pawel                 return;
8969391bb9cSRapkiewicz, Pawel             }
8979391bb9cSRapkiewicz, Pawel 
8989391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
8994a0cb85cSEd Tanous             for (const auto &objpath : resp)
9001abe55efSEd Tanous             {
9019391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
9024a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
9031abe55efSEd Tanous                 {
9041abe55efSEd Tanous                     // If interface is
9054a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
9064a0cb85cSEd Tanous                     // what we're looking for.
9079391bb9cSRapkiewicz, Pawel                     if (interface.first ==
9081abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
9091abe55efSEd Tanous                     {
9104a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
9114a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
9124a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
9134a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
9141abe55efSEd Tanous                         {
9159391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
9164c9afe43SEd Tanous                             iface_list.emplace(iface_id.substr(last_pos + 1));
9179391bb9cSRapkiewicz, Pawel                         }
9189391bb9cSRapkiewicz, Pawel                     }
9199391bb9cSRapkiewicz, Pawel                 }
9209391bb9cSRapkiewicz, Pawel             }
921a434f2bdSEd Tanous             // Finally make a callback with useful data
9224a0cb85cSEd Tanous             callback(true, iface_list);
9239391bb9cSRapkiewicz, Pawel         },
924aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
925aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9269391bb9cSRapkiewicz, Pawel };
9279391bb9cSRapkiewicz, Pawel 
9289391bb9cSRapkiewicz, Pawel /**
9299391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
9309391bb9cSRapkiewicz, Pawel  */
9311abe55efSEd Tanous class EthernetCollection : public Node
9321abe55efSEd Tanous {
9339391bb9cSRapkiewicz, Pawel   public:
9344a0cb85cSEd Tanous     template <typename CrowApp>
9351abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
9364a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
9371abe55efSEd Tanous     {
938588c3f0dSKowalski, Kamil         entityPrivileges = {
939588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
940e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
941e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
942e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
943e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
944e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
9459391bb9cSRapkiewicz, Pawel     }
9469391bb9cSRapkiewicz, Pawel 
9479391bb9cSRapkiewicz, Pawel   private:
9489391bb9cSRapkiewicz, Pawel     /**
9499391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
9509391bb9cSRapkiewicz, Pawel      */
95155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
9521abe55efSEd Tanous                const std::vector<std::string> &params) override
9531abe55efSEd Tanous     {
9540f74e643SEd Tanous         res.jsonValue["@odata.type"] =
9550f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
9560f74e643SEd Tanous         res.jsonValue["@odata.context"] =
9570f74e643SEd Tanous             "/redfish/v1/"
9580f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
9590f74e643SEd Tanous         res.jsonValue["@odata.id"] =
9600f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
9610f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
9620f74e643SEd Tanous         res.jsonValue["Description"] =
9630f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
9644c9afe43SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
9654a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
9661abe55efSEd Tanous         // preparation
967f12894f8SJason M. Bills         getEthernetIfaceList(
9684c9afe43SEd Tanous             [asyncResp](
9694c9afe43SEd Tanous                 const bool &success,
9704c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
9714a0cb85cSEd Tanous                 if (!success)
9721abe55efSEd Tanous                 {
9734c9afe43SEd Tanous                     messages::internalError(asyncResp->res);
9744a0cb85cSEd Tanous                     return;
9754a0cb85cSEd Tanous                 }
9764a0cb85cSEd Tanous 
9774c9afe43SEd Tanous                 nlohmann::json &iface_array =
9784c9afe43SEd Tanous                     asyncResp->res.jsonValue["Members"];
9794a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
980fda13ad2SSunitha Harish                 std::string tag = "_";
9814a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
9821abe55efSEd Tanous                 {
983fda13ad2SSunitha Harish                     std::size_t found = iface_item.find(tag);
984fda13ad2SSunitha Harish                     if (found == std::string::npos)
985fda13ad2SSunitha Harish                     {
9864a0cb85cSEd Tanous                         iface_array.push_back(
9874a0cb85cSEd Tanous                             {{"@odata.id",
9884a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
9894a0cb85cSEd Tanous                                   iface_item}});
9909391bb9cSRapkiewicz, Pawel                     }
991fda13ad2SSunitha Harish                 }
9924a0cb85cSEd Tanous 
9934c9afe43SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
9944c9afe43SEd Tanous                     iface_array.size();
9954c9afe43SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
9964a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
9979391bb9cSRapkiewicz, Pawel             });
9989391bb9cSRapkiewicz, Pawel     }
9999391bb9cSRapkiewicz, Pawel };
10009391bb9cSRapkiewicz, Pawel 
10019391bb9cSRapkiewicz, Pawel /**
10029391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
10039391bb9cSRapkiewicz, Pawel  */
10041abe55efSEd Tanous class EthernetInterface : public Node
10051abe55efSEd Tanous {
10069391bb9cSRapkiewicz, Pawel   public:
10079391bb9cSRapkiewicz, Pawel     /*
10089391bb9cSRapkiewicz, Pawel      * Default Constructor
10099391bb9cSRapkiewicz, Pawel      */
10104a0cb85cSEd Tanous     template <typename CrowApp>
10111abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
10124a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
10131abe55efSEd Tanous              std::string())
10141abe55efSEd Tanous     {
1015588c3f0dSKowalski, Kamil         entityPrivileges = {
1016588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1017e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1018e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1019e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1020e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1021e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
10229391bb9cSRapkiewicz, Pawel     }
10239391bb9cSRapkiewicz, Pawel 
1024e439f0f8SKowalski, Kamil   private:
1025bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
10264a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
10271abe55efSEd Tanous     {
1028bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
1029bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
1030bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
10314a0cb85cSEd Tanous                 if (ec)
10324a0cb85cSEd Tanous                 {
1033a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
10341abe55efSEd Tanous                 }
1035bc0bd6e0SEd Tanous             },
1036bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
1037bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
1038bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
1039bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
1040abf2add6SEd Tanous             std::variant<std::string>(hostname));
1041588c3f0dSKowalski, Kamil     }
1042588c3f0dSKowalski, Kamil 
1043d577665bSRatan Gupta     void handleMACAddressPatch(const std::string &ifaceId,
1044d577665bSRatan Gupta                                const std::string &macAddress,
1045d577665bSRatan Gupta                                const std::shared_ptr<AsyncResp> &asyncResp)
1046d577665bSRatan Gupta     {
1047d577665bSRatan Gupta         crow::connections::systemBus->async_method_call(
1048d577665bSRatan Gupta             [asyncResp, macAddress](const boost::system::error_code ec) {
1049d577665bSRatan Gupta                 if (ec)
1050d577665bSRatan Gupta                 {
1051d577665bSRatan Gupta                     messages::internalError(asyncResp->res);
1052d577665bSRatan Gupta                     return;
1053d577665bSRatan Gupta                 }
1054d577665bSRatan Gupta             },
1055d577665bSRatan Gupta             "xyz.openbmc_project.Network",
1056d577665bSRatan Gupta             "/xyz/openbmc_project/network/" + ifaceId,
1057d577665bSRatan Gupta             "org.freedesktop.DBus.Properties", "Set",
1058d577665bSRatan Gupta             "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1059d577665bSRatan Gupta             std::variant<std::string>(macAddress));
1060d577665bSRatan Gupta     }
1061286b9118SJohnathan Mantey 
1062da131a9aSJennifer Lee     void setDHCPEnabled(const std::string &ifaceId,
1063da131a9aSJennifer Lee                         const std::string &propertyName, const bool &value,
1064da131a9aSJennifer Lee                         const std::shared_ptr<AsyncResp> asyncResp)
1065da131a9aSJennifer Lee     {
1066da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1067da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1068da131a9aSJennifer Lee                 if (ec)
1069da131a9aSJennifer Lee                 {
1070da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1071da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1072da131a9aSJennifer Lee                     return;
1073da131a9aSJennifer Lee                 }
1074da131a9aSJennifer Lee             },
1075da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1076da131a9aSJennifer Lee             "/xyz/openbmc_project/network/" + ifaceId,
1077da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1078da131a9aSJennifer Lee             "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1079da131a9aSJennifer Lee             std::variant<bool>{value});
1080da131a9aSJennifer Lee     }
1081da131a9aSJennifer Lee     void setDHCPv4Config(const std::string &propertyName, const bool &value,
1082da131a9aSJennifer Lee                          const std::shared_ptr<AsyncResp> asyncResp)
1083da131a9aSJennifer Lee     {
1084da131a9aSJennifer Lee         BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1085da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1086da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1087da131a9aSJennifer Lee                 if (ec)
1088da131a9aSJennifer Lee                 {
1089da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1090da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1091da131a9aSJennifer Lee                     return;
1092da131a9aSJennifer Lee                 }
1093da131a9aSJennifer Lee             },
1094da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1095da131a9aSJennifer Lee             "/xyz/openbmc_project/network/config/dhcp",
1096da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1097da131a9aSJennifer Lee             "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1098da131a9aSJennifer Lee             std::variant<bool>{value});
1099da131a9aSJennifer Lee     }
1100d577665bSRatan Gupta 
1101da131a9aSJennifer Lee     void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1102da131a9aSJennifer Lee                            const std::shared_ptr<AsyncResp> asyncResp)
1103da131a9aSJennifer Lee     {
1104da131a9aSJennifer Lee         std::optional<bool> dhcpEnabled;
1105da131a9aSJennifer Lee         std::optional<bool> useDNSServers;
1106da131a9aSJennifer Lee         std::optional<bool> useDomainName;
1107da131a9aSJennifer Lee         std::optional<bool> useNTPServers;
1108da131a9aSJennifer Lee 
1109da131a9aSJennifer Lee         if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1110da131a9aSJennifer Lee                                  dhcpEnabled, "UseDNSServers", useDNSServers,
1111da131a9aSJennifer Lee                                  "UseDomainName", useDomainName,
1112da131a9aSJennifer Lee                                  "UseNTPServers", useNTPServers))
1113da131a9aSJennifer Lee         {
1114da131a9aSJennifer Lee             return;
1115da131a9aSJennifer Lee         }
1116da131a9aSJennifer Lee 
1117da131a9aSJennifer Lee         if (dhcpEnabled)
1118da131a9aSJennifer Lee         {
1119da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1120da131a9aSJennifer Lee             setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1121da131a9aSJennifer Lee         }
1122da131a9aSJennifer Lee 
1123da131a9aSJennifer Lee         if (useDNSServers)
1124da131a9aSJennifer Lee         {
1125da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1126da131a9aSJennifer Lee             setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1127da131a9aSJennifer Lee         }
1128da131a9aSJennifer Lee 
1129da131a9aSJennifer Lee         if (useDomainName)
1130da131a9aSJennifer Lee         {
1131da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1132da131a9aSJennifer Lee             setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1133da131a9aSJennifer Lee         }
1134da131a9aSJennifer Lee 
1135da131a9aSJennifer Lee         if (useNTPServers)
1136da131a9aSJennifer Lee         {
1137da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1138da131a9aSJennifer Lee             setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1139da131a9aSJennifer Lee         }
1140da131a9aSJennifer Lee     }
1141d1d50814SRavi Teja     void handleIPv4StaticPatch(
1142f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
1143d1d50814SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
11444a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
11451abe55efSEd Tanous     {
1146f476acbfSRatan Gupta         if (!input.is_array())
1147f476acbfSRatan Gupta         {
1148f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1149d1d50814SRavi Teja                                              "IPv4StaticAddresses");
1150f476acbfSRatan Gupta             return;
1151f476acbfSRatan Gupta         }
1152f476acbfSRatan Gupta 
11534a0cb85cSEd Tanous         int entryIdx = 0;
11544a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
1155d1d50814SRavi Teja             ipv4StaticData.begin();
1156537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
11571abe55efSEd Tanous         {
11584a0cb85cSEd Tanous             std::string pathString =
1159d1d50814SRavi Teja                 "IPv4StaticAddresses/" + std::to_string(entryIdx);
1160179db1d7SKowalski, Kamil 
1161f476acbfSRatan Gupta             if (thisJson.is_null())
1162f476acbfSRatan Gupta             {
1163d1d50814SRavi Teja                 if (thisData != ipv4StaticData.end())
1164f476acbfSRatan Gupta                 {
1165286b9118SJohnathan Mantey                     deleteIPv4(ifaceId, thisData->id, asyncResp);
1166f476acbfSRatan Gupta                     thisData++;
1167f476acbfSRatan Gupta                 }
1168f476acbfSRatan Gupta                 else
1169f476acbfSRatan Gupta                 {
1170f476acbfSRatan Gupta                     messages::propertyValueFormatError(
1171f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
1172f476acbfSRatan Gupta                     return;
1173f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
1174f476acbfSRatan Gupta                     // list and if unable to update one of the
1175f476acbfSRatan Gupta                     // list value then should we proceed further or
1176f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
1177f476acbfSRatan Gupta                     // till then we stop processing the next list item.
1178f476acbfSRatan Gupta                 }
1179f476acbfSRatan Gupta                 entryIdx++;
1180f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
1181f476acbfSRatan Gupta             }
1182f476acbfSRatan Gupta 
11839474b378SRatan Gupta             if (thisJson.empty())
11849474b378SRatan Gupta             {
1185d1d50814SRavi Teja                 if (thisData != ipv4StaticData.end())
11869474b378SRatan Gupta                 {
11879474b378SRatan Gupta                     thisData++;
11889474b378SRatan Gupta                 }
11899474b378SRatan Gupta                 else
11909474b378SRatan Gupta                 {
11919474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
11929474b378SRatan Gupta                                               pathString + "/Address");
11939474b378SRatan Gupta                     return;
1194f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
11959474b378SRatan Gupta                     // list and if unable to update one of the
11969474b378SRatan Gupta                     // list value then should we proceed further or
11979474b378SRatan Gupta                     // break there, would ask in the redfish forum
11989474b378SRatan Gupta                     // till then we stop processing the next list item.
11999474b378SRatan Gupta                 }
12009474b378SRatan Gupta                 entryIdx++;
12019474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
12029474b378SRatan Gupta             }
12039474b378SRatan Gupta 
1204537174c4SEd Tanous             std::optional<std::string> address;
1205537174c4SEd Tanous             std::optional<std::string> subnetMask;
1206537174c4SEd Tanous             std::optional<std::string> gateway;
1207537174c4SEd Tanous 
1208537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
12097e27d832SJohnathan Mantey                                      address, "SubnetMask", subnetMask,
12107e27d832SJohnathan Mantey                                      "Gateway", gateway))
1211537174c4SEd Tanous             {
1212537174c4SEd Tanous                 return;
1213179db1d7SKowalski, Kamil             }
1214179db1d7SKowalski, Kamil 
1215537174c4SEd Tanous             if (address)
12161abe55efSEd Tanous             {
1217537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
12181abe55efSEd Tanous                 {
1219537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
12204a0cb85cSEd Tanous                                                        pathString + "/Address");
1221537174c4SEd Tanous                     return;
12224a0cb85cSEd Tanous                 }
12234a0cb85cSEd Tanous             }
12244a0cb85cSEd Tanous 
1225537174c4SEd Tanous             uint8_t prefixLength = 0;
1226537174c4SEd Tanous             if (subnetMask)
12274a0cb85cSEd Tanous             {
1228537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
12294a0cb85cSEd Tanous                 {
1230f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1231537174c4SEd Tanous                         asyncResp->res, *subnetMask,
12324a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1233537174c4SEd Tanous                     return;
12344a0cb85cSEd Tanous                 }
12354a0cb85cSEd Tanous             }
12364a0cb85cSEd Tanous 
1237537174c4SEd Tanous             if (gateway)
12384a0cb85cSEd Tanous             {
1239537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
12404a0cb85cSEd Tanous                 {
1241537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1242537174c4SEd Tanous                                                        pathString + "/Gateway");
1243537174c4SEd Tanous                     return;
12444a0cb85cSEd Tanous                 }
12454a0cb85cSEd Tanous             }
12464a0cb85cSEd Tanous 
1247f476acbfSRatan Gupta             // if IP address exist then  modify it.
1248d1d50814SRavi Teja             if (thisData != ipv4StaticData.end())
12494a0cb85cSEd Tanous             {
1250179db1d7SKowalski, Kamil                 // Apply changes
1251537174c4SEd Tanous                 if (address)
12521abe55efSEd Tanous                 {
1253286b9118SJohnathan Mantey                     auto callback =
1254286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
12554a0cb85cSEd Tanous                             if (ec)
12561abe55efSEd Tanous                             {
1257a08b46ccSJason M. Bills                                 messages::internalError(asyncResp->res);
12584a0cb85cSEd Tanous                                 return;
12594a0cb85cSEd Tanous                             }
12604a0cb85cSEd Tanous                         };
12614a0cb85cSEd Tanous 
12624a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
12634a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1264f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1265f476acbfSRatan Gupta                             thisData->id,
12664a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
12674a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1268537174c4SEd Tanous                         std::variant<std::string>(*address));
1269179db1d7SKowalski, Kamil                 }
1270179db1d7SKowalski, Kamil 
1271537174c4SEd Tanous                 if (subnetMask)
12721abe55efSEd Tanous                 {
12734a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1274286b9118SJohnathan Mantey                                                  thisData->id, prefixLength,
1275286b9118SJohnathan Mantey                                                  asyncResp);
1276179db1d7SKowalski, Kamil                 }
1277179db1d7SKowalski, Kamil 
1278537174c4SEd Tanous                 if (gateway)
12791abe55efSEd Tanous                 {
1280286b9118SJohnathan Mantey                     auto callback =
1281286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
12824a0cb85cSEd Tanous                             if (ec)
12831abe55efSEd Tanous                             {
1284a08b46ccSJason M. Bills                                 messages::internalError(asyncResp->res);
12854a0cb85cSEd Tanous                                 return;
12864a0cb85cSEd Tanous                             }
12874a0cb85cSEd Tanous                         };
12884a0cb85cSEd Tanous 
12894a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
12904a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1291f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1292f476acbfSRatan Gupta                             thisData->id,
12934a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
12944a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1295537174c4SEd Tanous                         std::variant<std::string>(*gateway));
12964a0cb85cSEd Tanous                 }
1297f476acbfSRatan Gupta 
12984a0cb85cSEd Tanous                 thisData++;
12991abe55efSEd Tanous             }
13001abe55efSEd Tanous             else
13011abe55efSEd Tanous             {
13024a0cb85cSEd Tanous                 // Create IPv4 with provided data
1303537174c4SEd Tanous                 if (!gateway)
13041abe55efSEd Tanous                 {
1305a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
13064a0cb85cSEd Tanous                                               pathString + "/Gateway");
13074a0cb85cSEd Tanous                     continue;
13084a0cb85cSEd Tanous                 }
13094a0cb85cSEd Tanous 
1310537174c4SEd Tanous                 if (!address)
13111abe55efSEd Tanous                 {
1312a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
13134a0cb85cSEd Tanous                                               pathString + "/Address");
13144a0cb85cSEd Tanous                     continue;
13154a0cb85cSEd Tanous                 }
13164a0cb85cSEd Tanous 
1317537174c4SEd Tanous                 if (!subnetMask)
13181abe55efSEd Tanous                 {
1319a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
13204a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
13214a0cb85cSEd Tanous                     continue;
1322588c3f0dSKowalski, Kamil                 }
1323588c3f0dSKowalski, Kamil 
1324b01bf299SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1325b01bf299SEd Tanous                            asyncResp);
132695897b20SRatan Gupta 
1327d1d50814SRavi Teja                 nlohmann::json &ipv4StaticAddressJson =
1328d1d50814SRavi Teja                     asyncResp->res.jsonValue["IPv4StaticAddresses"][entryIdx];
1329d1d50814SRavi Teja                 ipv4StaticAddressJson["Address"] = *address;
1330d1d50814SRavi Teja                 ipv4StaticAddressJson["SubnetMask"] = *subnetMask;
1331d1d50814SRavi Teja                 ipv4StaticAddressJson["Gateway"] = *gateway;
13324a0cb85cSEd Tanous             }
13334a0cb85cSEd Tanous             entryIdx++;
13344a0cb85cSEd Tanous         }
13354a0cb85cSEd Tanous     }
13364a0cb85cSEd Tanous 
1337f85837bfSRAJESWARAN THILLAIGOVINDAN     void handleStaticNameServersPatch(
1338f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::string &ifaceId,
1339f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::vector<std::string> &updatedStaticNameServers,
1340f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::shared_ptr<AsyncResp> &asyncResp)
1341f85837bfSRAJESWARAN THILLAIGOVINDAN     {
1342f85837bfSRAJESWARAN THILLAIGOVINDAN         crow::connections::systemBus->async_method_call(
1343286b9118SJohnathan Mantey             [asyncResp](const boost::system::error_code ec) {
1344f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (ec)
1345f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1346f85837bfSRAJESWARAN THILLAIGOVINDAN                     messages::internalError(asyncResp->res);
1347f85837bfSRAJESWARAN THILLAIGOVINDAN                     return;
1348f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1349f85837bfSRAJESWARAN THILLAIGOVINDAN             },
1350f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network",
1351f85837bfSRAJESWARAN THILLAIGOVINDAN             "/xyz/openbmc_project/network/" + ifaceId,
1352f85837bfSRAJESWARAN THILLAIGOVINDAN             "org.freedesktop.DBus.Properties", "Set",
1353f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1354f85837bfSRAJESWARAN THILLAIGOVINDAN             std::variant<std::vector<std::string>>{updatedStaticNameServers});
1355f85837bfSRAJESWARAN THILLAIGOVINDAN     }
1356f85837bfSRAJESWARAN THILLAIGOVINDAN 
1357e48c0fc5SRavi Teja     void handleIPv6StaticAddressesPatch(
1358e48c0fc5SRavi Teja         const std::string &ifaceId, nlohmann::json &input,
1359e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1360e48c0fc5SRavi Teja         const std::shared_ptr<AsyncResp> asyncResp)
1361e48c0fc5SRavi Teja     {
1362e48c0fc5SRavi Teja         if (!input.is_array())
1363e48c0fc5SRavi Teja         {
1364e48c0fc5SRavi Teja             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1365e48c0fc5SRavi Teja                                              "IPv6StaticAddresses");
1366e48c0fc5SRavi Teja             return;
1367e48c0fc5SRavi Teja         }
1368e48c0fc5SRavi Teja 
1369e48c0fc5SRavi Teja         int entryIdx = 0;
1370e48c0fc5SRavi Teja         boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1371e48c0fc5SRavi Teja             ipv6StaticData.begin();
1372e48c0fc5SRavi Teja         for (nlohmann::json &thisJson : input)
1373e48c0fc5SRavi Teja         {
1374e48c0fc5SRavi Teja             std::string pathString =
1375e48c0fc5SRavi Teja                 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1376e48c0fc5SRavi Teja 
1377e48c0fc5SRavi Teja             if (thisJson.is_null())
1378e48c0fc5SRavi Teja             {
1379e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1380e48c0fc5SRavi Teja                 {
1381286b9118SJohnathan Mantey                     deleteIPv6(ifaceId, thisData->id, asyncResp);
1382e48c0fc5SRavi Teja                     thisData++;
1383e48c0fc5SRavi Teja                 }
1384e48c0fc5SRavi Teja                 else
1385e48c0fc5SRavi Teja                 {
1386e48c0fc5SRavi Teja                     messages::propertyValueFormatError(
1387e48c0fc5SRavi Teja                         asyncResp->res, input.dump(), pathString);
1388e48c0fc5SRavi Teja                     return;
1389e48c0fc5SRavi Teja                 }
1390e48c0fc5SRavi Teja                 entryIdx++;
1391e48c0fc5SRavi Teja                 continue;
1392e48c0fc5SRavi Teja             }
1393e48c0fc5SRavi Teja 
1394e48c0fc5SRavi Teja             if (thisJson.empty())
1395e48c0fc5SRavi Teja             {
1396e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1397e48c0fc5SRavi Teja                 {
1398e48c0fc5SRavi Teja                     thisData++;
1399e48c0fc5SRavi Teja                 }
1400e48c0fc5SRavi Teja                 else
1401e48c0fc5SRavi Teja                 {
1402e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1403e48c0fc5SRavi Teja                                               pathString + "/Address");
1404e48c0fc5SRavi Teja                     return;
1405e48c0fc5SRavi Teja                 }
1406e48c0fc5SRavi Teja                 entryIdx++;
1407e48c0fc5SRavi Teja                 continue;
1408e48c0fc5SRavi Teja             }
1409e48c0fc5SRavi Teja 
1410e48c0fc5SRavi Teja             std::optional<std::string> address;
1411e48c0fc5SRavi Teja             std::optional<uint8_t> prefixLength;
1412e48c0fc5SRavi Teja 
1413e48c0fc5SRavi Teja             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1414e48c0fc5SRavi Teja                                      address, "PrefixLength", prefixLength))
1415e48c0fc5SRavi Teja             {
1416e48c0fc5SRavi Teja                 return;
1417e48c0fc5SRavi Teja             }
1418e48c0fc5SRavi Teja 
1419e48c0fc5SRavi Teja             // if IP address exist then  modify it.
1420e48c0fc5SRavi Teja             if (thisData != ipv6StaticData.end())
1421e48c0fc5SRavi Teja             {
1422e48c0fc5SRavi Teja                 // Apply changes
1423e48c0fc5SRavi Teja                 if (address)
1424e48c0fc5SRavi Teja                 {
1425286b9118SJohnathan Mantey                     auto callback =
1426286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
1427e48c0fc5SRavi Teja                             if (ec)
1428e48c0fc5SRavi Teja                             {
1429e48c0fc5SRavi Teja                                 messages::internalError(asyncResp->res);
1430e48c0fc5SRavi Teja                                 return;
1431e48c0fc5SRavi Teja                             }
1432e48c0fc5SRavi Teja                         };
1433e48c0fc5SRavi Teja 
1434e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1435e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1436e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1437e48c0fc5SRavi Teja                             thisData->id,
1438e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1439e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "Address",
1440e48c0fc5SRavi Teja                         std::variant<std::string>(*address));
1441e48c0fc5SRavi Teja                 }
1442e48c0fc5SRavi Teja 
1443e48c0fc5SRavi Teja                 if (prefixLength)
1444e48c0fc5SRavi Teja                 {
1445286b9118SJohnathan Mantey                     auto callback =
1446286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
1447e48c0fc5SRavi Teja                             if (ec)
1448e48c0fc5SRavi Teja                             {
1449e48c0fc5SRavi Teja                                 messages::internalError(asyncResp->res);
1450e48c0fc5SRavi Teja                                 return;
1451e48c0fc5SRavi Teja                             }
1452e48c0fc5SRavi Teja                         };
1453e48c0fc5SRavi Teja 
1454e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1455e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1456e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1457e48c0fc5SRavi Teja                             thisData->id,
1458e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1459e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "PrefixLength",
1460e48c0fc5SRavi Teja                         std::variant<uint8_t>(*prefixLength));
1461e48c0fc5SRavi Teja                 }
1462e48c0fc5SRavi Teja 
1463e48c0fc5SRavi Teja                 thisData++;
1464e48c0fc5SRavi Teja             }
1465e48c0fc5SRavi Teja             else
1466e48c0fc5SRavi Teja             {
1467e48c0fc5SRavi Teja                 // Create IPv6 with provided data
1468e48c0fc5SRavi Teja 
1469e48c0fc5SRavi Teja                 if (!prefixLength)
1470e48c0fc5SRavi Teja                 {
1471e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1472e48c0fc5SRavi Teja                                               pathString + "/PrefixLength");
1473e48c0fc5SRavi Teja                     continue;
1474e48c0fc5SRavi Teja                 }
1475e48c0fc5SRavi Teja 
1476e48c0fc5SRavi Teja                 if (!address)
1477e48c0fc5SRavi Teja                 {
1478e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1479e48c0fc5SRavi Teja                                               pathString + "/Address");
1480e48c0fc5SRavi Teja                     continue;
1481e48c0fc5SRavi Teja                 }
1482e48c0fc5SRavi Teja 
1483e48c0fc5SRavi Teja                 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1484e48c0fc5SRavi Teja                            asyncResp);
1485e48c0fc5SRavi Teja 
1486e48c0fc5SRavi Teja                 nlohmann::json &ipv6StaticAddressJson =
1487e48c0fc5SRavi Teja                     asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1488e48c0fc5SRavi Teja                 ipv6StaticAddressJson["Address"] = *address;
1489e48c0fc5SRavi Teja                 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1490e48c0fc5SRavi Teja             }
1491e48c0fc5SRavi Teja             entryIdx++;
1492e48c0fc5SRavi Teja         }
1493e48c0fc5SRavi Teja     }
1494e48c0fc5SRavi Teja 
14950f74e643SEd Tanous     void parseInterfaceData(
14960f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
14970f74e643SEd Tanous         const EthernetInterfaceData &ethData,
1498e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1499d1d50814SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
1500e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1501e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
15024a0cb85cSEd Tanous     {
15034a0cb85cSEd Tanous         json_response["Id"] = iface_id;
15044a0cb85cSEd Tanous         json_response["@odata.id"] =
15054a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1506029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1507029573d4SEd Tanous         if (ethData.speed == 0)
1508029573d4SEd Tanous         {
1509029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1510029573d4SEd Tanous             json_response["Status"] = {
1511029573d4SEd Tanous                 {"Health", "OK"},
1512029573d4SEd Tanous                 {"State", "Disabled"},
1513029573d4SEd Tanous             };
1514029573d4SEd Tanous         }
1515029573d4SEd Tanous         else
1516029573d4SEd Tanous         {
1517029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1518029573d4SEd Tanous             json_response["Status"] = {
1519029573d4SEd Tanous                 {"Health", "OK"},
1520029573d4SEd Tanous                 {"State", "Enabled"},
1521029573d4SEd Tanous             };
1522029573d4SEd Tanous         }
15234a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
15244a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1525fda13ad2SSunitha Harish         json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
15262a133282Smanojkiraneda 
15274a0cb85cSEd Tanous         if (!ethData.hostname.empty())
15284a0cb85cSEd Tanous         {
15294a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
1530d24bfc7aSJennifer Lee             if (!ethData.domainnames.empty())
1531d24bfc7aSJennifer Lee             {
1532d24bfc7aSJennifer Lee                 json_response["FQDN"] =
1533d24bfc7aSJennifer Lee                     ethData.hostname + "." + ethData.domainnames[0];
1534d24bfc7aSJennifer Lee             }
15354a0cb85cSEd Tanous         }
15364a0cb85cSEd Tanous 
1537fda13ad2SSunitha Harish         json_response["VLANs"] = {
1538fda13ad2SSunitha Harish             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1539fda13ad2SSunitha Harish                               iface_id + "/VLANs"}};
1540fda13ad2SSunitha Harish 
1541029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
1542*95f8646eSManojkiran Eda 
1543*95f8646eSManojkiran Eda         if (!ethData.DHCPEnabled)
1544*95f8646eSManojkiran Eda         {
1545f85837bfSRAJESWARAN THILLAIGOVINDAN             json_response["StaticNameServers"] = ethData.nameservers;
1546*95f8646eSManojkiran Eda         }
1547*95f8646eSManojkiran Eda         else
1548*95f8646eSManojkiran Eda         {
1549*95f8646eSManojkiran Eda             json_response["StaticNameServers"] = {};
1550*95f8646eSManojkiran Eda         }
15514a0cb85cSEd Tanous 
15524a0cb85cSEd Tanous         nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
15534a0cb85cSEd Tanous         ipv4_array = nlohmann::json::array();
15544a0cb85cSEd Tanous         for (auto &ipv4_config : ipv4Data)
15554a0cb85cSEd Tanous         {
1556fa5053a6SGunnar Mills 
1557fa5053a6SGunnar Mills             std::string gatewayStr = ipv4_config.gateway;
1558fa5053a6SGunnar Mills             if (gatewayStr.empty())
1559fa5053a6SGunnar Mills             {
1560fa5053a6SGunnar Mills                 gatewayStr = "0.0.0.0";
1561fa5053a6SGunnar Mills             }
1562fa5053a6SGunnar Mills 
15634a0cb85cSEd Tanous             ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
15644a0cb85cSEd Tanous                                   {"SubnetMask", ipv4_config.netmask},
1565029573d4SEd Tanous                                   {"Address", ipv4_config.address},
1566fa5053a6SGunnar Mills                                   {"Gateway", gatewayStr}});
15674a0cb85cSEd Tanous         }
1568d1d50814SRavi Teja 
1569d1d50814SRavi Teja         nlohmann::json &ipv4_static_array =
1570d1d50814SRavi Teja             json_response["IPv4StaticAddresses"];
1571d1d50814SRavi Teja         ipv4_static_array = nlohmann::json::array();
1572d1d50814SRavi Teja         for (auto &ipv4_static_config : ipv4StaticData)
1573d1d50814SRavi Teja         {
1574d1d50814SRavi Teja 
1575d1d50814SRavi Teja             std::string gatewayStr = ipv4_static_config.gateway;
1576d1d50814SRavi Teja             if (gatewayStr.empty())
1577d1d50814SRavi Teja             {
1578d1d50814SRavi Teja                 gatewayStr = "0.0.0.0";
15794a0cb85cSEd Tanous             }
1580d1d50814SRavi Teja 
1581d1d50814SRavi Teja             ipv4_static_array.push_back(
1582d1d50814SRavi Teja                 {{"SubnetMask", ipv4_static_config.netmask},
1583d1d50814SRavi Teja                  {"Address", ipv4_static_config.address},
1584d1d50814SRavi Teja                  {"Gateway", gatewayStr}});
1585d1d50814SRavi Teja         }
1586d1d50814SRavi Teja 
15879a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1588e48c0fc5SRavi Teja 
1589e48c0fc5SRavi Teja         nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1590e48c0fc5SRavi Teja         ipv6_array = nlohmann::json::array();
1591e48c0fc5SRavi Teja         for (auto &ipv6_config : ipv6Data)
1592e48c0fc5SRavi Teja         {
1593e48c0fc5SRavi Teja             ipv6_array.push_back({{"Address", ipv6_config.address},
1594e48c0fc5SRavi Teja                                   {"PrefixLength", ipv6_config.prefixLength},
1595e48c0fc5SRavi Teja                                   {"AddressOrigin", ipv6_config.origin}});
1596e48c0fc5SRavi Teja         }
1597e48c0fc5SRavi Teja 
1598e48c0fc5SRavi Teja         nlohmann::json &ipv6_static_array =
1599e48c0fc5SRavi Teja             json_response["IPv6StaticAddresses"];
1600e48c0fc5SRavi Teja         ipv6_static_array = nlohmann::json::array();
1601e48c0fc5SRavi Teja         for (auto &ipv6_static_config : ipv6StaticData)
1602e48c0fc5SRavi Teja         {
1603e48c0fc5SRavi Teja             ipv6_static_array.push_back(
1604e48c0fc5SRavi Teja                 {{"Address", ipv6_static_config.address},
1605e48c0fc5SRavi Teja                  {"PrefixLength", ipv6_static_config.prefixLength}});
1606e48c0fc5SRavi Teja         }
1607588c3f0dSKowalski, Kamil     }
1608588c3f0dSKowalski, Kamil 
16099391bb9cSRapkiewicz, Pawel     /**
16109391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
16119391bb9cSRapkiewicz, Pawel      */
161255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
16131abe55efSEd Tanous                const std::vector<std::string> &params) override
16141abe55efSEd Tanous     {
16154a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16161abe55efSEd Tanous         if (params.size() != 1)
16171abe55efSEd Tanous         {
1618f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
16199391bb9cSRapkiewicz, Pawel             return;
16209391bb9cSRapkiewicz, Pawel         }
16219391bb9cSRapkiewicz, Pawel 
16224a0cb85cSEd Tanous         getEthernetIfaceData(
16234a0cb85cSEd Tanous             params[0],
16244a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
16254a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1626e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1627d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1628d1d50814SRavi Teja                     &ipv4StaticData,
1629e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1630e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1631e48c0fc5SRavi Teja                     &ipv6StaticData) {
16324a0cb85cSEd Tanous                 if (!success)
16331abe55efSEd Tanous                 {
16341abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16351abe55efSEd Tanous                     // object, and other errors
1636f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1637f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
16384a0cb85cSEd Tanous                     return;
16399391bb9cSRapkiewicz, Pawel                 }
16404c9afe43SEd Tanous 
16414c9afe43SEd Tanous                 // because this has no dependence on the interface at this
16424c9afe43SEd Tanous                 // point, it needs to be done after we know the interface
16434c9afe43SEd Tanous                 // exists, not before.
16444c9afe43SEd Tanous                 getDHCPConfigData(asyncResp);
16454c9afe43SEd Tanous 
16460f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1647fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
16480f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
16490f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
16500f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
16510f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
16520f74e643SEd Tanous                     "Management Network Interface";
16530f74e643SEd Tanous 
16540f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1655d1d50814SRavi Teja                                    ipv4Data, ipv4StaticData, ipv6Data,
1656d1d50814SRavi Teja                                    ipv6StaticData);
16579391bb9cSRapkiewicz, Pawel             });
16589391bb9cSRapkiewicz, Pawel     }
16599391bb9cSRapkiewicz, Pawel 
166055c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
16611abe55efSEd Tanous                  const std::vector<std::string> &params) override
16621abe55efSEd Tanous     {
16634a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16641abe55efSEd Tanous         if (params.size() != 1)
16651abe55efSEd Tanous         {
1666f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1667588c3f0dSKowalski, Kamil             return;
1668588c3f0dSKowalski, Kamil         }
1669588c3f0dSKowalski, Kamil 
16704a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1671588c3f0dSKowalski, Kamil 
1672bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1673d577665bSRatan Gupta         std::optional<std::string> macAddress;
16749a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1675f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1676d1d50814SRavi Teja         std::optional<nlohmann::json> ipv4StaticAddresses;
1677f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1678e48c0fc5SRavi Teja         std::optional<nlohmann::json> ipv6StaticAddresses;
1679f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
16805112e9b4SRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> nameServers;
1681da131a9aSJennifer Lee         std::optional<nlohmann::json> dhcpv4;
16820627a2c7SEd Tanous 
1683fda13ad2SSunitha Harish         if (!json_util::readJson(
1684fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
1685d1d50814SRavi Teja                 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1686d1d50814SRavi Teja                 macAddress, "StaticNameServers", staticNameServers,
1687d1d50814SRavi Teja                 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1688d1d50814SRavi Teja                 ipv6StaticAddresses, "NameServers", nameServers, "DHCPv4",
1689d1d50814SRavi Teja                 dhcpv4))
16901abe55efSEd Tanous         {
1691588c3f0dSKowalski, Kamil             return;
1692588c3f0dSKowalski, Kamil         }
1693f15aad37SRatan Gupta 
1694da131a9aSJennifer Lee         if (dhcpv4)
1695da131a9aSJennifer Lee         {
1696da131a9aSJennifer Lee             handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1697da131a9aSJennifer Lee         }
1698da131a9aSJennifer Lee 
16994a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1700588c3f0dSKowalski, Kamil         // preparation
17014a0cb85cSEd Tanous         getEthernetIfaceData(
17024a0cb85cSEd Tanous             iface_id,
1703fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1704fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
17050627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
1706d1d50814SRavi Teja              ipv4StaticAddresses = std::move(ipv4StaticAddresses),
17079a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1708e48c0fc5SRavi Teja              ipv6StaticAddresses = std::move(ipv6StaticAddresses),
17095112e9b4SRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers),
17105112e9b4SRAJESWARAN THILLAIGOVINDAN              nameServers = std::move(nameServers)](
17114a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1712e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1713d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1714d1d50814SRavi Teja                     &ipv4StaticData,
1715e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1716e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1717e48c0fc5SRavi Teja                     &ipv6StaticData) {
17181abe55efSEd Tanous                 if (!success)
17191abe55efSEd Tanous                 {
1720588c3f0dSKowalski, Kamil                     // ... otherwise return error
17211abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
17221abe55efSEd Tanous                     // object, and other errors
1723fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1724fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1725588c3f0dSKowalski, Kamil                     return;
1726588c3f0dSKowalski, Kamil                 }
1727588c3f0dSKowalski, Kamil 
17280627a2c7SEd Tanous                 if (hostname)
17291abe55efSEd Tanous                 {
17300627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
17311abe55efSEd Tanous                 }
17320627a2c7SEd Tanous 
1733d577665bSRatan Gupta                 if (macAddress)
1734d577665bSRatan Gupta                 {
1735d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1736d577665bSRatan Gupta                 }
1737d577665bSRatan Gupta 
17380627a2c7SEd Tanous                 if (ipv4Addresses)
17391abe55efSEd Tanous                 {
1740d1d50814SRavi Teja                     messages::propertyNotWritable(asyncResp->res,
1741d1d50814SRavi Teja                                                   "IPv4Addresses");
1742d1d50814SRavi Teja                 }
1743d1d50814SRavi Teja 
1744d1d50814SRavi Teja                 if (ipv4StaticAddresses)
1745d1d50814SRavi Teja                 {
1746537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1747537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1748537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1749537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1750537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1751537174c4SEd Tanous                     // on that, but could be done more efficiently
1752d1d50814SRavi Teja                     nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
1753d1d50814SRavi Teja                     handleIPv4StaticPatch(iface_id, ipv4Static, ipv4StaticData,
1754d1d50814SRavi Teja                                           asyncResp);
17551abe55efSEd Tanous                 }
17560627a2c7SEd Tanous 
17575112e9b4SRAJESWARAN THILLAIGOVINDAN                 if (nameServers)
17585112e9b4SRAJESWARAN THILLAIGOVINDAN                 {
17595112e9b4SRAJESWARAN THILLAIGOVINDAN                     // Data.Permissions is read-only
17605112e9b4SRAJESWARAN THILLAIGOVINDAN                     messages::propertyNotWritable(asyncResp->res,
17615112e9b4SRAJESWARAN THILLAIGOVINDAN                                                   "NameServers");
17625112e9b4SRAJESWARAN THILLAIGOVINDAN                 }
17635112e9b4SRAJESWARAN THILLAIGOVINDAN 
1764f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1765f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1766f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1767f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1768f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
17699a6fc6feSRavi Teja 
17709a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
17719a6fc6feSRavi Teja                 {
17729a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
17739a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
17749a6fc6feSRavi Teja                 }
1775e48c0fc5SRavi Teja 
1776e48c0fc5SRavi Teja                 if (ipv6StaticAddresses)
1777e48c0fc5SRavi Teja                 {
1778e48c0fc5SRavi Teja                     nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1779e48c0fc5SRavi Teja                     handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1780e48c0fc5SRavi Teja                                                    ipv6StaticData, asyncResp);
1781e48c0fc5SRavi Teja                 }
1782588c3f0dSKowalski, Kamil             });
1783588c3f0dSKowalski, Kamil     }
17849391bb9cSRapkiewicz, Pawel };
17859391bb9cSRapkiewicz, Pawel 
1786e439f0f8SKowalski, Kamil /**
17874a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
17884a0cb85cSEd Tanous  * Schema
1789e439f0f8SKowalski, Kamil  */
17901abe55efSEd Tanous class VlanNetworkInterface : public Node
17911abe55efSEd Tanous {
1792e439f0f8SKowalski, Kamil   public:
1793e439f0f8SKowalski, Kamil     /*
1794e439f0f8SKowalski, Kamil      * Default Constructor
1795e439f0f8SKowalski, Kamil      */
1796e439f0f8SKowalski, Kamil     template <typename CrowApp>
17971abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
17984a0cb85cSEd Tanous         Node(app,
17990f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
18001abe55efSEd Tanous              std::string(), std::string())
18011abe55efSEd Tanous     {
1802e439f0f8SKowalski, Kamil         entityPrivileges = {
1803e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1804e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1805e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1806e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1807e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1808e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1809e439f0f8SKowalski, Kamil     }
1810e439f0f8SKowalski, Kamil 
1811e439f0f8SKowalski, Kamil   private:
18120f74e643SEd Tanous     void parseInterfaceData(
18130f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
18140f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
1815e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1816d1d50814SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
1817e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1818e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
18191abe55efSEd Tanous     {
1820e439f0f8SKowalski, Kamil         // Fill out obvious data...
18214a0cb85cSEd Tanous         json_response["Id"] = iface_id;
18224a0cb85cSEd Tanous         json_response["@odata.id"] =
18234a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
18244a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1825e439f0f8SKowalski, Kamil 
18264a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1827fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
18284a0cb85cSEd Tanous         {
1829fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
18304a0cb85cSEd Tanous         }
1831e439f0f8SKowalski, Kamil     }
1832e439f0f8SKowalski, Kamil 
1833fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
18341abe55efSEd Tanous     {
18351abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
18361abe55efSEd Tanous         {
1837927a505aSKowalski, Kamil             return false;
18381abe55efSEd Tanous         }
18391abe55efSEd Tanous         else
18401abe55efSEd Tanous         {
1841927a505aSKowalski, Kamil             return true;
1842927a505aSKowalski, Kamil         }
1843927a505aSKowalski, Kamil     }
1844927a505aSKowalski, Kamil 
1845e439f0f8SKowalski, Kamil     /**
1846e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1847e439f0f8SKowalski, Kamil      */
184855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
18491abe55efSEd Tanous                const std::vector<std::string> &params) override
18501abe55efSEd Tanous     {
18514a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18524a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1853e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1854e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1855e439f0f8SKowalski, Kamil         // impossible.
18561abe55efSEd Tanous         if (params.size() != 2)
18571abe55efSEd Tanous         {
1858f12894f8SJason M. Bills             messages::internalError(res);
1859e439f0f8SKowalski, Kamil             res.end();
1860e439f0f8SKowalski, Kamil             return;
1861e439f0f8SKowalski, Kamil         }
1862e439f0f8SKowalski, Kamil 
18634a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
18644a0cb85cSEd Tanous         const std::string &iface_id = params[1];
18650f74e643SEd Tanous         res.jsonValue["@odata.type"] =
18660f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
18670f74e643SEd Tanous         res.jsonValue["@odata.context"] =
18680f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
18690f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1870e439f0f8SKowalski, Kamil 
1871fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
18721abe55efSEd Tanous         {
1873a434f2bdSEd Tanous             return;
1874a434f2bdSEd Tanous         }
1875a434f2bdSEd Tanous 
1876e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1877e439f0f8SKowalski, Kamil         // preparation
18784a0cb85cSEd Tanous         getEthernetIfaceData(
1879fda13ad2SSunitha Harish             params[1],
1880fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1881fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
18824a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1883e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1884d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1885d1d50814SRavi Teja                     &ipv4StaticData,
1886e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1887e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1888e48c0fc5SRavi Teja                     &ipv6StaticData) {
1889fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
18901abe55efSEd Tanous                 {
18910f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
18920f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
1893d1d50814SRavi Teja                                        ipv4Data, ipv4StaticData, ipv6Data,
1894d1d50814SRavi Teja                                        ipv6StaticData);
18951abe55efSEd Tanous                 }
18961abe55efSEd Tanous                 else
18971abe55efSEd Tanous                 {
1898e439f0f8SKowalski, Kamil                     // ... otherwise return error
18991abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
19001abe55efSEd Tanous                     // object, and other errors
1901f12894f8SJason M. Bills                     messages::resourceNotFound(
1902f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1903e439f0f8SKowalski, Kamil                 }
1904e439f0f8SKowalski, Kamil             });
1905e439f0f8SKowalski, Kamil     }
1906e439f0f8SKowalski, Kamil 
190755c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
19081abe55efSEd Tanous                  const std::vector<std::string> &params) override
19091abe55efSEd Tanous     {
19104a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19111abe55efSEd Tanous         if (params.size() != 2)
19121abe55efSEd Tanous         {
1913f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1914e439f0f8SKowalski, Kamil             return;
1915e439f0f8SKowalski, Kamil         }
1916e439f0f8SKowalski, Kamil 
1917d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
191855c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1919927a505aSKowalski, Kamil 
1920fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
19211abe55efSEd Tanous         {
1922fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1923fda13ad2SSunitha Harish                                        ifaceId);
1924927a505aSKowalski, Kamil             return;
1925927a505aSKowalski, Kamil         }
1926927a505aSKowalski, Kamil 
19270627a2c7SEd Tanous         bool vlanEnable = false;
19280627a2c7SEd Tanous         uint64_t vlanId = 0;
19290627a2c7SEd Tanous 
19300627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
19310627a2c7SEd Tanous                                  vlanId))
19321abe55efSEd Tanous         {
1933927a505aSKowalski, Kamil             return;
1934927a505aSKowalski, Kamil         }
1935927a505aSKowalski, Kamil 
1936927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1937927a505aSKowalski, Kamil         // preparation
1938e48c0fc5SRavi Teja         getEthernetIfaceData(
1939e48c0fc5SRavi Teja             params[1],
1940e48c0fc5SRavi Teja             [this, asyncResp, parentIfaceId{std::string(params[0])},
1941e48c0fc5SRavi Teja              ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1942e48c0fc5SRavi Teja                 const bool &success, const EthernetInterfaceData &ethData,
1943e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1944d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1945d1d50814SRavi Teja                     &ipv4StaticData,
1946e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1947e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1948e48c0fc5SRavi Teja                     &ipv6StaticData) {
194908244d02SSunitha Harish                 if (success && !ethData.vlan_id.empty())
195008244d02SSunitha Harish                 {
195108244d02SSunitha Harish                     auto callback =
195208244d02SSunitha Harish                         [asyncResp](const boost::system::error_code ec) {
195308244d02SSunitha Harish                             if (ec)
195408244d02SSunitha Harish                             {
195508244d02SSunitha Harish                                 messages::internalError(asyncResp->res);
195608244d02SSunitha Harish                             }
195708244d02SSunitha Harish                         };
195808244d02SSunitha Harish 
195908244d02SSunitha Harish                     if (vlanEnable == true)
196008244d02SSunitha Harish                     {
196108244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
196208244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
196308244d02SSunitha Harish                             "/xyz/openbmc_project/network/" + ifaceId,
196408244d02SSunitha Harish                             "org.freedesktop.DBus.Properties", "Set",
196508244d02SSunitha Harish                             "xyz.openbmc_project.Network.VLAN", "Id",
196608244d02SSunitha Harish                             std::variant<uint32_t>(vlanId));
196708244d02SSunitha Harish                     }
196808244d02SSunitha Harish                     else
196908244d02SSunitha Harish                     {
1970e48c0fc5SRavi Teja                         BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1971e48c0fc5SRavi Teja                                             "vlan interface";
197208244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
197308244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
1974e48c0fc5SRavi Teja                             std::string("/xyz/openbmc_project/network/") +
1975e48c0fc5SRavi Teja                                 ifaceId,
197608244d02SSunitha Harish                             "xyz.openbmc_project.Object.Delete", "Delete");
197708244d02SSunitha Harish                     }
197808244d02SSunitha Harish                 }
197908244d02SSunitha Harish                 else
19801abe55efSEd Tanous                 {
19811abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
19821abe55efSEd Tanous                     // object, and other errors
1983e48c0fc5SRavi Teja                     messages::resourceNotFound(
1984e48c0fc5SRavi Teja                         asyncResp->res, "VLAN Network Interface", ifaceId);
1985927a505aSKowalski, Kamil                     return;
1986927a505aSKowalski, Kamil                 }
1987927a505aSKowalski, Kamil             });
1988e439f0f8SKowalski, Kamil     }
1989e439f0f8SKowalski, Kamil 
199055c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
19911abe55efSEd Tanous                   const std::vector<std::string> &params) override
19921abe55efSEd Tanous     {
19934a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19941abe55efSEd Tanous         if (params.size() != 2)
19951abe55efSEd Tanous         {
1996f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1997e439f0f8SKowalski, Kamil             return;
1998e439f0f8SKowalski, Kamil         }
1999e439f0f8SKowalski, Kamil 
2000d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
200155c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
2002927a505aSKowalski, Kamil 
2003fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
20041abe55efSEd Tanous         {
2005fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2006fda13ad2SSunitha Harish                                        ifaceId);
2007927a505aSKowalski, Kamil             return;
2008927a505aSKowalski, Kamil         }
2009927a505aSKowalski, Kamil 
2010927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
2011927a505aSKowalski, Kamil         // preparation
2012f12894f8SJason M. Bills         getEthernetIfaceData(
2013fda13ad2SSunitha Harish             params[1],
2014fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
2015fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
2016f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
2017e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2018d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
2019d1d50814SRavi Teja                     &ipv4StaticData,
2020e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2021e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
2022e48c0fc5SRavi Teja                     &ipv6StaticData) {
2023fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
20241abe55efSEd Tanous                 {
2025f12894f8SJason M. Bills                     auto callback =
2026f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
20271abe55efSEd Tanous                             if (ec)
20281abe55efSEd Tanous                             {
2029f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
2030927a505aSKowalski, Kamil                             }
20314a0cb85cSEd Tanous                         };
20324a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
20334a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
20344a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
20354a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
20361abe55efSEd Tanous                 }
20371abe55efSEd Tanous                 else
20381abe55efSEd Tanous                 {
2039927a505aSKowalski, Kamil                     // ... otherwise return error
2040f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
2041f12894f8SJason M. Bills                     // object, and other errors
2042f12894f8SJason M. Bills                     messages::resourceNotFound(
2043f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
2044927a505aSKowalski, Kamil                 }
2045927a505aSKowalski, Kamil             });
2046e439f0f8SKowalski, Kamil     }
2047e439f0f8SKowalski, Kamil };
2048e439f0f8SKowalski, Kamil 
2049e439f0f8SKowalski, Kamil /**
2050e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
2051e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
2052e439f0f8SKowalski, Kamil  */
20531abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
20541abe55efSEd Tanous {
2055e439f0f8SKowalski, Kamil   public:
2056e439f0f8SKowalski, Kamil     template <typename CrowApp>
20571abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
20584a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
20594a0cb85cSEd Tanous              std::string())
20601abe55efSEd Tanous     {
2061e439f0f8SKowalski, Kamil         entityPrivileges = {
2062e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
2063e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
2064e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2065e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2066e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2067e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2068e439f0f8SKowalski, Kamil     }
2069e439f0f8SKowalski, Kamil 
2070e439f0f8SKowalski, Kamil   private:
2071e439f0f8SKowalski, Kamil     /**
2072e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
2073e439f0f8SKowalski, Kamil      */
207455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
20751abe55efSEd Tanous                const std::vector<std::string> &params) override
20761abe55efSEd Tanous     {
20774a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
20781abe55efSEd Tanous         if (params.size() != 1)
20791abe55efSEd Tanous         {
2080e439f0f8SKowalski, Kamil             // This means there is a problem with the router
2081f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2082e439f0f8SKowalski, Kamil             return;
2083e439f0f8SKowalski, Kamil         }
2084e439f0f8SKowalski, Kamil 
20854a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
2086e439f0f8SKowalski, Kamil 
20874a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
20881abe55efSEd Tanous         // preparation
2089f12894f8SJason M. Bills         getEthernetIfaceList(
209043b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
20911abe55efSEd Tanous                 const bool &success,
20924c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
20934a0cb85cSEd Tanous                 if (!success)
20941abe55efSEd Tanous                 {
2095f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
20964a0cb85cSEd Tanous                     return;
20971abe55efSEd Tanous                 }
20984c9afe43SEd Tanous 
20994c9afe43SEd Tanous                 if (iface_list.find(rootInterfaceName) == iface_list.end())
21004c9afe43SEd Tanous                 {
21014c9afe43SEd Tanous                     messages::resourceNotFound(asyncResp->res,
21024c9afe43SEd Tanous                                                "VLanNetworkInterfaceCollection",
21034c9afe43SEd Tanous                                                rootInterfaceName);
21044c9afe43SEd Tanous                     return;
21054c9afe43SEd Tanous                 }
21064c9afe43SEd Tanous 
21070f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
21080f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
21090f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
21100f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
21110f74e643SEd Tanous                     "/redfish/v1/$metadata"
21120f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
21130f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
21140f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
21150f74e643SEd Tanous                     "VLAN Network Interface Collection";
21164a0cb85cSEd Tanous 
21174a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
21184a0cb85cSEd Tanous 
21194a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
21201abe55efSEd Tanous                 {
21214a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
21224a0cb85cSEd Tanous                     {
21234a0cb85cSEd Tanous                         iface_array.push_back(
21244a0cb85cSEd Tanous                             {{"@odata.id",
21254a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
21264a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
2127e439f0f8SKowalski, Kamil                     }
2128e439f0f8SKowalski, Kamil                 }
2129e439f0f8SKowalski, Kamil 
21304a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
21314a0cb85cSEd Tanous                     iface_array.size();
21324a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
21334a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
21344a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
21354a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
2136e439f0f8SKowalski, Kamil             });
2137e439f0f8SKowalski, Kamil     }
2138e439f0f8SKowalski, Kamil 
213955c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
21401abe55efSEd Tanous                 const std::vector<std::string> &params) override
21411abe55efSEd Tanous     {
21424a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
21431abe55efSEd Tanous         if (params.size() != 1)
21441abe55efSEd Tanous         {
2145f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2146e439f0f8SKowalski, Kamil             return;
2147e439f0f8SKowalski, Kamil         }
2148fda13ad2SSunitha Harish         bool vlanEnable = false;
21490627a2c7SEd Tanous         uint32_t vlanId = 0;
2150fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2151fda13ad2SSunitha Harish                                  vlanEnable))
21521abe55efSEd Tanous         {
21534a0cb85cSEd Tanous             return;
2154e439f0f8SKowalski, Kamil         }
2155fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
2156fda13ad2SSunitha Harish         if (!vlanId)
2157fda13ad2SSunitha Harish         {
2158fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
2159fda13ad2SSunitha Harish         }
2160fda13ad2SSunitha Harish         if (!vlanEnable)
2161fda13ad2SSunitha Harish         {
2162fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
2163fda13ad2SSunitha Harish         }
2164fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2165fda13ad2SSunitha Harish         {
2166fda13ad2SSunitha Harish             return;
2167fda13ad2SSunitha Harish         }
2168fda13ad2SSunitha Harish 
21694a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
21704a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
21711abe55efSEd Tanous             if (ec)
21721abe55efSEd Tanous             {
21734a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
21744a0cb85cSEd Tanous                 // phosphor-network responses
2175f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
21764a0cb85cSEd Tanous                 return;
21771abe55efSEd Tanous             }
2178f12894f8SJason M. Bills             messages::created(asyncResp->res);
2179e439f0f8SKowalski, Kamil         };
21804a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
21814a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
21824a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
21834a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
21840627a2c7SEd Tanous             rootInterfaceName, vlanId);
21854a0cb85cSEd Tanous     }
21864a0cb85cSEd Tanous };
21879391bb9cSRapkiewicz, Pawel } // namespace redfish
2188