xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision d24bfc7a855e9d209ada9452077f190971dae9cf)
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;
103*d24bfc7aSJennifer 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                         }
240*d24bfc7aSJennifer Lee                         else if (propertyPair.first == "DomainName")
241*d24bfc7aSJennifer Lee                         {
242*d24bfc7aSJennifer Lee                             const std::vector<std::string> *domainNames =
243*d24bfc7aSJennifer Lee                                 sdbusplus::message::variant_ns::get_if<
244*d24bfc7aSJennifer Lee                                     std::vector<std::string>>(
245*d24bfc7aSJennifer Lee                                     &propertyPair.second);
246*d24bfc7aSJennifer Lee                             if (domainNames != nullptr)
247*d24bfc7aSJennifer Lee                             {
248*d24bfc7aSJennifer Lee                                 ethData.domainnames = std::move(*domainNames);
249*d24bfc7aSJennifer Lee                             }
250*d24bfc7aSJennifer 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
3854a0cb85cSEd Tanous inline void
3864a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
3874a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
3884a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_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                     }
4604a0cb85cSEd Tanous                     // Check if given address is local, or global
4614a0cb85cSEd Tanous                     ipv4_address.linktype =
4624a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
46318659d10SJohnathan Mantey                             ? LinkType::Local
46418659d10SJohnathan Mantey                             : LinkType::Global;
4654a0cb85cSEd Tanous                 }
4664a0cb85cSEd Tanous             }
4674a0cb85cSEd Tanous         }
4684a0cb85cSEd Tanous     }
4694a0cb85cSEd Tanous }
470588c3f0dSKowalski, Kamil 
471588c3f0dSKowalski, Kamil /**
472588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
473588c3f0dSKowalski, Kamil  *
474588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
475588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
476588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
477588c3f0dSKowalski, Kamil  *
478588c3f0dSKowalski, Kamil  * @return None.
479588c3f0dSKowalski, Kamil  */
480588c3f0dSKowalski, Kamil template <typename CallbackFunc>
4814a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
4821abe55efSEd Tanous                   CallbackFunc &&callback)
4831abe55efSEd Tanous {
48455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
485588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
486588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
487588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
488588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
489abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
4904a0cb85cSEd Tanous }
491588c3f0dSKowalski, Kamil 
492588c3f0dSKowalski, Kamil /**
493179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
494179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
495179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
496179db1d7SKowalski, Kamil  *
497179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
498179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
499179db1d7SKowalski, Kamil  *
500179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
501179db1d7SKowalski, Kamil  */
5024a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
5031abe55efSEd Tanous                                        uint8_t *bits = nullptr)
5041abe55efSEd Tanous {
505179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
506179db1d7SKowalski, Kamil 
507179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
508179db1d7SKowalski, Kamil 
5094a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
5101abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
5111abe55efSEd Tanous     {
512179db1d7SKowalski, Kamil         return false;
513179db1d7SKowalski, Kamil     }
514179db1d7SKowalski, Kamil 
5151abe55efSEd Tanous     if (bits != nullptr)
5161abe55efSEd Tanous     {
517179db1d7SKowalski, Kamil         *bits = 0;
518179db1d7SKowalski, Kamil     }
519179db1d7SKowalski, Kamil 
520179db1d7SKowalski, Kamil     char *endPtr;
521179db1d7SKowalski, Kamil     long previousValue = 255;
522179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
5231abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
5241abe55efSEd Tanous     {
5251abe55efSEd Tanous         if (byte.empty())
5261abe55efSEd Tanous         {
5271db9ca37SKowalski, Kamil             return false;
5281db9ca37SKowalski, Kamil         }
5291db9ca37SKowalski, Kamil 
530179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
5311db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
532179db1d7SKowalski, Kamil 
5334a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
5344a0cb85cSEd Tanous         // is not 100% number
5351abe55efSEd Tanous         if (*endPtr != '\0')
5361abe55efSEd Tanous         {
537179db1d7SKowalski, Kamil             return false;
538179db1d7SKowalski, Kamil         }
539179db1d7SKowalski, Kamil 
540179db1d7SKowalski, Kamil         // Value should be contained in byte
5411abe55efSEd Tanous         if (value < 0 || value > 255)
5421abe55efSEd Tanous         {
543179db1d7SKowalski, Kamil             return false;
544179db1d7SKowalski, Kamil         }
545179db1d7SKowalski, Kamil 
5461abe55efSEd Tanous         if (bits != nullptr)
5471abe55efSEd Tanous         {
548179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
5491abe55efSEd Tanous             if (previousValue != 255 && value != 0)
5501abe55efSEd Tanous             {
551179db1d7SKowalski, Kamil                 return false;
552179db1d7SKowalski, Kamil             }
553179db1d7SKowalski, Kamil 
554179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
555179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
556179db1d7SKowalski, Kamil 
557179db1d7SKowalski, Kamil             // Count bits
5581abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
5591abe55efSEd Tanous             {
5601abe55efSEd Tanous                 if (value & (1 << bitIdx))
5611abe55efSEd Tanous                 {
5621abe55efSEd Tanous                     if (firstZeroInByteHit)
5631abe55efSEd Tanous                     {
564179db1d7SKowalski, Kamil                         // Continuity not preserved
565179db1d7SKowalski, Kamil                         return false;
5661abe55efSEd Tanous                     }
5671abe55efSEd Tanous                     else
5681abe55efSEd Tanous                     {
569179db1d7SKowalski, Kamil                         (*bits)++;
570179db1d7SKowalski, Kamil                     }
5711abe55efSEd Tanous                 }
5721abe55efSEd Tanous                 else
5731abe55efSEd Tanous                 {
574179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
575179db1d7SKowalski, Kamil                 }
576179db1d7SKowalski, Kamil             }
577179db1d7SKowalski, Kamil         }
578179db1d7SKowalski, Kamil 
579179db1d7SKowalski, Kamil         previousValue = value;
580179db1d7SKowalski, Kamil     }
581179db1d7SKowalski, Kamil 
582179db1d7SKowalski, Kamil     return true;
583179db1d7SKowalski, Kamil }
584179db1d7SKowalski, Kamil 
585179db1d7SKowalski, Kamil /**
586b01bf299SEd Tanous  * @brief Changes IPv4 address type property (Address, Gateway)
587b01bf299SEd Tanous  *
588b01bf299SEd Tanous  * @param[in] ifaceId     Id of interface whose IP should be modified
589b01bf299SEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
590b01bf299SEd Tanous  * @param[in] ipHash      DBus Hash id of modified IP
591b01bf299SEd Tanous  * @param[in] name        Name of field in JSON representation
592b01bf299SEd Tanous  * @param[in] newValue    New value that should be written
593b01bf299SEd Tanous  * @param[io] asyncResp   Response object that will be returned to client
594b01bf299SEd Tanous  *
595b01bf299SEd Tanous  * @return true if give IP is valid and has been sent do D-Bus, false
596b01bf299SEd Tanous  * otherwise
597b01bf299SEd Tanous  */
598b01bf299SEd Tanous inline void changeIPv4AddressProperty(
599b01bf299SEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
600b01bf299SEd Tanous     const std::string &name, const std::string &newValue,
601b01bf299SEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
602b01bf299SEd Tanous {
603286b9118SJohnathan Mantey     auto callback =
604286b9118SJohnathan Mantey         [asyncResp, ipIdx, name{std::string(name)},
605286b9118SJohnathan Mantey          newValue{std::move(newValue)}](const boost::system::error_code ec) {
606b01bf299SEd Tanous             if (ec)
607b01bf299SEd Tanous             {
608b01bf299SEd Tanous                 messages::internalError(asyncResp->res);
609b01bf299SEd Tanous             }
610b01bf299SEd Tanous         };
611b01bf299SEd Tanous 
612b01bf299SEd Tanous     crow::connections::systemBus->async_method_call(
613b01bf299SEd Tanous         std::move(callback), "xyz.openbmc_project.Network",
614b01bf299SEd Tanous         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
615b01bf299SEd Tanous         "org.freedesktop.DBus.Properties", "Set",
616b01bf299SEd Tanous         "xyz.openbmc_project.Network.IP", name,
617b01bf299SEd Tanous         std::variant<std::string>(newValue));
618b01bf299SEd Tanous }
619b01bf299SEd Tanous 
620b01bf299SEd Tanous /**
621179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
622179db1d7SKowalski, Kamil  *
623179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
6244a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
6251abe55efSEd Tanous  * modified
626179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
627179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
628179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
629179db1d7SKowalski, Kamil  *
630179db1d7SKowalski, Kamil  * @return None
631179db1d7SKowalski, Kamil  */
632b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
6334a0cb85cSEd Tanous                                          const std::string &ipHash,
6344a0cb85cSEd Tanous                                          uint8_t &newValue,
6354a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
6361abe55efSEd Tanous {
637286b9118SJohnathan Mantey     auto callback = [asyncResp, ipIdx](const boost::system::error_code ec) {
6381abe55efSEd Tanous         if (ec)
6391abe55efSEd Tanous         {
640a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
6411abe55efSEd Tanous         }
642179db1d7SKowalski, Kamil     };
643179db1d7SKowalski, Kamil 
64455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
645179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
646179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
647179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
648179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
649abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
6504a0cb85cSEd Tanous }
651588c3f0dSKowalski, Kamil 
652588c3f0dSKowalski, Kamil /**
653179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
654179db1d7SKowalski, Kamil  *
655179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
656179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
657179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
658179db1d7SKowalski, Kamil  *
659179db1d7SKowalski, Kamil  * @return None
660179db1d7SKowalski, Kamil  */
6614a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
6624a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6631abe55efSEd Tanous {
66455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
665286b9118SJohnathan Mantey         [asyncResp](const boost::system::error_code ec) {
6661abe55efSEd Tanous             if (ec)
6671abe55efSEd Tanous             {
668a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6691abe55efSEd Tanous             }
670179db1d7SKowalski, Kamil         },
671179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
672179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
673179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
674179db1d7SKowalski, Kamil }
675179db1d7SKowalski, Kamil 
676179db1d7SKowalski, Kamil /**
677179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
678179db1d7SKowalski, Kamil  *
679179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6804a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
681179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
682179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
683179db1d7SKowalski, Kamil  *
684179db1d7SKowalski, Kamil  * @return None
685179db1d7SKowalski, Kamil  */
686b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
687b01bf299SEd Tanous                        uint8_t subnetMask, const std::string &gateway,
688b01bf299SEd Tanous                        const std::string &address,
6894a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6901abe55efSEd Tanous {
69143b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
6921abe55efSEd Tanous         if (ec)
6931abe55efSEd Tanous         {
694a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
695179db1d7SKowalski, Kamil         }
696179db1d7SKowalski, Kamil     };
697179db1d7SKowalski, Kamil 
69855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
699179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
700179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
701179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
702179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
703179db1d7SKowalski, Kamil         gateway);
704179db1d7SKowalski, Kamil }
705e48c0fc5SRavi Teja 
706e48c0fc5SRavi Teja /**
707e48c0fc5SRavi Teja  * @brief Deletes given IPv6
708e48c0fc5SRavi Teja  *
709e48c0fc5SRavi Teja  * @param[in] ifaceId     Id of interface whose IP should be deleted
710e48c0fc5SRavi Teja  * @param[in] ipHash      DBus Hash id of IP that should be deleted
711e48c0fc5SRavi Teja  * @param[io] asyncResp   Response object that will be returned to client
712e48c0fc5SRavi Teja  *
713e48c0fc5SRavi Teja  * @return None
714e48c0fc5SRavi Teja  */
715e48c0fc5SRavi Teja inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
716e48c0fc5SRavi Teja                        const std::shared_ptr<AsyncResp> asyncResp)
717e48c0fc5SRavi Teja {
718e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
719286b9118SJohnathan Mantey         [asyncResp](const boost::system::error_code ec) {
720e48c0fc5SRavi Teja             if (ec)
721e48c0fc5SRavi Teja             {
722e48c0fc5SRavi Teja                 messages::internalError(asyncResp->res);
723e48c0fc5SRavi Teja             }
724e48c0fc5SRavi Teja         },
725e48c0fc5SRavi Teja         "xyz.openbmc_project.Network",
726e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
727e48c0fc5SRavi Teja         "xyz.openbmc_project.Object.Delete", "Delete");
728e48c0fc5SRavi Teja }
729e48c0fc5SRavi Teja 
730e48c0fc5SRavi Teja /**
731e48c0fc5SRavi Teja  * @brief Creates IPv6 with given data
732e48c0fc5SRavi Teja  *
733e48c0fc5SRavi Teja  * @param[in] ifaceId      Id of interface whose IP should be added
734e48c0fc5SRavi Teja  * @param[in] ipIdx        Index of IP in input array that should be added
735e48c0fc5SRavi Teja  * @param[in] prefixLength Prefix length that needs to be added
736e48c0fc5SRavi Teja  * @param[in] address      IP address that needs to be added
737e48c0fc5SRavi Teja  * @param[io] asyncResp    Response object that will be returned to client
738e48c0fc5SRavi Teja  *
739e48c0fc5SRavi Teja  * @return None
740e48c0fc5SRavi Teja  */
741e48c0fc5SRavi Teja inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
742e48c0fc5SRavi Teja                        uint8_t prefixLength, const std::string &address,
743e48c0fc5SRavi Teja                        std::shared_ptr<AsyncResp> asyncResp)
744e48c0fc5SRavi Teja {
745e48c0fc5SRavi Teja     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
746e48c0fc5SRavi Teja         if (ec)
747e48c0fc5SRavi Teja         {
748e48c0fc5SRavi Teja             messages::internalError(asyncResp->res);
749e48c0fc5SRavi Teja         }
750e48c0fc5SRavi Teja     };
751e48c0fc5SRavi Teja     // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
752e48c0fc5SRavi Teja     // does not have assosiated gateway property
753e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
754e48c0fc5SRavi Teja         std::move(createIpHandler), "xyz.openbmc_project.Network",
755e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId,
756e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Create", "IP",
757e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
758e48c0fc5SRavi Teja         "");
759e48c0fc5SRavi Teja }
760e48c0fc5SRavi Teja 
7612a133282Smanojkiraneda using GetAllPropertiesType =
7622a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
7632a133282Smanojkiraneda 
7642a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
7652a133282Smanojkiraneda {
7662a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
7672a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
7682a133282Smanojkiraneda         if (error_code)
7692a133282Smanojkiraneda         {
7702a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
7712a133282Smanojkiraneda             messages::internalError(asyncResp->res);
7722a133282Smanojkiraneda             return;
7732a133282Smanojkiraneda         }
774fda13ad2SSunitha Harish         nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
7752a133282Smanojkiraneda         for (const auto &property : dbus_data)
7762a133282Smanojkiraneda         {
7772a133282Smanojkiraneda             auto value =
7782a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
7792a133282Smanojkiraneda 
7802a133282Smanojkiraneda             if (value == nullptr)
7812a133282Smanojkiraneda             {
7822a133282Smanojkiraneda                 continue;
7832a133282Smanojkiraneda             }
7842a133282Smanojkiraneda             if (property.first == "DNSEnabled")
7852a133282Smanojkiraneda             {
7862a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
7872a133282Smanojkiraneda             }
7882a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
7892a133282Smanojkiraneda             {
7902a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
7912a133282Smanojkiraneda             }
7922a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
7932a133282Smanojkiraneda             {
7942a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
7952a133282Smanojkiraneda             }
7962a133282Smanojkiraneda         }
7972a133282Smanojkiraneda     };
7982a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
7992a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
8002a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
8012a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
8022a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
8032a133282Smanojkiraneda }
804179db1d7SKowalski, Kamil 
805179db1d7SKowalski, Kamil /**
806179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
807179db1d7SKowalski, Kamil  * Object
808179db1d7SKowalski, Kamil  * from EntityManager Network Manager
8094a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
810179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
811179db1d7SKowalski, Kamil  * into JSON
812179db1d7SKowalski, Kamil  */
813179db1d7SKowalski, Kamil template <typename CallbackFunc>
8144a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
8151abe55efSEd Tanous                           CallbackFunc &&callback)
8161abe55efSEd Tanous {
81755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
8184a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
8191abe55efSEd Tanous             const boost::system::error_code error_code,
8204a0cb85cSEd Tanous             const GetManagedObjects &resp) {
82155c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
8224a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
823e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6Data;
824e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6StaticData;
825179db1d7SKowalski, Kamil 
8261abe55efSEd Tanous             if (error_code)
8271abe55efSEd Tanous             {
828e48c0fc5SRavi Teja                 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
829179db1d7SKowalski, Kamil                 return;
830179db1d7SKowalski, Kamil             }
831179db1d7SKowalski, Kamil 
8324c9afe43SEd Tanous             bool found =
8334a0cb85cSEd Tanous                 extractEthernetInterfaceData(ethiface_id, resp, ethData);
8344c9afe43SEd Tanous             if (!found)
8354c9afe43SEd Tanous             {
836e48c0fc5SRavi Teja                 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
8374c9afe43SEd Tanous                 return;
8384c9afe43SEd Tanous             }
8394c9afe43SEd Tanous 
8404a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
841179db1d7SKowalski, Kamil             // Fix global GW
8421abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
8431abe55efSEd Tanous             {
8444a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
8454a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
8461abe55efSEd Tanous                 {
8474a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
848179db1d7SKowalski, Kamil                 }
849179db1d7SKowalski, Kamil             }
850179db1d7SKowalski, Kamil 
851e48c0fc5SRavi Teja             extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
8524a0cb85cSEd Tanous             // Finally make a callback with usefull data
853e48c0fc5SRavi Teja             callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
854179db1d7SKowalski, Kamil         },
855179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
856179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
857179db1d7SKowalski, Kamil };
858179db1d7SKowalski, Kamil 
859179db1d7SKowalski, Kamil /**
8609391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
8619391bb9cSRapkiewicz, Pawel  * Manager
8621abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
8631abe55efSEd Tanous  * into JSON.
8649391bb9cSRapkiewicz, Pawel  */
8659391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
8661abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
8671abe55efSEd Tanous {
86855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
8694a0cb85cSEd Tanous         [callback{std::move(callback)}](
8709391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
8714a0cb85cSEd Tanous             GetManagedObjects &resp) {
8721abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
8731abe55efSEd Tanous             // ethernet interfaces
8744c9afe43SEd Tanous             boost::container::flat_set<std::string> iface_list;
8754a0cb85cSEd Tanous             iface_list.reserve(resp.size());
8761abe55efSEd Tanous             if (error_code)
8771abe55efSEd Tanous             {
8784a0cb85cSEd Tanous                 callback(false, iface_list);
8799391bb9cSRapkiewicz, Pawel                 return;
8809391bb9cSRapkiewicz, Pawel             }
8819391bb9cSRapkiewicz, Pawel 
8829391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
8834a0cb85cSEd Tanous             for (const auto &objpath : resp)
8841abe55efSEd Tanous             {
8859391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
8864a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
8871abe55efSEd Tanous                 {
8881abe55efSEd Tanous                     // If interface is
8894a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
8904a0cb85cSEd Tanous                     // what we're looking for.
8919391bb9cSRapkiewicz, Pawel                     if (interface.first ==
8921abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
8931abe55efSEd Tanous                     {
8944a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
8954a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
8964a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
8974a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
8981abe55efSEd Tanous                         {
8999391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
9004c9afe43SEd Tanous                             iface_list.emplace(iface_id.substr(last_pos + 1));
9019391bb9cSRapkiewicz, Pawel                         }
9029391bb9cSRapkiewicz, Pawel                     }
9039391bb9cSRapkiewicz, Pawel                 }
9049391bb9cSRapkiewicz, Pawel             }
905a434f2bdSEd Tanous             // Finally make a callback with useful data
9064a0cb85cSEd Tanous             callback(true, iface_list);
9079391bb9cSRapkiewicz, Pawel         },
908aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
909aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9109391bb9cSRapkiewicz, Pawel };
9119391bb9cSRapkiewicz, Pawel 
9129391bb9cSRapkiewicz, Pawel /**
9139391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
9149391bb9cSRapkiewicz, Pawel  */
9151abe55efSEd Tanous class EthernetCollection : public Node
9161abe55efSEd Tanous {
9179391bb9cSRapkiewicz, Pawel   public:
9184a0cb85cSEd Tanous     template <typename CrowApp>
9191abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
9204a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
9211abe55efSEd Tanous     {
922588c3f0dSKowalski, Kamil         entityPrivileges = {
923588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
924e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
925e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
926e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
927e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
928e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
9299391bb9cSRapkiewicz, Pawel     }
9309391bb9cSRapkiewicz, Pawel 
9319391bb9cSRapkiewicz, Pawel   private:
9329391bb9cSRapkiewicz, Pawel     /**
9339391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
9349391bb9cSRapkiewicz, Pawel      */
93555c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
9361abe55efSEd Tanous                const std::vector<std::string> &params) override
9371abe55efSEd Tanous     {
9380f74e643SEd Tanous         res.jsonValue["@odata.type"] =
9390f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
9400f74e643SEd Tanous         res.jsonValue["@odata.context"] =
9410f74e643SEd Tanous             "/redfish/v1/"
9420f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
9430f74e643SEd Tanous         res.jsonValue["@odata.id"] =
9440f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
9450f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
9460f74e643SEd Tanous         res.jsonValue["Description"] =
9470f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
9484c9afe43SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
9494a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
9501abe55efSEd Tanous         // preparation
951f12894f8SJason M. Bills         getEthernetIfaceList(
9524c9afe43SEd Tanous             [asyncResp](
9534c9afe43SEd Tanous                 const bool &success,
9544c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
9554a0cb85cSEd Tanous                 if (!success)
9561abe55efSEd Tanous                 {
9574c9afe43SEd Tanous                     messages::internalError(asyncResp->res);
9584a0cb85cSEd Tanous                     return;
9594a0cb85cSEd Tanous                 }
9604a0cb85cSEd Tanous 
9614c9afe43SEd Tanous                 nlohmann::json &iface_array =
9624c9afe43SEd Tanous                     asyncResp->res.jsonValue["Members"];
9634a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
964fda13ad2SSunitha Harish                 std::string tag = "_";
9654a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
9661abe55efSEd Tanous                 {
967fda13ad2SSunitha Harish                     std::size_t found = iface_item.find(tag);
968fda13ad2SSunitha Harish                     if (found == std::string::npos)
969fda13ad2SSunitha Harish                     {
9704a0cb85cSEd Tanous                         iface_array.push_back(
9714a0cb85cSEd Tanous                             {{"@odata.id",
9724a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
9734a0cb85cSEd Tanous                                   iface_item}});
9749391bb9cSRapkiewicz, Pawel                     }
975fda13ad2SSunitha Harish                 }
9764a0cb85cSEd Tanous 
9774c9afe43SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
9784c9afe43SEd Tanous                     iface_array.size();
9794c9afe43SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
9804a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
9819391bb9cSRapkiewicz, Pawel             });
9829391bb9cSRapkiewicz, Pawel     }
9839391bb9cSRapkiewicz, Pawel };
9849391bb9cSRapkiewicz, Pawel 
9859391bb9cSRapkiewicz, Pawel /**
9869391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
9879391bb9cSRapkiewicz, Pawel  */
9881abe55efSEd Tanous class EthernetInterface : public Node
9891abe55efSEd Tanous {
9909391bb9cSRapkiewicz, Pawel   public:
9919391bb9cSRapkiewicz, Pawel     /*
9929391bb9cSRapkiewicz, Pawel      * Default Constructor
9939391bb9cSRapkiewicz, Pawel      */
9944a0cb85cSEd Tanous     template <typename CrowApp>
9951abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
9964a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
9971abe55efSEd Tanous              std::string())
9981abe55efSEd Tanous     {
999588c3f0dSKowalski, Kamil         entityPrivileges = {
1000588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1001e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1002e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1003e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1004e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1005e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
10069391bb9cSRapkiewicz, Pawel     }
10079391bb9cSRapkiewicz, Pawel 
1008e439f0f8SKowalski, Kamil   private:
1009bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
10104a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
10111abe55efSEd Tanous     {
1012bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
1013bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
1014bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
10154a0cb85cSEd Tanous                 if (ec)
10164a0cb85cSEd Tanous                 {
1017a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
10181abe55efSEd Tanous                 }
1019bc0bd6e0SEd Tanous             },
1020bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
1021bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
1022bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
1023bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
1024abf2add6SEd Tanous             std::variant<std::string>(hostname));
1025588c3f0dSKowalski, Kamil     }
1026588c3f0dSKowalski, Kamil 
1027d577665bSRatan Gupta     void handleMACAddressPatch(const std::string &ifaceId,
1028d577665bSRatan Gupta                                const std::string &macAddress,
1029d577665bSRatan Gupta                                const std::shared_ptr<AsyncResp> &asyncResp)
1030d577665bSRatan Gupta     {
1031d577665bSRatan Gupta         crow::connections::systemBus->async_method_call(
1032d577665bSRatan Gupta             [asyncResp, macAddress](const boost::system::error_code ec) {
1033d577665bSRatan Gupta                 if (ec)
1034d577665bSRatan Gupta                 {
1035d577665bSRatan Gupta                     messages::internalError(asyncResp->res);
1036d577665bSRatan Gupta                     return;
1037d577665bSRatan Gupta                 }
1038d577665bSRatan Gupta             },
1039d577665bSRatan Gupta             "xyz.openbmc_project.Network",
1040d577665bSRatan Gupta             "/xyz/openbmc_project/network/" + ifaceId,
1041d577665bSRatan Gupta             "org.freedesktop.DBus.Properties", "Set",
1042d577665bSRatan Gupta             "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1043d577665bSRatan Gupta             std::variant<std::string>(macAddress));
1044d577665bSRatan Gupta     }
1045286b9118SJohnathan Mantey 
1046da131a9aSJennifer Lee     void setDHCPEnabled(const std::string &ifaceId,
1047da131a9aSJennifer Lee                         const std::string &propertyName, const bool &value,
1048da131a9aSJennifer Lee                         const std::shared_ptr<AsyncResp> asyncResp)
1049da131a9aSJennifer Lee     {
1050da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1051da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1052da131a9aSJennifer Lee                 if (ec)
1053da131a9aSJennifer Lee                 {
1054da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1055da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1056da131a9aSJennifer Lee                     return;
1057da131a9aSJennifer Lee                 }
1058da131a9aSJennifer Lee             },
1059da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1060da131a9aSJennifer Lee             "/xyz/openbmc_project/network/" + ifaceId,
1061da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1062da131a9aSJennifer Lee             "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1063da131a9aSJennifer Lee             std::variant<bool>{value});
1064da131a9aSJennifer Lee     }
1065da131a9aSJennifer Lee     void setDHCPv4Config(const std::string &propertyName, const bool &value,
1066da131a9aSJennifer Lee                          const std::shared_ptr<AsyncResp> asyncResp)
1067da131a9aSJennifer Lee     {
1068da131a9aSJennifer Lee         BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1069da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1070da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1071da131a9aSJennifer Lee                 if (ec)
1072da131a9aSJennifer Lee                 {
1073da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1074da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1075da131a9aSJennifer Lee                     return;
1076da131a9aSJennifer Lee                 }
1077da131a9aSJennifer Lee             },
1078da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1079da131a9aSJennifer Lee             "/xyz/openbmc_project/network/config/dhcp",
1080da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1081da131a9aSJennifer Lee             "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1082da131a9aSJennifer Lee             std::variant<bool>{value});
1083da131a9aSJennifer Lee     }
1084d577665bSRatan Gupta 
1085da131a9aSJennifer Lee     void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1086da131a9aSJennifer Lee                            const std::shared_ptr<AsyncResp> asyncResp)
1087da131a9aSJennifer Lee     {
1088da131a9aSJennifer Lee         std::optional<bool> dhcpEnabled;
1089da131a9aSJennifer Lee         std::optional<bool> useDNSServers;
1090da131a9aSJennifer Lee         std::optional<bool> useDomainName;
1091da131a9aSJennifer Lee         std::optional<bool> useNTPServers;
1092da131a9aSJennifer Lee 
1093da131a9aSJennifer Lee         if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1094da131a9aSJennifer Lee                                  dhcpEnabled, "UseDNSServers", useDNSServers,
1095da131a9aSJennifer Lee                                  "UseDomainName", useDomainName,
1096da131a9aSJennifer Lee                                  "UseNTPServers", useNTPServers))
1097da131a9aSJennifer Lee         {
1098da131a9aSJennifer Lee             return;
1099da131a9aSJennifer Lee         }
1100da131a9aSJennifer Lee 
1101da131a9aSJennifer Lee         if (dhcpEnabled)
1102da131a9aSJennifer Lee         {
1103da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1104da131a9aSJennifer Lee             setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1105da131a9aSJennifer Lee         }
1106da131a9aSJennifer Lee 
1107da131a9aSJennifer Lee         if (useDNSServers)
1108da131a9aSJennifer Lee         {
1109da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1110da131a9aSJennifer Lee             setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1111da131a9aSJennifer Lee         }
1112da131a9aSJennifer Lee 
1113da131a9aSJennifer Lee         if (useDomainName)
1114da131a9aSJennifer Lee         {
1115da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1116da131a9aSJennifer Lee             setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1117da131a9aSJennifer Lee         }
1118da131a9aSJennifer Lee 
1119da131a9aSJennifer Lee         if (useNTPServers)
1120da131a9aSJennifer Lee         {
1121da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1122da131a9aSJennifer Lee             setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1123da131a9aSJennifer Lee         }
1124da131a9aSJennifer Lee     }
11254a0cb85cSEd Tanous     void handleIPv4Patch(
1126f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
11274a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
11284a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
11291abe55efSEd Tanous     {
1130f476acbfSRatan Gupta         if (!input.is_array())
1131f476acbfSRatan Gupta         {
1132f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1133f476acbfSRatan Gupta                                              "IPv4Addresses");
1134f476acbfSRatan Gupta             return;
1135f476acbfSRatan Gupta         }
1136f476acbfSRatan Gupta 
11374a0cb85cSEd Tanous         int entryIdx = 0;
11384a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
11394a0cb85cSEd Tanous             ipv4Data.begin();
1140537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
11411abe55efSEd Tanous         {
11424a0cb85cSEd Tanous             std::string pathString =
1143a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
1144179db1d7SKowalski, Kamil 
1145f476acbfSRatan Gupta             if (thisJson.is_null())
1146f476acbfSRatan Gupta             {
1147f476acbfSRatan Gupta                 if (thisData != ipv4Data.end())
1148f476acbfSRatan Gupta                 {
1149286b9118SJohnathan Mantey                     deleteIPv4(ifaceId, thisData->id, asyncResp);
1150f476acbfSRatan Gupta                     thisData++;
1151f476acbfSRatan Gupta                 }
1152f476acbfSRatan Gupta                 else
1153f476acbfSRatan Gupta                 {
1154f476acbfSRatan Gupta                     messages::propertyValueFormatError(
1155f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
1156f476acbfSRatan Gupta                     return;
1157f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
1158f476acbfSRatan Gupta                     // list and if unable to update one of the
1159f476acbfSRatan Gupta                     // list value then should we proceed further or
1160f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
1161f476acbfSRatan Gupta                     // till then we stop processing the next list item.
1162f476acbfSRatan Gupta                 }
1163f476acbfSRatan Gupta                 entryIdx++;
1164f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
1165f476acbfSRatan Gupta             }
1166f476acbfSRatan Gupta 
11679474b378SRatan Gupta             if (thisJson.empty())
11689474b378SRatan Gupta             {
11699474b378SRatan Gupta                 if (thisData != ipv4Data.end())
11709474b378SRatan Gupta                 {
11719474b378SRatan Gupta                     thisData++;
11729474b378SRatan Gupta                 }
11739474b378SRatan Gupta                 else
11749474b378SRatan Gupta                 {
11759474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
11769474b378SRatan Gupta                                               pathString + "/Address");
11779474b378SRatan Gupta                     return;
1178f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
11799474b378SRatan Gupta                     // list and if unable to update one of the
11809474b378SRatan Gupta                     // list value then should we proceed further or
11819474b378SRatan Gupta                     // break there, would ask in the redfish forum
11829474b378SRatan Gupta                     // till then we stop processing the next list item.
11839474b378SRatan Gupta                 }
11849474b378SRatan Gupta                 entryIdx++;
11859474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
11869474b378SRatan Gupta             }
11879474b378SRatan Gupta 
1188537174c4SEd Tanous             std::optional<std::string> address;
1189537174c4SEd Tanous             std::optional<std::string> subnetMask;
1190537174c4SEd Tanous             std::optional<std::string> gateway;
1191537174c4SEd Tanous 
1192537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
11937e27d832SJohnathan Mantey                                      address, "SubnetMask", subnetMask,
11947e27d832SJohnathan Mantey                                      "Gateway", gateway))
1195537174c4SEd Tanous             {
1196537174c4SEd Tanous                 return;
1197179db1d7SKowalski, Kamil             }
1198179db1d7SKowalski, Kamil 
1199537174c4SEd Tanous             if (address)
12001abe55efSEd Tanous             {
1201537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
12021abe55efSEd Tanous                 {
1203537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
12044a0cb85cSEd Tanous                                                        pathString + "/Address");
1205537174c4SEd Tanous                     return;
12064a0cb85cSEd Tanous                 }
12074a0cb85cSEd Tanous             }
12084a0cb85cSEd Tanous 
1209537174c4SEd Tanous             uint8_t prefixLength = 0;
1210537174c4SEd Tanous             if (subnetMask)
12114a0cb85cSEd Tanous             {
1212537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
12134a0cb85cSEd Tanous                 {
1214f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1215537174c4SEd Tanous                         asyncResp->res, *subnetMask,
12164a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1217537174c4SEd Tanous                     return;
12184a0cb85cSEd Tanous                 }
12194a0cb85cSEd Tanous             }
12204a0cb85cSEd Tanous 
1221537174c4SEd Tanous             if (gateway)
12224a0cb85cSEd Tanous             {
1223537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
12244a0cb85cSEd Tanous                 {
1225537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1226537174c4SEd Tanous                                                        pathString + "/Gateway");
1227537174c4SEd Tanous                     return;
12284a0cb85cSEd Tanous                 }
12294a0cb85cSEd Tanous             }
12304a0cb85cSEd Tanous 
1231f476acbfSRatan Gupta             // if IP address exist then  modify it.
12324a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
12334a0cb85cSEd Tanous             {
1234179db1d7SKowalski, Kamil                 // Apply changes
1235537174c4SEd Tanous                 if (address)
12361abe55efSEd Tanous                 {
1237286b9118SJohnathan Mantey                     auto callback =
1238286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
12394a0cb85cSEd Tanous                             if (ec)
12401abe55efSEd Tanous                             {
1241a08b46ccSJason M. Bills                                 messages::internalError(asyncResp->res);
12424a0cb85cSEd Tanous                                 return;
12434a0cb85cSEd Tanous                             }
12444a0cb85cSEd Tanous                         };
12454a0cb85cSEd Tanous 
12464a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
12474a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1248f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1249f476acbfSRatan Gupta                             thisData->id,
12504a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
12514a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1252537174c4SEd Tanous                         std::variant<std::string>(*address));
1253179db1d7SKowalski, Kamil                 }
1254179db1d7SKowalski, Kamil 
1255537174c4SEd Tanous                 if (subnetMask)
12561abe55efSEd Tanous                 {
12574a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1258286b9118SJohnathan Mantey                                                  thisData->id, prefixLength,
1259286b9118SJohnathan Mantey                                                  asyncResp);
1260179db1d7SKowalski, Kamil                 }
1261179db1d7SKowalski, Kamil 
1262537174c4SEd Tanous                 if (gateway)
12631abe55efSEd Tanous                 {
1264286b9118SJohnathan Mantey                     auto callback =
1265286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
12664a0cb85cSEd Tanous                             if (ec)
12671abe55efSEd Tanous                             {
1268a08b46ccSJason M. Bills                                 messages::internalError(asyncResp->res);
12694a0cb85cSEd Tanous                                 return;
12704a0cb85cSEd Tanous                             }
12714a0cb85cSEd Tanous                         };
12724a0cb85cSEd Tanous 
12734a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
12744a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1275f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1276f476acbfSRatan Gupta                             thisData->id,
12774a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
12784a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1279537174c4SEd Tanous                         std::variant<std::string>(*gateway));
12804a0cb85cSEd Tanous                 }
1281f476acbfSRatan Gupta 
12824a0cb85cSEd Tanous                 thisData++;
12831abe55efSEd Tanous             }
12841abe55efSEd Tanous             else
12851abe55efSEd Tanous             {
12864a0cb85cSEd Tanous                 // Create IPv4 with provided data
1287537174c4SEd Tanous                 if (!gateway)
12881abe55efSEd Tanous                 {
1289a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
12904a0cb85cSEd Tanous                                               pathString + "/Gateway");
12914a0cb85cSEd Tanous                     continue;
12924a0cb85cSEd Tanous                 }
12934a0cb85cSEd Tanous 
1294537174c4SEd Tanous                 if (!address)
12951abe55efSEd Tanous                 {
1296a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
12974a0cb85cSEd Tanous                                               pathString + "/Address");
12984a0cb85cSEd Tanous                     continue;
12994a0cb85cSEd Tanous                 }
13004a0cb85cSEd Tanous 
1301537174c4SEd Tanous                 if (!subnetMask)
13021abe55efSEd Tanous                 {
1303a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
13044a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
13054a0cb85cSEd Tanous                     continue;
1306588c3f0dSKowalski, Kamil                 }
1307588c3f0dSKowalski, Kamil 
1308b01bf299SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1309b01bf299SEd Tanous                            asyncResp);
131095897b20SRatan Gupta 
131195897b20SRatan Gupta                 nlohmann::json &ipv4AddressJson =
131295897b20SRatan Gupta                     asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
131395897b20SRatan Gupta                 ipv4AddressJson["Address"] = *address;
131495897b20SRatan Gupta                 ipv4AddressJson["SubnetMask"] = *subnetMask;
131595897b20SRatan Gupta                 ipv4AddressJson["Gateway"] = *gateway;
13164a0cb85cSEd Tanous             }
13174a0cb85cSEd Tanous             entryIdx++;
13184a0cb85cSEd Tanous         }
13194a0cb85cSEd Tanous     }
13204a0cb85cSEd Tanous 
1321f85837bfSRAJESWARAN THILLAIGOVINDAN     void handleStaticNameServersPatch(
1322f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::string &ifaceId,
1323f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::vector<std::string> &updatedStaticNameServers,
1324f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::shared_ptr<AsyncResp> &asyncResp)
1325f85837bfSRAJESWARAN THILLAIGOVINDAN     {
1326f85837bfSRAJESWARAN THILLAIGOVINDAN         crow::connections::systemBus->async_method_call(
1327286b9118SJohnathan Mantey             [asyncResp](const boost::system::error_code ec) {
1328f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (ec)
1329f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1330f85837bfSRAJESWARAN THILLAIGOVINDAN                     messages::internalError(asyncResp->res);
1331f85837bfSRAJESWARAN THILLAIGOVINDAN                     return;
1332f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1333f85837bfSRAJESWARAN THILLAIGOVINDAN             },
1334f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network",
1335f85837bfSRAJESWARAN THILLAIGOVINDAN             "/xyz/openbmc_project/network/" + ifaceId,
1336f85837bfSRAJESWARAN THILLAIGOVINDAN             "org.freedesktop.DBus.Properties", "Set",
1337f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1338f85837bfSRAJESWARAN THILLAIGOVINDAN             std::variant<std::vector<std::string>>{updatedStaticNameServers});
1339f85837bfSRAJESWARAN THILLAIGOVINDAN     }
1340f85837bfSRAJESWARAN THILLAIGOVINDAN 
1341e48c0fc5SRavi Teja     void handleIPv6StaticAddressesPatch(
1342e48c0fc5SRavi Teja         const std::string &ifaceId, nlohmann::json &input,
1343e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1344e48c0fc5SRavi Teja         const std::shared_ptr<AsyncResp> asyncResp)
1345e48c0fc5SRavi Teja     {
1346e48c0fc5SRavi Teja         if (!input.is_array())
1347e48c0fc5SRavi Teja         {
1348e48c0fc5SRavi Teja             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1349e48c0fc5SRavi Teja                                              "IPv6StaticAddresses");
1350e48c0fc5SRavi Teja             return;
1351e48c0fc5SRavi Teja         }
1352e48c0fc5SRavi Teja 
1353e48c0fc5SRavi Teja         int entryIdx = 0;
1354e48c0fc5SRavi Teja         boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1355e48c0fc5SRavi Teja             ipv6StaticData.begin();
1356e48c0fc5SRavi Teja         for (nlohmann::json &thisJson : input)
1357e48c0fc5SRavi Teja         {
1358e48c0fc5SRavi Teja             std::string pathString =
1359e48c0fc5SRavi Teja                 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1360e48c0fc5SRavi Teja 
1361e48c0fc5SRavi Teja             if (thisJson.is_null())
1362e48c0fc5SRavi Teja             {
1363e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1364e48c0fc5SRavi Teja                 {
1365286b9118SJohnathan Mantey                     deleteIPv6(ifaceId, thisData->id, asyncResp);
1366e48c0fc5SRavi Teja                     thisData++;
1367e48c0fc5SRavi Teja                 }
1368e48c0fc5SRavi Teja                 else
1369e48c0fc5SRavi Teja                 {
1370e48c0fc5SRavi Teja                     messages::propertyValueFormatError(
1371e48c0fc5SRavi Teja                         asyncResp->res, input.dump(), pathString);
1372e48c0fc5SRavi Teja                     return;
1373e48c0fc5SRavi Teja                 }
1374e48c0fc5SRavi Teja                 entryIdx++;
1375e48c0fc5SRavi Teja                 continue;
1376e48c0fc5SRavi Teja             }
1377e48c0fc5SRavi Teja 
1378e48c0fc5SRavi Teja             if (thisJson.empty())
1379e48c0fc5SRavi Teja             {
1380e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1381e48c0fc5SRavi Teja                 {
1382e48c0fc5SRavi Teja                     thisData++;
1383e48c0fc5SRavi Teja                 }
1384e48c0fc5SRavi Teja                 else
1385e48c0fc5SRavi Teja                 {
1386e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1387e48c0fc5SRavi Teja                                               pathString + "/Address");
1388e48c0fc5SRavi Teja                     return;
1389e48c0fc5SRavi Teja                 }
1390e48c0fc5SRavi Teja                 entryIdx++;
1391e48c0fc5SRavi Teja                 continue;
1392e48c0fc5SRavi Teja             }
1393e48c0fc5SRavi Teja 
1394e48c0fc5SRavi Teja             std::optional<std::string> address;
1395e48c0fc5SRavi Teja             std::optional<uint8_t> prefixLength;
1396e48c0fc5SRavi Teja 
1397e48c0fc5SRavi Teja             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1398e48c0fc5SRavi Teja                                      address, "PrefixLength", prefixLength))
1399e48c0fc5SRavi Teja             {
1400e48c0fc5SRavi Teja                 return;
1401e48c0fc5SRavi Teja             }
1402e48c0fc5SRavi Teja 
1403e48c0fc5SRavi Teja             // if IP address exist then  modify it.
1404e48c0fc5SRavi Teja             if (thisData != ipv6StaticData.end())
1405e48c0fc5SRavi Teja             {
1406e48c0fc5SRavi Teja                 // Apply changes
1407e48c0fc5SRavi Teja                 if (address)
1408e48c0fc5SRavi Teja                 {
1409286b9118SJohnathan Mantey                     auto callback =
1410286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
1411e48c0fc5SRavi Teja                             if (ec)
1412e48c0fc5SRavi Teja                             {
1413e48c0fc5SRavi Teja                                 messages::internalError(asyncResp->res);
1414e48c0fc5SRavi Teja                                 return;
1415e48c0fc5SRavi Teja                             }
1416e48c0fc5SRavi Teja                         };
1417e48c0fc5SRavi Teja 
1418e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1419e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1420e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1421e48c0fc5SRavi Teja                             thisData->id,
1422e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1423e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "Address",
1424e48c0fc5SRavi Teja                         std::variant<std::string>(*address));
1425e48c0fc5SRavi Teja                 }
1426e48c0fc5SRavi Teja 
1427e48c0fc5SRavi Teja                 if (prefixLength)
1428e48c0fc5SRavi Teja                 {
1429286b9118SJohnathan Mantey                     auto callback =
1430286b9118SJohnathan Mantey                         [asyncResp](const boost::system::error_code ec) {
1431e48c0fc5SRavi Teja                             if (ec)
1432e48c0fc5SRavi Teja                             {
1433e48c0fc5SRavi Teja                                 messages::internalError(asyncResp->res);
1434e48c0fc5SRavi Teja                                 return;
1435e48c0fc5SRavi Teja                             }
1436e48c0fc5SRavi Teja                         };
1437e48c0fc5SRavi Teja 
1438e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1439e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1440e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1441e48c0fc5SRavi Teja                             thisData->id,
1442e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1443e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "PrefixLength",
1444e48c0fc5SRavi Teja                         std::variant<uint8_t>(*prefixLength));
1445e48c0fc5SRavi Teja                 }
1446e48c0fc5SRavi Teja 
1447e48c0fc5SRavi Teja                 thisData++;
1448e48c0fc5SRavi Teja             }
1449e48c0fc5SRavi Teja             else
1450e48c0fc5SRavi Teja             {
1451e48c0fc5SRavi Teja                 // Create IPv6 with provided data
1452e48c0fc5SRavi Teja 
1453e48c0fc5SRavi Teja                 if (!prefixLength)
1454e48c0fc5SRavi Teja                 {
1455e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1456e48c0fc5SRavi Teja                                               pathString + "/PrefixLength");
1457e48c0fc5SRavi Teja                     continue;
1458e48c0fc5SRavi Teja                 }
1459e48c0fc5SRavi Teja 
1460e48c0fc5SRavi Teja                 if (!address)
1461e48c0fc5SRavi Teja                 {
1462e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1463e48c0fc5SRavi Teja                                               pathString + "/Address");
1464e48c0fc5SRavi Teja                     continue;
1465e48c0fc5SRavi Teja                 }
1466e48c0fc5SRavi Teja 
1467e48c0fc5SRavi Teja                 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1468e48c0fc5SRavi Teja                            asyncResp);
1469e48c0fc5SRavi Teja 
1470e48c0fc5SRavi Teja                 nlohmann::json &ipv6StaticAddressJson =
1471e48c0fc5SRavi Teja                     asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1472e48c0fc5SRavi Teja                 ipv6StaticAddressJson["Address"] = *address;
1473e48c0fc5SRavi Teja                 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1474e48c0fc5SRavi Teja             }
1475e48c0fc5SRavi Teja             entryIdx++;
1476e48c0fc5SRavi Teja         }
1477e48c0fc5SRavi Teja     }
1478e48c0fc5SRavi Teja 
14790f74e643SEd Tanous     void parseInterfaceData(
14800f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
14810f74e643SEd Tanous         const EthernetInterfaceData &ethData,
1482e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1483e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1484e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
14854a0cb85cSEd Tanous     {
14864a0cb85cSEd Tanous         json_response["Id"] = iface_id;
14874a0cb85cSEd Tanous         json_response["@odata.id"] =
14884a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1489029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1490029573d4SEd Tanous         if (ethData.speed == 0)
1491029573d4SEd Tanous         {
1492029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1493029573d4SEd Tanous             json_response["Status"] = {
1494029573d4SEd Tanous                 {"Health", "OK"},
1495029573d4SEd Tanous                 {"State", "Disabled"},
1496029573d4SEd Tanous             };
1497029573d4SEd Tanous         }
1498029573d4SEd Tanous         else
1499029573d4SEd Tanous         {
1500029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1501029573d4SEd Tanous             json_response["Status"] = {
1502029573d4SEd Tanous                 {"Health", "OK"},
1503029573d4SEd Tanous                 {"State", "Enabled"},
1504029573d4SEd Tanous             };
1505029573d4SEd Tanous         }
15064a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
15074a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1508fda13ad2SSunitha Harish         json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
15092a133282Smanojkiraneda 
15104a0cb85cSEd Tanous         if (!ethData.hostname.empty())
15114a0cb85cSEd Tanous         {
15124a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
1513*d24bfc7aSJennifer Lee             if (!ethData.domainnames.empty())
1514*d24bfc7aSJennifer Lee             {
1515*d24bfc7aSJennifer Lee                 json_response["FQDN"] =
1516*d24bfc7aSJennifer Lee                     ethData.hostname + "." + ethData.domainnames[0];
1517*d24bfc7aSJennifer Lee             }
15184a0cb85cSEd Tanous         }
15194a0cb85cSEd Tanous 
1520fda13ad2SSunitha Harish         json_response["VLANs"] = {
1521fda13ad2SSunitha Harish             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1522fda13ad2SSunitha Harish                               iface_id + "/VLANs"}};
1523fda13ad2SSunitha Harish 
1524029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
1525f85837bfSRAJESWARAN THILLAIGOVINDAN         json_response["StaticNameServers"] = ethData.nameservers;
15264a0cb85cSEd Tanous 
15274a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
15284a0cb85cSEd Tanous         {
15294a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
15304a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
15314a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
15324a0cb85cSEd Tanous             {
1533fa5053a6SGunnar Mills 
1534fa5053a6SGunnar Mills                 std::string gatewayStr = ipv4_config.gateway;
1535fa5053a6SGunnar Mills                 if (gatewayStr.empty())
1536fa5053a6SGunnar Mills                 {
1537fa5053a6SGunnar Mills                     gatewayStr = "0.0.0.0";
1538fa5053a6SGunnar Mills                 }
1539fa5053a6SGunnar Mills 
15404a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
15414a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1542029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1543fa5053a6SGunnar Mills                                       {"Gateway", gatewayStr}});
15444a0cb85cSEd Tanous             }
15454a0cb85cSEd Tanous         }
15469a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1547e48c0fc5SRavi Teja 
1548e48c0fc5SRavi Teja         nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1549e48c0fc5SRavi Teja         ipv6_array = nlohmann::json::array();
1550e48c0fc5SRavi Teja         for (auto &ipv6_config : ipv6Data)
1551e48c0fc5SRavi Teja         {
1552e48c0fc5SRavi Teja             ipv6_array.push_back({{"Address", ipv6_config.address},
1553e48c0fc5SRavi Teja                                   {"PrefixLength", ipv6_config.prefixLength},
1554e48c0fc5SRavi Teja                                   {"AddressOrigin", ipv6_config.origin}});
1555e48c0fc5SRavi Teja         }
1556e48c0fc5SRavi Teja 
1557e48c0fc5SRavi Teja         nlohmann::json &ipv6_static_array =
1558e48c0fc5SRavi Teja             json_response["IPv6StaticAddresses"];
1559e48c0fc5SRavi Teja         ipv6_static_array = nlohmann::json::array();
1560e48c0fc5SRavi Teja         for (auto &ipv6_static_config : ipv6StaticData)
1561e48c0fc5SRavi Teja         {
1562e48c0fc5SRavi Teja             ipv6_static_array.push_back(
1563e48c0fc5SRavi Teja                 {{"Address", ipv6_static_config.address},
1564e48c0fc5SRavi Teja                  {"PrefixLength", ipv6_static_config.prefixLength}});
1565e48c0fc5SRavi Teja         }
1566588c3f0dSKowalski, Kamil     }
1567588c3f0dSKowalski, Kamil 
15689391bb9cSRapkiewicz, Pawel     /**
15699391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
15709391bb9cSRapkiewicz, Pawel      */
157155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15721abe55efSEd Tanous                const std::vector<std::string> &params) override
15731abe55efSEd Tanous     {
15744a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15751abe55efSEd Tanous         if (params.size() != 1)
15761abe55efSEd Tanous         {
1577f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
15789391bb9cSRapkiewicz, Pawel             return;
15799391bb9cSRapkiewicz, Pawel         }
15809391bb9cSRapkiewicz, Pawel 
15814a0cb85cSEd Tanous         getEthernetIfaceData(
15824a0cb85cSEd Tanous             params[0],
15834a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
15844a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1585e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1586e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1587e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1588e48c0fc5SRavi Teja                     &ipv6StaticData) {
15894a0cb85cSEd Tanous                 if (!success)
15901abe55efSEd Tanous                 {
15911abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15921abe55efSEd Tanous                     // object, and other errors
1593f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1594f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
15954a0cb85cSEd Tanous                     return;
15969391bb9cSRapkiewicz, Pawel                 }
15974c9afe43SEd Tanous 
15984c9afe43SEd Tanous                 // because this has no dependence on the interface at this
15994c9afe43SEd Tanous                 // point, it needs to be done after we know the interface
16004c9afe43SEd Tanous                 // exists, not before.
16014c9afe43SEd Tanous                 getDHCPConfigData(asyncResp);
16024c9afe43SEd Tanous 
16030f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1604fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
16050f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
16060f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
16070f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
16080f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
16090f74e643SEd Tanous                     "Management Network Interface";
16100f74e643SEd Tanous 
16110f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1612e48c0fc5SRavi Teja                                    ipv4Data, ipv6Data, ipv6StaticData);
16139391bb9cSRapkiewicz, Pawel             });
16149391bb9cSRapkiewicz, Pawel     }
16159391bb9cSRapkiewicz, Pawel 
161655c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
16171abe55efSEd Tanous                  const std::vector<std::string> &params) override
16181abe55efSEd Tanous     {
16194a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16201abe55efSEd Tanous         if (params.size() != 1)
16211abe55efSEd Tanous         {
1622f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1623588c3f0dSKowalski, Kamil             return;
1624588c3f0dSKowalski, Kamil         }
1625588c3f0dSKowalski, Kamil 
16264a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1627588c3f0dSKowalski, Kamil 
1628bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1629d577665bSRatan Gupta         std::optional<std::string> macAddress;
16309a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1631f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1632f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1633e48c0fc5SRavi Teja         std::optional<nlohmann::json> ipv6StaticAddresses;
1634f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
16355112e9b4SRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> nameServers;
1636da131a9aSJennifer Lee         std::optional<nlohmann::json> dhcpv4;
16370627a2c7SEd Tanous 
1638fda13ad2SSunitha Harish         if (!json_util::readJson(
1639fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
16406ca6ac12SJohnathan Mantey                 "MACAddress", macAddress, "StaticNameServers",
16416ca6ac12SJohnathan Mantey                 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
16426ca6ac12SJohnathan Mantey                 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
16436ca6ac12SJohnathan Mantey                 nameServers, "DHCPv4", dhcpv4))
16441abe55efSEd Tanous         {
1645588c3f0dSKowalski, Kamil             return;
1646588c3f0dSKowalski, Kamil         }
1647f15aad37SRatan Gupta 
1648da131a9aSJennifer Lee         if (dhcpv4)
1649da131a9aSJennifer Lee         {
1650da131a9aSJennifer Lee             handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1651da131a9aSJennifer Lee         }
1652da131a9aSJennifer Lee 
16534a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1654588c3f0dSKowalski, Kamil         // preparation
16554a0cb85cSEd Tanous         getEthernetIfaceData(
16564a0cb85cSEd Tanous             iface_id,
1657fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1658fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
16590627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
16609a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1661e48c0fc5SRavi Teja              ipv6StaticAddresses = std::move(ipv6StaticAddresses),
16625112e9b4SRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers),
16635112e9b4SRAJESWARAN THILLAIGOVINDAN              nameServers = std::move(nameServers)](
16644a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1665e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1666e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1667e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1668e48c0fc5SRavi Teja                     &ipv6StaticData) {
16691abe55efSEd Tanous                 if (!success)
16701abe55efSEd Tanous                 {
1671588c3f0dSKowalski, Kamil                     // ... otherwise return error
16721abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16731abe55efSEd Tanous                     // object, and other errors
1674fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1675fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1676588c3f0dSKowalski, Kamil                     return;
1677588c3f0dSKowalski, Kamil                 }
1678588c3f0dSKowalski, Kamil 
16790627a2c7SEd Tanous                 if (hostname)
16801abe55efSEd Tanous                 {
16810627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
16821abe55efSEd Tanous                 }
16830627a2c7SEd Tanous 
1684d577665bSRatan Gupta                 if (macAddress)
1685d577665bSRatan Gupta                 {
1686d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1687d577665bSRatan Gupta                 }
1688d577665bSRatan Gupta 
16890627a2c7SEd Tanous                 if (ipv4Addresses)
16901abe55efSEd Tanous                 {
1691537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1692537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1693537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1694537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1695537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1696537174c4SEd Tanous                     // on that, but could be done more efficiently
1697f476acbfSRatan Gupta                     nlohmann::json ipv4 = std::move(*ipv4Addresses);
1698537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
16991abe55efSEd Tanous                 }
17000627a2c7SEd Tanous 
17015112e9b4SRAJESWARAN THILLAIGOVINDAN                 if (nameServers)
17025112e9b4SRAJESWARAN THILLAIGOVINDAN                 {
17035112e9b4SRAJESWARAN THILLAIGOVINDAN                     // Data.Permissions is read-only
17045112e9b4SRAJESWARAN THILLAIGOVINDAN                     messages::propertyNotWritable(asyncResp->res,
17055112e9b4SRAJESWARAN THILLAIGOVINDAN                                                   "NameServers");
17065112e9b4SRAJESWARAN THILLAIGOVINDAN                 }
17075112e9b4SRAJESWARAN THILLAIGOVINDAN 
1708f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1709f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1710f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1711f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1712f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
17139a6fc6feSRavi Teja 
17149a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
17159a6fc6feSRavi Teja                 {
17169a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
17179a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
17189a6fc6feSRavi Teja                 }
1719e48c0fc5SRavi Teja 
1720e48c0fc5SRavi Teja                 if (ipv6StaticAddresses)
1721e48c0fc5SRavi Teja                 {
1722e48c0fc5SRavi Teja                     nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1723e48c0fc5SRavi Teja                     handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1724e48c0fc5SRavi Teja                                                    ipv6StaticData, asyncResp);
1725e48c0fc5SRavi Teja                 }
1726588c3f0dSKowalski, Kamil             });
1727588c3f0dSKowalski, Kamil     }
17289391bb9cSRapkiewicz, Pawel };
17299391bb9cSRapkiewicz, Pawel 
1730e439f0f8SKowalski, Kamil /**
17314a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
17324a0cb85cSEd Tanous  * Schema
1733e439f0f8SKowalski, Kamil  */
17341abe55efSEd Tanous class VlanNetworkInterface : public Node
17351abe55efSEd Tanous {
1736e439f0f8SKowalski, Kamil   public:
1737e439f0f8SKowalski, Kamil     /*
1738e439f0f8SKowalski, Kamil      * Default Constructor
1739e439f0f8SKowalski, Kamil      */
1740e439f0f8SKowalski, Kamil     template <typename CrowApp>
17411abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
17424a0cb85cSEd Tanous         Node(app,
17430f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
17441abe55efSEd Tanous              std::string(), std::string())
17451abe55efSEd Tanous     {
1746e439f0f8SKowalski, Kamil         entityPrivileges = {
1747e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1748e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1749e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1750e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1751e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1752e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1753e439f0f8SKowalski, Kamil     }
1754e439f0f8SKowalski, Kamil 
1755e439f0f8SKowalski, Kamil   private:
17560f74e643SEd Tanous     void parseInterfaceData(
17570f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
17580f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
1759e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1760e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1761e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
17621abe55efSEd Tanous     {
1763e439f0f8SKowalski, Kamil         // Fill out obvious data...
17644a0cb85cSEd Tanous         json_response["Id"] = iface_id;
17654a0cb85cSEd Tanous         json_response["@odata.id"] =
17664a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
17674a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1768e439f0f8SKowalski, Kamil 
17694a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1770fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
17714a0cb85cSEd Tanous         {
1772fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
17734a0cb85cSEd Tanous         }
1774e439f0f8SKowalski, Kamil     }
1775e439f0f8SKowalski, Kamil 
1776fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
17771abe55efSEd Tanous     {
17781abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
17791abe55efSEd Tanous         {
1780927a505aSKowalski, Kamil             return false;
17811abe55efSEd Tanous         }
17821abe55efSEd Tanous         else
17831abe55efSEd Tanous         {
1784927a505aSKowalski, Kamil             return true;
1785927a505aSKowalski, Kamil         }
1786927a505aSKowalski, Kamil     }
1787927a505aSKowalski, Kamil 
1788e439f0f8SKowalski, Kamil     /**
1789e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1790e439f0f8SKowalski, Kamil      */
179155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
17921abe55efSEd Tanous                const std::vector<std::string> &params) override
17931abe55efSEd Tanous     {
17944a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17954a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1796e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1797e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1798e439f0f8SKowalski, Kamil         // impossible.
17991abe55efSEd Tanous         if (params.size() != 2)
18001abe55efSEd Tanous         {
1801f12894f8SJason M. Bills             messages::internalError(res);
1802e439f0f8SKowalski, Kamil             res.end();
1803e439f0f8SKowalski, Kamil             return;
1804e439f0f8SKowalski, Kamil         }
1805e439f0f8SKowalski, Kamil 
18064a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
18074a0cb85cSEd Tanous         const std::string &iface_id = params[1];
18080f74e643SEd Tanous         res.jsonValue["@odata.type"] =
18090f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
18100f74e643SEd Tanous         res.jsonValue["@odata.context"] =
18110f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
18120f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1813e439f0f8SKowalski, Kamil 
1814fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
18151abe55efSEd Tanous         {
1816a434f2bdSEd Tanous             return;
1817a434f2bdSEd Tanous         }
1818a434f2bdSEd Tanous 
1819e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1820e439f0f8SKowalski, Kamil         // preparation
18214a0cb85cSEd Tanous         getEthernetIfaceData(
1822fda13ad2SSunitha Harish             params[1],
1823fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1824fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
18254a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1826e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1827e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1828e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1829e48c0fc5SRavi Teja                     &ipv6StaticData) {
1830fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
18311abe55efSEd Tanous                 {
18320f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
18330f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
1834e48c0fc5SRavi Teja                                        ipv4Data, ipv6Data, ipv6StaticData);
18351abe55efSEd Tanous                 }
18361abe55efSEd Tanous                 else
18371abe55efSEd Tanous                 {
1838e439f0f8SKowalski, Kamil                     // ... otherwise return error
18391abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
18401abe55efSEd Tanous                     // object, and other errors
1841f12894f8SJason M. Bills                     messages::resourceNotFound(
1842f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1843e439f0f8SKowalski, Kamil                 }
1844e439f0f8SKowalski, Kamil             });
1845e439f0f8SKowalski, Kamil     }
1846e439f0f8SKowalski, Kamil 
184755c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
18481abe55efSEd Tanous                  const std::vector<std::string> &params) override
18491abe55efSEd Tanous     {
18504a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18511abe55efSEd Tanous         if (params.size() != 2)
18521abe55efSEd Tanous         {
1853f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1854e439f0f8SKowalski, Kamil             return;
1855e439f0f8SKowalski, Kamil         }
1856e439f0f8SKowalski, Kamil 
1857d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
185855c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1859927a505aSKowalski, Kamil 
1860fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
18611abe55efSEd Tanous         {
1862fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1863fda13ad2SSunitha Harish                                        ifaceId);
1864927a505aSKowalski, Kamil             return;
1865927a505aSKowalski, Kamil         }
1866927a505aSKowalski, Kamil 
18670627a2c7SEd Tanous         bool vlanEnable = false;
18680627a2c7SEd Tanous         uint64_t vlanId = 0;
18690627a2c7SEd Tanous 
18700627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
18710627a2c7SEd Tanous                                  vlanId))
18721abe55efSEd Tanous         {
1873927a505aSKowalski, Kamil             return;
1874927a505aSKowalski, Kamil         }
1875927a505aSKowalski, Kamil 
1876927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1877927a505aSKowalski, Kamil         // preparation
1878e48c0fc5SRavi Teja         getEthernetIfaceData(
1879e48c0fc5SRavi Teja             params[1],
1880e48c0fc5SRavi Teja             [this, asyncResp, parentIfaceId{std::string(params[0])},
1881e48c0fc5SRavi Teja              ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
1882e48c0fc5SRavi Teja                 const bool &success, const EthernetInterfaceData &ethData,
1883e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1884e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1885e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1886e48c0fc5SRavi Teja                     &ipv6StaticData) {
188708244d02SSunitha Harish                 if (success && !ethData.vlan_id.empty())
188808244d02SSunitha Harish                 {
188908244d02SSunitha Harish                     auto callback =
189008244d02SSunitha Harish                         [asyncResp](const boost::system::error_code ec) {
189108244d02SSunitha Harish                             if (ec)
189208244d02SSunitha Harish                             {
189308244d02SSunitha Harish                                 messages::internalError(asyncResp->res);
189408244d02SSunitha Harish                             }
189508244d02SSunitha Harish                         };
189608244d02SSunitha Harish 
189708244d02SSunitha Harish                     if (vlanEnable == true)
189808244d02SSunitha Harish                     {
189908244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
190008244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
190108244d02SSunitha Harish                             "/xyz/openbmc_project/network/" + ifaceId,
190208244d02SSunitha Harish                             "org.freedesktop.DBus.Properties", "Set",
190308244d02SSunitha Harish                             "xyz.openbmc_project.Network.VLAN", "Id",
190408244d02SSunitha Harish                             std::variant<uint32_t>(vlanId));
190508244d02SSunitha Harish                     }
190608244d02SSunitha Harish                     else
190708244d02SSunitha Harish                     {
1908e48c0fc5SRavi Teja                         BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
1909e48c0fc5SRavi Teja                                             "vlan interface";
191008244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
191108244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
1912e48c0fc5SRavi Teja                             std::string("/xyz/openbmc_project/network/") +
1913e48c0fc5SRavi Teja                                 ifaceId,
191408244d02SSunitha Harish                             "xyz.openbmc_project.Object.Delete", "Delete");
191508244d02SSunitha Harish                     }
191608244d02SSunitha Harish                 }
191708244d02SSunitha Harish                 else
19181abe55efSEd Tanous                 {
19191abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
19201abe55efSEd Tanous                     // object, and other errors
1921e48c0fc5SRavi Teja                     messages::resourceNotFound(
1922e48c0fc5SRavi Teja                         asyncResp->res, "VLAN Network Interface", ifaceId);
1923927a505aSKowalski, Kamil                     return;
1924927a505aSKowalski, Kamil                 }
1925927a505aSKowalski, Kamil             });
1926e439f0f8SKowalski, Kamil     }
1927e439f0f8SKowalski, Kamil 
192855c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
19291abe55efSEd Tanous                   const std::vector<std::string> &params) override
19301abe55efSEd Tanous     {
19314a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19321abe55efSEd Tanous         if (params.size() != 2)
19331abe55efSEd Tanous         {
1934f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1935e439f0f8SKowalski, Kamil             return;
1936e439f0f8SKowalski, Kamil         }
1937e439f0f8SKowalski, Kamil 
1938d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
193955c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1940927a505aSKowalski, Kamil 
1941fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
19421abe55efSEd Tanous         {
1943fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1944fda13ad2SSunitha Harish                                        ifaceId);
1945927a505aSKowalski, Kamil             return;
1946927a505aSKowalski, Kamil         }
1947927a505aSKowalski, Kamil 
1948927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1949927a505aSKowalski, Kamil         // preparation
1950f12894f8SJason M. Bills         getEthernetIfaceData(
1951fda13ad2SSunitha Harish             params[1],
1952fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
1953fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
1954f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1955e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1956e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1957e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1958e48c0fc5SRavi Teja                     &ipv6StaticData) {
1959fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
19601abe55efSEd Tanous                 {
1961f12894f8SJason M. Bills                     auto callback =
1962f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
19631abe55efSEd Tanous                             if (ec)
19641abe55efSEd Tanous                             {
1965f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1966927a505aSKowalski, Kamil                             }
19674a0cb85cSEd Tanous                         };
19684a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
19694a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
19704a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
19714a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
19721abe55efSEd Tanous                 }
19731abe55efSEd Tanous                 else
19741abe55efSEd Tanous                 {
1975927a505aSKowalski, Kamil                     // ... otherwise return error
1976f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1977f12894f8SJason M. Bills                     // object, and other errors
1978f12894f8SJason M. Bills                     messages::resourceNotFound(
1979f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1980927a505aSKowalski, Kamil                 }
1981927a505aSKowalski, Kamil             });
1982e439f0f8SKowalski, Kamil     }
1983e439f0f8SKowalski, Kamil };
1984e439f0f8SKowalski, Kamil 
1985e439f0f8SKowalski, Kamil /**
1986e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1987e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1988e439f0f8SKowalski, Kamil  */
19891abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
19901abe55efSEd Tanous {
1991e439f0f8SKowalski, Kamil   public:
1992e439f0f8SKowalski, Kamil     template <typename CrowApp>
19931abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
19944a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
19954a0cb85cSEd Tanous              std::string())
19961abe55efSEd Tanous     {
1997e439f0f8SKowalski, Kamil         entityPrivileges = {
1998e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1999e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
2000e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2001e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2002e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2003e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2004e439f0f8SKowalski, Kamil     }
2005e439f0f8SKowalski, Kamil 
2006e439f0f8SKowalski, Kamil   private:
2007e439f0f8SKowalski, Kamil     /**
2008e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
2009e439f0f8SKowalski, Kamil      */
201055c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
20111abe55efSEd Tanous                const std::vector<std::string> &params) override
20121abe55efSEd Tanous     {
20134a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
20141abe55efSEd Tanous         if (params.size() != 1)
20151abe55efSEd Tanous         {
2016e439f0f8SKowalski, Kamil             // This means there is a problem with the router
2017f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2018e439f0f8SKowalski, Kamil             return;
2019e439f0f8SKowalski, Kamil         }
2020e439f0f8SKowalski, Kamil 
20214a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
2022e439f0f8SKowalski, Kamil 
20234a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
20241abe55efSEd Tanous         // preparation
2025f12894f8SJason M. Bills         getEthernetIfaceList(
202643b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
20271abe55efSEd Tanous                 const bool &success,
20284c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
20294a0cb85cSEd Tanous                 if (!success)
20301abe55efSEd Tanous                 {
2031f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
20324a0cb85cSEd Tanous                     return;
20331abe55efSEd Tanous                 }
20344c9afe43SEd Tanous 
20354c9afe43SEd Tanous                 if (iface_list.find(rootInterfaceName) == iface_list.end())
20364c9afe43SEd Tanous                 {
20374c9afe43SEd Tanous                     messages::resourceNotFound(asyncResp->res,
20384c9afe43SEd Tanous                                                "VLanNetworkInterfaceCollection",
20394c9afe43SEd Tanous                                                rootInterfaceName);
20404c9afe43SEd Tanous                     return;
20414c9afe43SEd Tanous                 }
20424c9afe43SEd Tanous 
20430f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
20440f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
20450f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
20460f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
20470f74e643SEd Tanous                     "/redfish/v1/$metadata"
20480f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
20490f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
20500f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
20510f74e643SEd Tanous                     "VLAN Network Interface Collection";
20524a0cb85cSEd Tanous 
20534a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
20544a0cb85cSEd Tanous 
20554a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
20561abe55efSEd Tanous                 {
20574a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
20584a0cb85cSEd Tanous                     {
20594a0cb85cSEd Tanous                         iface_array.push_back(
20604a0cb85cSEd Tanous                             {{"@odata.id",
20614a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
20624a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
2063e439f0f8SKowalski, Kamil                     }
2064e439f0f8SKowalski, Kamil                 }
2065e439f0f8SKowalski, Kamil 
20664a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
20674a0cb85cSEd Tanous                     iface_array.size();
20684a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
20694a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
20704a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
20714a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
2072e439f0f8SKowalski, Kamil             });
2073e439f0f8SKowalski, Kamil     }
2074e439f0f8SKowalski, Kamil 
207555c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
20761abe55efSEd Tanous                 const std::vector<std::string> &params) override
20771abe55efSEd Tanous     {
20784a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
20791abe55efSEd Tanous         if (params.size() != 1)
20801abe55efSEd Tanous         {
2081f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2082e439f0f8SKowalski, Kamil             return;
2083e439f0f8SKowalski, Kamil         }
2084fda13ad2SSunitha Harish         bool vlanEnable = false;
20850627a2c7SEd Tanous         uint32_t vlanId = 0;
2086fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2087fda13ad2SSunitha Harish                                  vlanEnable))
20881abe55efSEd Tanous         {
20894a0cb85cSEd Tanous             return;
2090e439f0f8SKowalski, Kamil         }
2091fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
2092fda13ad2SSunitha Harish         if (!vlanId)
2093fda13ad2SSunitha Harish         {
2094fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
2095fda13ad2SSunitha Harish         }
2096fda13ad2SSunitha Harish         if (!vlanEnable)
2097fda13ad2SSunitha Harish         {
2098fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
2099fda13ad2SSunitha Harish         }
2100fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2101fda13ad2SSunitha Harish         {
2102fda13ad2SSunitha Harish             return;
2103fda13ad2SSunitha Harish         }
2104fda13ad2SSunitha Harish 
21054a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
21064a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
21071abe55efSEd Tanous             if (ec)
21081abe55efSEd Tanous             {
21094a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
21104a0cb85cSEd Tanous                 // phosphor-network responses
2111f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
21124a0cb85cSEd Tanous                 return;
21131abe55efSEd Tanous             }
2114f12894f8SJason M. Bills             messages::created(asyncResp->res);
2115e439f0f8SKowalski, Kamil         };
21164a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
21174a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
21184a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
21194a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
21200627a2c7SEd Tanous             rootInterfaceName, vlanId);
21214a0cb85cSEd Tanous     }
21224a0cb85cSEd Tanous };
21239391bb9cSRapkiewicz, Pawel } // namespace redfish
2124