xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision c619141b47d5aaa5227a2a9ef0ef8ee6f0bef22f)
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             {
858*c619141bSRavi Teja                 if (((ipv4.linktype == LinkType::Global) &&
859*c619141bSRavi Teja                      (ipv4.gateway == "0.0.0.0")) ||
860*c619141bSRavi 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;
1542f85837bfSRAJESWARAN THILLAIGOVINDAN         json_response["StaticNameServers"] = ethData.nameservers;
15434a0cb85cSEd Tanous 
15444a0cb85cSEd Tanous         nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
15454a0cb85cSEd Tanous         ipv4_array = nlohmann::json::array();
15464a0cb85cSEd Tanous         for (auto &ipv4_config : ipv4Data)
15474a0cb85cSEd Tanous         {
1548fa5053a6SGunnar Mills 
1549fa5053a6SGunnar Mills             std::string gatewayStr = ipv4_config.gateway;
1550fa5053a6SGunnar Mills             if (gatewayStr.empty())
1551fa5053a6SGunnar Mills             {
1552fa5053a6SGunnar Mills                 gatewayStr = "0.0.0.0";
1553fa5053a6SGunnar Mills             }
1554fa5053a6SGunnar Mills 
15554a0cb85cSEd Tanous             ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
15564a0cb85cSEd Tanous                                   {"SubnetMask", ipv4_config.netmask},
1557029573d4SEd Tanous                                   {"Address", ipv4_config.address},
1558fa5053a6SGunnar Mills                                   {"Gateway", gatewayStr}});
15594a0cb85cSEd Tanous         }
1560d1d50814SRavi Teja 
1561d1d50814SRavi Teja         nlohmann::json &ipv4_static_array =
1562d1d50814SRavi Teja             json_response["IPv4StaticAddresses"];
1563d1d50814SRavi Teja         ipv4_static_array = nlohmann::json::array();
1564d1d50814SRavi Teja         for (auto &ipv4_static_config : ipv4StaticData)
1565d1d50814SRavi Teja         {
1566d1d50814SRavi Teja 
1567d1d50814SRavi Teja             std::string gatewayStr = ipv4_static_config.gateway;
1568d1d50814SRavi Teja             if (gatewayStr.empty())
1569d1d50814SRavi Teja             {
1570d1d50814SRavi Teja                 gatewayStr = "0.0.0.0";
15714a0cb85cSEd Tanous             }
1572d1d50814SRavi Teja 
1573d1d50814SRavi Teja             ipv4_static_array.push_back(
1574d1d50814SRavi Teja                 {{"SubnetMask", ipv4_static_config.netmask},
1575d1d50814SRavi Teja                  {"Address", ipv4_static_config.address},
1576d1d50814SRavi Teja                  {"Gateway", gatewayStr}});
1577d1d50814SRavi Teja         }
1578d1d50814SRavi Teja 
15799a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1580e48c0fc5SRavi Teja 
1581e48c0fc5SRavi Teja         nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1582e48c0fc5SRavi Teja         ipv6_array = nlohmann::json::array();
1583e48c0fc5SRavi Teja         for (auto &ipv6_config : ipv6Data)
1584e48c0fc5SRavi Teja         {
1585e48c0fc5SRavi Teja             ipv6_array.push_back({{"Address", ipv6_config.address},
1586e48c0fc5SRavi Teja                                   {"PrefixLength", ipv6_config.prefixLength},
1587e48c0fc5SRavi Teja                                   {"AddressOrigin", ipv6_config.origin}});
1588e48c0fc5SRavi Teja         }
1589e48c0fc5SRavi Teja 
1590e48c0fc5SRavi Teja         nlohmann::json &ipv6_static_array =
1591e48c0fc5SRavi Teja             json_response["IPv6StaticAddresses"];
1592e48c0fc5SRavi Teja         ipv6_static_array = nlohmann::json::array();
1593e48c0fc5SRavi Teja         for (auto &ipv6_static_config : ipv6StaticData)
1594e48c0fc5SRavi Teja         {
1595e48c0fc5SRavi Teja             ipv6_static_array.push_back(
1596e48c0fc5SRavi Teja                 {{"Address", ipv6_static_config.address},
1597e48c0fc5SRavi Teja                  {"PrefixLength", ipv6_static_config.prefixLength}});
1598e48c0fc5SRavi Teja         }
1599588c3f0dSKowalski, Kamil     }
1600588c3f0dSKowalski, Kamil 
16019391bb9cSRapkiewicz, Pawel     /**
16029391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
16039391bb9cSRapkiewicz, Pawel      */
160455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
16051abe55efSEd Tanous                const std::vector<std::string> &params) override
16061abe55efSEd Tanous     {
16074a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16081abe55efSEd Tanous         if (params.size() != 1)
16091abe55efSEd Tanous         {
1610f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
16119391bb9cSRapkiewicz, Pawel             return;
16129391bb9cSRapkiewicz, Pawel         }
16139391bb9cSRapkiewicz, Pawel 
16144a0cb85cSEd Tanous         getEthernetIfaceData(
16154a0cb85cSEd Tanous             params[0],
16164a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
16174a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1618e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1619d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1620d1d50814SRavi Teja                     &ipv4StaticData,
1621e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1622e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1623e48c0fc5SRavi Teja                     &ipv6StaticData) {
16244a0cb85cSEd Tanous                 if (!success)
16251abe55efSEd Tanous                 {
16261abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16271abe55efSEd Tanous                     // object, and other errors
1628f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1629f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
16304a0cb85cSEd Tanous                     return;
16319391bb9cSRapkiewicz, Pawel                 }
16324c9afe43SEd Tanous 
16334c9afe43SEd Tanous                 // because this has no dependence on the interface at this
16344c9afe43SEd Tanous                 // point, it needs to be done after we know the interface
16354c9afe43SEd Tanous                 // exists, not before.
16364c9afe43SEd Tanous                 getDHCPConfigData(asyncResp);
16374c9afe43SEd Tanous 
16380f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1639fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
16400f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
16410f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
16420f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
16430f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
16440f74e643SEd Tanous                     "Management Network Interface";
16450f74e643SEd Tanous 
16460f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1647d1d50814SRavi Teja                                    ipv4Data, ipv4StaticData, ipv6Data,
1648d1d50814SRavi Teja                                    ipv6StaticData);
16499391bb9cSRapkiewicz, Pawel             });
16509391bb9cSRapkiewicz, Pawel     }
16519391bb9cSRapkiewicz, Pawel 
165255c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
16531abe55efSEd Tanous                  const std::vector<std::string> &params) override
16541abe55efSEd Tanous     {
16554a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16561abe55efSEd Tanous         if (params.size() != 1)
16571abe55efSEd Tanous         {
1658f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1659588c3f0dSKowalski, Kamil             return;
1660588c3f0dSKowalski, Kamil         }
1661588c3f0dSKowalski, Kamil 
16624a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1663588c3f0dSKowalski, Kamil 
1664bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1665d577665bSRatan Gupta         std::optional<std::string> macAddress;
16669a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1667f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1668d1d50814SRavi Teja         std::optional<nlohmann::json> ipv4StaticAddresses;
1669f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1670e48c0fc5SRavi Teja         std::optional<nlohmann::json> ipv6StaticAddresses;
1671f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
16725112e9b4SRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> nameServers;
1673da131a9aSJennifer Lee         std::optional<nlohmann::json> dhcpv4;
16740627a2c7SEd Tanous 
1675fda13ad2SSunitha Harish         if (!json_util::readJson(
1676fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
1677d1d50814SRavi Teja                 "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress",
1678d1d50814SRavi Teja                 macAddress, "StaticNameServers", staticNameServers,
1679d1d50814SRavi Teja                 "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses",
1680d1d50814SRavi Teja                 ipv6StaticAddresses, "NameServers", nameServers, "DHCPv4",
1681d1d50814SRavi Teja                 dhcpv4))
16821abe55efSEd Tanous         {
1683588c3f0dSKowalski, Kamil             return;
1684588c3f0dSKowalski, Kamil         }
1685f15aad37SRatan Gupta 
1686da131a9aSJennifer Lee         if (dhcpv4)
1687da131a9aSJennifer Lee         {
1688da131a9aSJennifer Lee             handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1689da131a9aSJennifer Lee         }
1690da131a9aSJennifer Lee 
16914a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1692588c3f0dSKowalski, Kamil         // preparation
16934a0cb85cSEd Tanous         getEthernetIfaceData(
16944a0cb85cSEd Tanous             iface_id,
1695fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1696fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
16970627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
1698d1d50814SRavi Teja              ipv4StaticAddresses = std::move(ipv4StaticAddresses),
16999a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1700e48c0fc5SRavi Teja              ipv6StaticAddresses = std::move(ipv6StaticAddresses),
17015112e9b4SRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers),
17025112e9b4SRAJESWARAN THILLAIGOVINDAN              nameServers = std::move(nameServers)](
17034a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1704e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1705d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1706d1d50814SRavi Teja                     &ipv4StaticData,
1707e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1708e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1709e48c0fc5SRavi Teja                     &ipv6StaticData) {
17101abe55efSEd Tanous                 if (!success)
17111abe55efSEd Tanous                 {
1712588c3f0dSKowalski, Kamil                     // ... otherwise return error
17131abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
17141abe55efSEd Tanous                     // object, and other errors
1715fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1716fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1717588c3f0dSKowalski, Kamil                     return;
1718588c3f0dSKowalski, Kamil                 }
1719588c3f0dSKowalski, Kamil 
17200627a2c7SEd Tanous                 if (hostname)
17211abe55efSEd Tanous                 {
17220627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
17231abe55efSEd Tanous                 }
17240627a2c7SEd Tanous 
1725d577665bSRatan Gupta                 if (macAddress)
1726d577665bSRatan Gupta                 {
1727d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1728d577665bSRatan Gupta                 }
1729d577665bSRatan Gupta 
17300627a2c7SEd Tanous                 if (ipv4Addresses)
17311abe55efSEd Tanous                 {
1732d1d50814SRavi Teja                     messages::propertyNotWritable(asyncResp->res,
1733d1d50814SRavi Teja                                                   "IPv4Addresses");
1734d1d50814SRavi Teja                 }
1735d1d50814SRavi Teja 
1736d1d50814SRavi Teja                 if (ipv4StaticAddresses)
1737d1d50814SRavi Teja                 {
1738537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1739537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1740537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1741537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1742537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1743537174c4SEd Tanous                     // on that, but could be done more efficiently
1744d1d50814SRavi Teja                     nlohmann::json ipv4Static = std::move(*ipv4StaticAddresses);
1745d1d50814SRavi Teja                     handleIPv4StaticPatch(iface_id, ipv4Static, ipv4StaticData,
1746d1d50814SRavi Teja                                           asyncResp);
17471abe55efSEd Tanous                 }
17480627a2c7SEd Tanous 
17495112e9b4SRAJESWARAN THILLAIGOVINDAN                 if (nameServers)
17505112e9b4SRAJESWARAN THILLAIGOVINDAN                 {
17515112e9b4SRAJESWARAN THILLAIGOVINDAN                     // Data.Permissions is read-only
17525112e9b4SRAJESWARAN THILLAIGOVINDAN                     messages::propertyNotWritable(asyncResp->res,
17535112e9b4SRAJESWARAN THILLAIGOVINDAN                                                   "NameServers");
17545112e9b4SRAJESWARAN THILLAIGOVINDAN                 }
17555112e9b4SRAJESWARAN THILLAIGOVINDAN 
1756f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1757f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1758f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1759f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1760f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
17619a6fc6feSRavi Teja 
17629a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
17639a6fc6feSRavi Teja                 {
17649a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
17659a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
17669a6fc6feSRavi Teja                 }
1767e48c0fc5SRavi Teja 
1768e48c0fc5SRavi Teja                 if (ipv6StaticAddresses)
1769e48c0fc5SRavi Teja                 {
1770e48c0fc5SRavi Teja                     nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1771e48c0fc5SRavi Teja                     handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1772e48c0fc5SRavi Teja                                                    ipv6StaticData, asyncResp);
1773e48c0fc5SRavi Teja                 }
1774588c3f0dSKowalski, Kamil             });
1775588c3f0dSKowalski, Kamil     }
17769391bb9cSRapkiewicz, Pawel };
17779391bb9cSRapkiewicz, Pawel 
1778e439f0f8SKowalski, Kamil /**
17794a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
17804a0cb85cSEd Tanous  * Schema
1781e439f0f8SKowalski, Kamil  */
17821abe55efSEd Tanous class VlanNetworkInterface : public Node
17831abe55efSEd Tanous {
1784e439f0f8SKowalski, Kamil   public:
1785e439f0f8SKowalski, Kamil     /*
1786e439f0f8SKowalski, Kamil      * Default Constructor
1787e439f0f8SKowalski, Kamil      */
1788e439f0f8SKowalski, Kamil     template <typename CrowApp>
17891abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
17904a0cb85cSEd Tanous         Node(app,
17910f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
17921abe55efSEd Tanous              std::string(), std::string())
17931abe55efSEd Tanous     {
1794e439f0f8SKowalski, Kamil         entityPrivileges = {
1795e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1796e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1797e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1798e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1799e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1800e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1801e439f0f8SKowalski, Kamil     }
1802e439f0f8SKowalski, Kamil 
1803e439f0f8SKowalski, Kamil   private:
18040f74e643SEd Tanous     void parseInterfaceData(
18050f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
18060f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
1807e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1808d1d50814SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4StaticData,
1809e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1810e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
18111abe55efSEd Tanous     {
1812e439f0f8SKowalski, Kamil         // Fill out obvious data...
18134a0cb85cSEd Tanous         json_response["Id"] = iface_id;
18144a0cb85cSEd Tanous         json_response["@odata.id"] =
18154a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
18164a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1817e439f0f8SKowalski, Kamil 
18184a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1819fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
18204a0cb85cSEd Tanous         {
1821fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
18224a0cb85cSEd Tanous         }
1823e439f0f8SKowalski, Kamil     }
1824e439f0f8SKowalski, Kamil 
1825fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
18261abe55efSEd Tanous     {
18271abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
18281abe55efSEd Tanous         {
1829927a505aSKowalski, Kamil             return false;
18301abe55efSEd Tanous         }
18311abe55efSEd Tanous         else
18321abe55efSEd Tanous         {
1833927a505aSKowalski, Kamil             return true;
1834927a505aSKowalski, Kamil         }
1835927a505aSKowalski, Kamil     }
1836927a505aSKowalski, Kamil 
1837e439f0f8SKowalski, Kamil     /**
1838e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1839e439f0f8SKowalski, Kamil      */
184055c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
18411abe55efSEd Tanous                const std::vector<std::string> &params) override
18421abe55efSEd Tanous     {
18434a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18444a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1845e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1846e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1847e439f0f8SKowalski, Kamil         // impossible.
18481abe55efSEd Tanous         if (params.size() != 2)
18491abe55efSEd Tanous         {
1850f12894f8SJason M. Bills             messages::internalError(res);
1851e439f0f8SKowalski, Kamil             res.end();
1852e439f0f8SKowalski, Kamil             return;
1853e439f0f8SKowalski, Kamil         }
1854e439f0f8SKowalski, Kamil 
18554a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
18564a0cb85cSEd Tanous         const std::string &iface_id = params[1];
18570f74e643SEd Tanous         res.jsonValue["@odata.type"] =
18580f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
18590f74e643SEd Tanous         res.jsonValue["@odata.context"] =
18600f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
18610f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1862e439f0f8SKowalski, Kamil 
1863fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
18641abe55efSEd Tanous         {
1865a434f2bdSEd Tanous             return;
1866a434f2bdSEd Tanous         }
1867a434f2bdSEd Tanous 
1868e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1869e439f0f8SKowalski, Kamil         // preparation
18704a0cb85cSEd Tanous         getEthernetIfaceData(
1871fda13ad2SSunitha Harish             params[1],
1872fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1873fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
18744a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1875e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1876d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1877d1d50814SRavi Teja                     &ipv4StaticData,
1878e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1879e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1880e48c0fc5SRavi Teja                     &ipv6StaticData) {
1881fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
18821abe55efSEd Tanous                 {
18830f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
18840f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
1885d1d50814SRavi Teja                                        ipv4Data, ipv4StaticData, ipv6Data,
1886d1d50814SRavi Teja                                        ipv6StaticData);
18871abe55efSEd Tanous                 }
18881abe55efSEd Tanous                 else
18891abe55efSEd Tanous                 {
1890e439f0f8SKowalski, Kamil                     // ... otherwise return error
18911abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
18921abe55efSEd Tanous                     // object, and other errors
1893f12894f8SJason M. Bills                     messages::resourceNotFound(
1894f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1895e439f0f8SKowalski, Kamil                 }
1896e439f0f8SKowalski, Kamil             });
1897e439f0f8SKowalski, Kamil     }
1898e439f0f8SKowalski, Kamil 
189955c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
19001abe55efSEd Tanous                  const std::vector<std::string> &params) override
19011abe55efSEd Tanous     {
19024a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19031abe55efSEd Tanous         if (params.size() != 2)
19041abe55efSEd Tanous         {
1905f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1906e439f0f8SKowalski, Kamil             return;
1907e439f0f8SKowalski, Kamil         }
1908e439f0f8SKowalski, Kamil 
1909d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
191055c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1911927a505aSKowalski, Kamil 
1912fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
19131abe55efSEd Tanous         {
1914fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1915fda13ad2SSunitha Harish                                        ifaceId);
1916927a505aSKowalski, Kamil             return;
1917927a505aSKowalski, Kamil         }
1918927a505aSKowalski, Kamil 
19190627a2c7SEd Tanous         bool vlanEnable = false;
19200627a2c7SEd Tanous         uint64_t vlanId = 0;
19210627a2c7SEd Tanous 
19220627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
19230627a2c7SEd Tanous                                  vlanId))
19241abe55efSEd Tanous         {
1925927a505aSKowalski, Kamil             return;
1926927a505aSKowalski, Kamil         }
1927927a505aSKowalski, Kamil 
1928927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1929927a505aSKowalski, Kamil         // preparation
1930e48c0fc5SRavi Teja         getEthernetIfaceData(
1931e48c0fc5SRavi Teja             params[1],
1932e48c0fc5SRavi Teja             [this, asyncResp, parentIfaceId{std::string(params[0])},
1933e48c0fc5SRavi Teja              ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1934e48c0fc5SRavi Teja                 const bool &success, const EthernetInterfaceData &ethData,
1935e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1936d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
1937d1d50814SRavi Teja                     &ipv4StaticData,
1938e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1939e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1940e48c0fc5SRavi Teja                     &ipv6StaticData) {
194108244d02SSunitha Harish                 if (success && !ethData.vlan_id.empty())
194208244d02SSunitha Harish                 {
194308244d02SSunitha Harish                     auto callback =
194408244d02SSunitha Harish                         [asyncResp](const boost::system::error_code ec) {
194508244d02SSunitha Harish                             if (ec)
194608244d02SSunitha Harish                             {
194708244d02SSunitha Harish                                 messages::internalError(asyncResp->res);
194808244d02SSunitha Harish                             }
194908244d02SSunitha Harish                         };
195008244d02SSunitha Harish 
195108244d02SSunitha Harish                     if (vlanEnable == true)
195208244d02SSunitha Harish                     {
195308244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
195408244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
195508244d02SSunitha Harish                             "/xyz/openbmc_project/network/" + ifaceId,
195608244d02SSunitha Harish                             "org.freedesktop.DBus.Properties", "Set",
195708244d02SSunitha Harish                             "xyz.openbmc_project.Network.VLAN", "Id",
195808244d02SSunitha Harish                             std::variant<uint32_t>(vlanId));
195908244d02SSunitha Harish                     }
196008244d02SSunitha Harish                     else
196108244d02SSunitha Harish                     {
1962e48c0fc5SRavi Teja                         BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1963e48c0fc5SRavi Teja                                             "vlan interface";
196408244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
196508244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
1966e48c0fc5SRavi Teja                             std::string("/xyz/openbmc_project/network/") +
1967e48c0fc5SRavi Teja                                 ifaceId,
196808244d02SSunitha Harish                             "xyz.openbmc_project.Object.Delete", "Delete");
196908244d02SSunitha Harish                     }
197008244d02SSunitha Harish                 }
197108244d02SSunitha Harish                 else
19721abe55efSEd Tanous                 {
19731abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
19741abe55efSEd Tanous                     // object, and other errors
1975e48c0fc5SRavi Teja                     messages::resourceNotFound(
1976e48c0fc5SRavi Teja                         asyncResp->res, "VLAN Network Interface", ifaceId);
1977927a505aSKowalski, Kamil                     return;
1978927a505aSKowalski, Kamil                 }
1979927a505aSKowalski, Kamil             });
1980e439f0f8SKowalski, Kamil     }
1981e439f0f8SKowalski, Kamil 
198255c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
19831abe55efSEd Tanous                   const std::vector<std::string> &params) override
19841abe55efSEd Tanous     {
19854a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19861abe55efSEd Tanous         if (params.size() != 2)
19871abe55efSEd Tanous         {
1988f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1989e439f0f8SKowalski, Kamil             return;
1990e439f0f8SKowalski, Kamil         }
1991e439f0f8SKowalski, Kamil 
1992d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
199355c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1994927a505aSKowalski, Kamil 
1995fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
19961abe55efSEd Tanous         {
1997fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1998fda13ad2SSunitha Harish                                        ifaceId);
1999927a505aSKowalski, Kamil             return;
2000927a505aSKowalski, Kamil         }
2001927a505aSKowalski, Kamil 
2002927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
2003927a505aSKowalski, Kamil         // preparation
2004f12894f8SJason M. Bills         getEthernetIfaceData(
2005fda13ad2SSunitha Harish             params[1],
2006fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
2007fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
2008f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
2009e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2010d1d50814SRavi Teja                 const boost::container::flat_set<IPv4AddressData>
2011d1d50814SRavi Teja                     &ipv4StaticData,
2012e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2013e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
2014e48c0fc5SRavi Teja                     &ipv6StaticData) {
2015fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
20161abe55efSEd Tanous                 {
2017f12894f8SJason M. Bills                     auto callback =
2018f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
20191abe55efSEd Tanous                             if (ec)
20201abe55efSEd Tanous                             {
2021f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
2022927a505aSKowalski, Kamil                             }
20234a0cb85cSEd Tanous                         };
20244a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
20254a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
20264a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
20274a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
20281abe55efSEd Tanous                 }
20291abe55efSEd Tanous                 else
20301abe55efSEd Tanous                 {
2031927a505aSKowalski, Kamil                     // ... otherwise return error
2032f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
2033f12894f8SJason M. Bills                     // object, and other errors
2034f12894f8SJason M. Bills                     messages::resourceNotFound(
2035f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
2036927a505aSKowalski, Kamil                 }
2037927a505aSKowalski, Kamil             });
2038e439f0f8SKowalski, Kamil     }
2039e439f0f8SKowalski, Kamil };
2040e439f0f8SKowalski, Kamil 
2041e439f0f8SKowalski, Kamil /**
2042e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
2043e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
2044e439f0f8SKowalski, Kamil  */
20451abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
20461abe55efSEd Tanous {
2047e439f0f8SKowalski, Kamil   public:
2048e439f0f8SKowalski, Kamil     template <typename CrowApp>
20491abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
20504a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
20514a0cb85cSEd Tanous              std::string())
20521abe55efSEd Tanous     {
2053e439f0f8SKowalski, Kamil         entityPrivileges = {
2054e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
2055e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
2056e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2057e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2058e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2059e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2060e439f0f8SKowalski, Kamil     }
2061e439f0f8SKowalski, Kamil 
2062e439f0f8SKowalski, Kamil   private:
2063e439f0f8SKowalski, Kamil     /**
2064e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
2065e439f0f8SKowalski, Kamil      */
206655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
20671abe55efSEd Tanous                const std::vector<std::string> &params) override
20681abe55efSEd Tanous     {
20694a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
20701abe55efSEd Tanous         if (params.size() != 1)
20711abe55efSEd Tanous         {
2072e439f0f8SKowalski, Kamil             // This means there is a problem with the router
2073f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2074e439f0f8SKowalski, Kamil             return;
2075e439f0f8SKowalski, Kamil         }
2076e439f0f8SKowalski, Kamil 
20774a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
2078e439f0f8SKowalski, Kamil 
20794a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
20801abe55efSEd Tanous         // preparation
2081f12894f8SJason M. Bills         getEthernetIfaceList(
208243b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
20831abe55efSEd Tanous                 const bool &success,
20844c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
20854a0cb85cSEd Tanous                 if (!success)
20861abe55efSEd Tanous                 {
2087f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
20884a0cb85cSEd Tanous                     return;
20891abe55efSEd Tanous                 }
20904c9afe43SEd Tanous 
20914c9afe43SEd Tanous                 if (iface_list.find(rootInterfaceName) == iface_list.end())
20924c9afe43SEd Tanous                 {
20934c9afe43SEd Tanous                     messages::resourceNotFound(asyncResp->res,
20944c9afe43SEd Tanous                                                "VLanNetworkInterfaceCollection",
20954c9afe43SEd Tanous                                                rootInterfaceName);
20964c9afe43SEd Tanous                     return;
20974c9afe43SEd Tanous                 }
20984c9afe43SEd Tanous 
20990f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
21000f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
21010f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
21020f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
21030f74e643SEd Tanous                     "/redfish/v1/$metadata"
21040f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
21050f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
21060f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
21070f74e643SEd Tanous                     "VLAN Network Interface Collection";
21084a0cb85cSEd Tanous 
21094a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
21104a0cb85cSEd Tanous 
21114a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
21121abe55efSEd Tanous                 {
21134a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
21144a0cb85cSEd Tanous                     {
21154a0cb85cSEd Tanous                         iface_array.push_back(
21164a0cb85cSEd Tanous                             {{"@odata.id",
21174a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
21184a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
2119e439f0f8SKowalski, Kamil                     }
2120e439f0f8SKowalski, Kamil                 }
2121e439f0f8SKowalski, Kamil 
21224a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
21234a0cb85cSEd Tanous                     iface_array.size();
21244a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
21254a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
21264a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
21274a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
2128e439f0f8SKowalski, Kamil             });
2129e439f0f8SKowalski, Kamil     }
2130e439f0f8SKowalski, Kamil 
213155c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
21321abe55efSEd Tanous                 const std::vector<std::string> &params) override
21331abe55efSEd Tanous     {
21344a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
21351abe55efSEd Tanous         if (params.size() != 1)
21361abe55efSEd Tanous         {
2137f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2138e439f0f8SKowalski, Kamil             return;
2139e439f0f8SKowalski, Kamil         }
2140fda13ad2SSunitha Harish         bool vlanEnable = false;
21410627a2c7SEd Tanous         uint32_t vlanId = 0;
2142fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2143fda13ad2SSunitha Harish                                  vlanEnable))
21441abe55efSEd Tanous         {
21454a0cb85cSEd Tanous             return;
2146e439f0f8SKowalski, Kamil         }
2147fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
2148fda13ad2SSunitha Harish         if (!vlanId)
2149fda13ad2SSunitha Harish         {
2150fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
2151fda13ad2SSunitha Harish         }
2152fda13ad2SSunitha Harish         if (!vlanEnable)
2153fda13ad2SSunitha Harish         {
2154fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
2155fda13ad2SSunitha Harish         }
2156fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2157fda13ad2SSunitha Harish         {
2158fda13ad2SSunitha Harish             return;
2159fda13ad2SSunitha Harish         }
2160fda13ad2SSunitha Harish 
21614a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
21624a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
21631abe55efSEd Tanous             if (ec)
21641abe55efSEd Tanous             {
21654a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
21664a0cb85cSEd Tanous                 // phosphor-network responses
2167f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
21684a0cb85cSEd Tanous                 return;
21691abe55efSEd Tanous             }
2170f12894f8SJason M. Bills             messages::created(asyncResp->res);
2171e439f0f8SKowalski, Kamil         };
21724a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
21734a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
21744a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
21754a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
21760627a2c7SEd Tanous             rootInterfaceName, vlanId);
21774a0cb85cSEd Tanous     }
21784a0cb85cSEd Tanous };
21799391bb9cSRapkiewicz, Pawel } // namespace redfish
2180