xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 18659d104075975913fdbc38841d2aac13e05e61)
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;
1039391bb9cSRapkiewicz, Pawel };
1049391bb9cSRapkiewicz, Pawel 
1059391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
1069391bb9cSRapkiewicz, Pawel // into full dot notation
1071abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
1081abe55efSEd Tanous {
1099391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
1109391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
1119391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
1129391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
1139391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
1149391bb9cSRapkiewicz, Pawel     return netmask;
1159391bb9cSRapkiewicz, Pawel }
1169391bb9cSRapkiewicz, Pawel 
1174a0cb85cSEd Tanous inline std::string
1184a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1194a0cb85cSEd Tanous                                         bool isIPv4)
1201abe55efSEd Tanous {
1214a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1221abe55efSEd Tanous     {
1234a0cb85cSEd Tanous         return "Static";
1249391bb9cSRapkiewicz, Pawel     }
1254a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1261abe55efSEd Tanous     {
1274a0cb85cSEd Tanous         if (isIPv4)
1281abe55efSEd Tanous         {
1294a0cb85cSEd Tanous             return "IPv4LinkLocal";
1301abe55efSEd Tanous         }
1311abe55efSEd Tanous         else
1321abe55efSEd Tanous         {
1334a0cb85cSEd Tanous             return "LinkLocal";
1349391bb9cSRapkiewicz, Pawel         }
1359391bb9cSRapkiewicz, Pawel     }
1364a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1371abe55efSEd Tanous     {
1384a0cb85cSEd Tanous         if (isIPv4)
1394a0cb85cSEd Tanous         {
1404a0cb85cSEd Tanous             return "DHCP";
1414a0cb85cSEd Tanous         }
1424a0cb85cSEd Tanous         else
1434a0cb85cSEd Tanous         {
1444a0cb85cSEd Tanous             return "DHCPv6";
1454a0cb85cSEd Tanous         }
1464a0cb85cSEd Tanous     }
1474a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1484a0cb85cSEd Tanous     {
1494a0cb85cSEd Tanous         return "SLAAC";
1504a0cb85cSEd Tanous     }
1514a0cb85cSEd Tanous     return "";
1524a0cb85cSEd Tanous }
1534a0cb85cSEd Tanous 
1544a0cb85cSEd Tanous inline std::string
1554a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1564a0cb85cSEd Tanous {
1574a0cb85cSEd Tanous     if (inputOrigin == "Static")
1584a0cb85cSEd Tanous     {
1594a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1604a0cb85cSEd Tanous     }
1614a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1624a0cb85cSEd Tanous     {
1634a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1644a0cb85cSEd Tanous     }
1654a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1664a0cb85cSEd Tanous     {
1674a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1684a0cb85cSEd Tanous     }
1694a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1704a0cb85cSEd Tanous     {
1714a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1724a0cb85cSEd Tanous     }
1734a0cb85cSEd Tanous     return "";
1744a0cb85cSEd Tanous }
1754a0cb85cSEd Tanous 
1764c9afe43SEd Tanous inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
1774a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1784a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1794a0cb85cSEd Tanous {
1804c9afe43SEd Tanous     bool idFound = false;
1814a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1824a0cb85cSEd Tanous     {
1834a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1844a0cb85cSEd Tanous         {
185029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
186029573d4SEd Tanous             {
1874c9afe43SEd Tanous                 idFound = true;
1884a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1894a0cb85cSEd Tanous                 {
1904a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1914a0cb85cSEd Tanous                     {
1924a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1934a0cb85cSEd Tanous                         {
1944a0cb85cSEd Tanous                             const std::string *mac =
195abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1964a0cb85cSEd Tanous                             if (mac != nullptr)
1974a0cb85cSEd Tanous                             {
1984a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1994a0cb85cSEd Tanous                             }
2004a0cb85cSEd Tanous                         }
2014a0cb85cSEd Tanous                     }
2024a0cb85cSEd Tanous                 }
2034a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
2044a0cb85cSEd Tanous                 {
2054a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2064a0cb85cSEd Tanous                     {
2074a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
2084a0cb85cSEd Tanous                         {
2091b6b96c5SEd Tanous                             const uint32_t *id =
210abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2114a0cb85cSEd Tanous                             if (id != nullptr)
2124a0cb85cSEd Tanous                             {
213fda13ad2SSunitha Harish                                 ethData.vlan_id.push_back(*id);
2144a0cb85cSEd Tanous                             }
2154a0cb85cSEd Tanous                         }
2164a0cb85cSEd Tanous                     }
2174a0cb85cSEd Tanous                 }
2184a0cb85cSEd Tanous                 else if (ifacePair.first ==
2194a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2204a0cb85cSEd Tanous                 {
2214a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2224a0cb85cSEd Tanous                     {
2234a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2244a0cb85cSEd Tanous                         {
2254a0cb85cSEd Tanous                             const bool *auto_neg =
226abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2274a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2284a0cb85cSEd Tanous                             {
2294a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2304a0cb85cSEd Tanous                             }
2314a0cb85cSEd Tanous                         }
2324a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2334a0cb85cSEd Tanous                         {
2344a0cb85cSEd Tanous                             const uint32_t *speed =
235abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2364a0cb85cSEd Tanous                             if (speed != nullptr)
2374a0cb85cSEd Tanous                             {
2384a0cb85cSEd Tanous                                 ethData.speed = *speed;
2394a0cb85cSEd Tanous                             }
2404a0cb85cSEd Tanous                         }
241f85837bfSRAJESWARAN THILLAIGOVINDAN                         else if (propertyPair.first == "Nameservers")
242029573d4SEd Tanous                         {
243029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
244029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
245029573d4SEd Tanous                                     std::vector<std::string>>(
246029573d4SEd Tanous                                     &propertyPair.second);
247029573d4SEd Tanous                             if (nameservers != nullptr)
248029573d4SEd Tanous                             {
249029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2504a0cb85cSEd Tanous                             }
2514a0cb85cSEd Tanous                         }
2522a133282Smanojkiraneda                         else if (propertyPair.first == "DHCPEnabled")
2532a133282Smanojkiraneda                         {
2542a133282Smanojkiraneda                             const bool *DHCPEnabled =
2552a133282Smanojkiraneda                                 std::get_if<bool>(&propertyPair.second);
2562a133282Smanojkiraneda                             if (DHCPEnabled != nullptr)
2572a133282Smanojkiraneda                             {
2582a133282Smanojkiraneda                                 ethData.DHCPEnabled = *DHCPEnabled;
2592a133282Smanojkiraneda                             }
2602a133282Smanojkiraneda                         }
261029573d4SEd Tanous                     }
262029573d4SEd Tanous                 }
263029573d4SEd Tanous             }
264029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
265029573d4SEd Tanous             // to check eth number
266029573d4SEd Tanous             if (ifacePair.first ==
2674a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2684a0cb85cSEd Tanous             {
2694a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2704a0cb85cSEd Tanous                 {
2714a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2724a0cb85cSEd Tanous                     {
2734a0cb85cSEd Tanous                         const std::string *hostname =
274029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
275029573d4SEd Tanous                                 &propertyPair.second);
2764a0cb85cSEd Tanous                         if (hostname != nullptr)
2774a0cb85cSEd Tanous                         {
2784a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2794a0cb85cSEd Tanous                         }
2804a0cb85cSEd Tanous                     }
2814a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2824a0cb85cSEd Tanous                     {
2834a0cb85cSEd Tanous                         const std::string *defaultGateway =
284029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
285029573d4SEd Tanous                                 &propertyPair.second);
2864a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2874a0cb85cSEd Tanous                         {
2884a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2894a0cb85cSEd Tanous                         }
2904a0cb85cSEd Tanous                     }
2919a6fc6feSRavi Teja                     else if (propertyPair.first == "DefaultGateway6")
2929a6fc6feSRavi Teja                     {
2939a6fc6feSRavi Teja                         const std::string *defaultGateway6 =
2949a6fc6feSRavi Teja                             sdbusplus::message::variant_ns::get_if<std::string>(
2959a6fc6feSRavi Teja                                 &propertyPair.second);
2969a6fc6feSRavi Teja                         if (defaultGateway6 != nullptr)
2979a6fc6feSRavi Teja                         {
2989a6fc6feSRavi Teja                             ethData.ipv6_default_gateway = *defaultGateway6;
2999a6fc6feSRavi Teja                         }
3009a6fc6feSRavi Teja                     }
3014a0cb85cSEd Tanous                 }
3024a0cb85cSEd Tanous             }
3034a0cb85cSEd Tanous         }
3044a0cb85cSEd Tanous     }
3054c9afe43SEd Tanous     return idFound;
3064a0cb85cSEd Tanous }
3074a0cb85cSEd Tanous 
308e48c0fc5SRavi Teja // Helper function that extracts data for single ethernet ipv6 address
309e48c0fc5SRavi Teja inline void extractIPV6Data(
310e48c0fc5SRavi Teja     const std::string &ethiface_id, const GetManagedObjects &dbus_data,
311e48c0fc5SRavi Teja     boost::container::flat_set<IPv6AddressData> &ipv6_config,
312e48c0fc5SRavi Teja     boost::container::flat_set<IPv6AddressData> &ipv6_static_config)
313e48c0fc5SRavi Teja {
314e48c0fc5SRavi Teja     const std::string ipv6PathStart =
315e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv6/";
316e48c0fc5SRavi Teja 
317e48c0fc5SRavi Teja     // Since there might be several IPv6 configurations aligned with
318e48c0fc5SRavi Teja     // single ethernet interface, loop over all of them
319e48c0fc5SRavi Teja     for (const auto &objpath : dbus_data)
320e48c0fc5SRavi Teja     {
321e48c0fc5SRavi Teja         // Check if proper pattern for object path appears
322e48c0fc5SRavi Teja         if (boost::starts_with(objpath.first.str, ipv6PathStart))
323e48c0fc5SRavi Teja         {
324e48c0fc5SRavi Teja             for (auto &interface : objpath.second)
325e48c0fc5SRavi Teja             {
326e48c0fc5SRavi Teja                 if (interface.first == "xyz.openbmc_project.Network.IP")
327e48c0fc5SRavi Teja                 {
328e48c0fc5SRavi Teja                     // Instance IPv6AddressData structure, and set as
329e48c0fc5SRavi Teja                     // appropriate
330e48c0fc5SRavi Teja                     std::pair<
331e48c0fc5SRavi Teja                         boost::container::flat_set<IPv6AddressData>::iterator,
332e48c0fc5SRavi Teja                         bool>
333e48c0fc5SRavi Teja                         it = ipv6_config.insert(
334e48c0fc5SRavi Teja                             {objpath.first.str.substr(ipv6PathStart.size())});
335e48c0fc5SRavi Teja                     IPv6AddressData &ipv6_address = *it.first;
336e48c0fc5SRavi Teja                     for (auto &property : interface.second)
337e48c0fc5SRavi Teja                     {
338e48c0fc5SRavi Teja                         if (property.first == "Address")
339e48c0fc5SRavi Teja                         {
340e48c0fc5SRavi Teja                             const std::string *address =
341e48c0fc5SRavi Teja                                 std::get_if<std::string>(&property.second);
342e48c0fc5SRavi Teja                             if (address != nullptr)
343e48c0fc5SRavi Teja                             {
344e48c0fc5SRavi Teja                                 ipv6_address.address = *address;
345e48c0fc5SRavi Teja                             }
346e48c0fc5SRavi Teja                         }
347e48c0fc5SRavi Teja                         else if (property.first == "Origin")
348e48c0fc5SRavi Teja                         {
349e48c0fc5SRavi Teja                             const std::string *origin =
350e48c0fc5SRavi Teja                                 std::get_if<std::string>(&property.second);
351e48c0fc5SRavi Teja                             if (origin != nullptr)
352e48c0fc5SRavi Teja                             {
353e48c0fc5SRavi Teja                                 ipv6_address.origin =
354e48c0fc5SRavi Teja                                     translateAddressOriginDbusToRedfish(*origin,
355e48c0fc5SRavi Teja                                                                         false);
356e48c0fc5SRavi Teja                             }
357e48c0fc5SRavi Teja                         }
358e48c0fc5SRavi Teja                         else if (property.first == "PrefixLength")
359e48c0fc5SRavi Teja                         {
360e48c0fc5SRavi Teja                             const uint8_t *prefix =
361e48c0fc5SRavi Teja                                 std::get_if<uint8_t>(&property.second);
362e48c0fc5SRavi Teja                             if (prefix != nullptr)
363e48c0fc5SRavi Teja                             {
364e48c0fc5SRavi Teja                                 ipv6_address.prefixLength = *prefix;
365e48c0fc5SRavi Teja                             }
366e48c0fc5SRavi Teja                         }
367e48c0fc5SRavi Teja                         else
368e48c0fc5SRavi Teja                         {
369e48c0fc5SRavi Teja                             BMCWEB_LOG_ERROR
370e48c0fc5SRavi Teja                                 << "Got extra property: " << property.first
371e48c0fc5SRavi Teja                                 << " on the " << objpath.first.str << " object";
372e48c0fc5SRavi Teja                         }
373e48c0fc5SRavi Teja                     }
374e48c0fc5SRavi Teja                     if (ipv6_address.origin == "Static")
375e48c0fc5SRavi Teja                     {
376e48c0fc5SRavi Teja                         std::pair<boost::container::flat_set<
377e48c0fc5SRavi Teja                                       IPv6AddressData>::iterator,
378e48c0fc5SRavi Teja                                   bool>
379e48c0fc5SRavi Teja                             iter = ipv6_static_config.insert(
380e48c0fc5SRavi Teja                                 {objpath.first.str.substr(
381e48c0fc5SRavi Teja                                     ipv6PathStart.size())});
382e48c0fc5SRavi Teja                         IPv6AddressData &ipv6_static_address = *iter.first;
383e48c0fc5SRavi Teja 
384e48c0fc5SRavi Teja                         ipv6_static_address.address = ipv6_address.address;
385e48c0fc5SRavi Teja                         ipv6_static_address.prefixLength =
386e48c0fc5SRavi Teja                             ipv6_address.prefixLength;
387e48c0fc5SRavi Teja                     }
388e48c0fc5SRavi Teja                 }
389e48c0fc5SRavi Teja             }
390e48c0fc5SRavi Teja         }
391e48c0fc5SRavi Teja     }
392e48c0fc5SRavi Teja }
393e48c0fc5SRavi Teja 
3944a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
3954a0cb85cSEd Tanous inline void
3964a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
3974a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
3984a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
3994a0cb85cSEd Tanous {
4004a0cb85cSEd Tanous     const std::string ipv4PathStart =
4014a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
4024a0cb85cSEd Tanous 
4034a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
4044a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
4054a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
4064a0cb85cSEd Tanous     {
4074a0cb85cSEd Tanous         // Check if proper pattern for object path appears
4084a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
4094a0cb85cSEd Tanous         {
4104a0cb85cSEd Tanous             for (auto &interface : objpath.second)
4114a0cb85cSEd Tanous             {
4124a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
4134a0cb85cSEd Tanous                 {
4144a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
4154a0cb85cSEd Tanous                     // appropriate
4164a0cb85cSEd Tanous                     std::pair<
4174a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
4184a0cb85cSEd Tanous                         bool>
4194a0cb85cSEd Tanous                         it = ipv4_config.insert(
420b01bf299SEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
4214a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
4224a0cb85cSEd Tanous                     for (auto &property : interface.second)
4234a0cb85cSEd Tanous                     {
4244a0cb85cSEd Tanous                         if (property.first == "Address")
4254a0cb85cSEd Tanous                         {
4264a0cb85cSEd Tanous                             const std::string *address =
427abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4284a0cb85cSEd Tanous                             if (address != nullptr)
4294a0cb85cSEd Tanous                             {
4304a0cb85cSEd Tanous                                 ipv4_address.address = *address;
4314a0cb85cSEd Tanous                             }
4324a0cb85cSEd Tanous                         }
4334a0cb85cSEd Tanous                         else if (property.first == "Gateway")
4344a0cb85cSEd Tanous                         {
4354a0cb85cSEd Tanous                             const std::string *gateway =
436abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4374a0cb85cSEd Tanous                             if (gateway != nullptr)
4384a0cb85cSEd Tanous                             {
4394a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
4404a0cb85cSEd Tanous                             }
4414a0cb85cSEd Tanous                         }
4424a0cb85cSEd Tanous                         else if (property.first == "Origin")
4434a0cb85cSEd Tanous                         {
4444a0cb85cSEd Tanous                             const std::string *origin =
445abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
4464a0cb85cSEd Tanous                             if (origin != nullptr)
4474a0cb85cSEd Tanous                             {
4484a0cb85cSEd Tanous                                 ipv4_address.origin =
4494a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
4504a0cb85cSEd Tanous                                                                         true);
4514a0cb85cSEd Tanous                             }
4524a0cb85cSEd Tanous                         }
4534a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
4544a0cb85cSEd Tanous                         {
4554a0cb85cSEd Tanous                             const uint8_t *mask =
456abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
4574a0cb85cSEd Tanous                             if (mask != nullptr)
4584a0cb85cSEd Tanous                             {
4594a0cb85cSEd Tanous                                 // convert it to the string
4604a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
4614a0cb85cSEd Tanous                             }
4624a0cb85cSEd Tanous                         }
4634a0cb85cSEd Tanous                         else
4644a0cb85cSEd Tanous                         {
4654a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
4664a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
4674a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
4684a0cb85cSEd Tanous                         }
4694a0cb85cSEd Tanous                     }
4704a0cb85cSEd Tanous                     // Check if given address is local, or global
4714a0cb85cSEd Tanous                     ipv4_address.linktype =
4724a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
473*18659d10SJohnathan Mantey                             ? LinkType::Local
474*18659d10SJohnathan Mantey                             : LinkType::Global;
4754a0cb85cSEd Tanous                 }
4764a0cb85cSEd Tanous             }
4774a0cb85cSEd Tanous         }
4784a0cb85cSEd Tanous     }
4794a0cb85cSEd Tanous }
480588c3f0dSKowalski, Kamil 
481588c3f0dSKowalski, Kamil /**
482588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
483588c3f0dSKowalski, Kamil  *
484588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
485588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
486588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
487588c3f0dSKowalski, Kamil  *
488588c3f0dSKowalski, Kamil  * @return None.
489588c3f0dSKowalski, Kamil  */
490588c3f0dSKowalski, Kamil template <typename CallbackFunc>
4914a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
4921abe55efSEd Tanous                   CallbackFunc &&callback)
4931abe55efSEd Tanous {
49455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
495588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
496588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
497588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
498588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
499abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
5004a0cb85cSEd Tanous }
501588c3f0dSKowalski, Kamil 
502588c3f0dSKowalski, Kamil /**
503179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
504179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
505179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
506179db1d7SKowalski, Kamil  *
507179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
508179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
509179db1d7SKowalski, Kamil  *
510179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
511179db1d7SKowalski, Kamil  */
5124a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
5131abe55efSEd Tanous                                        uint8_t *bits = nullptr)
5141abe55efSEd Tanous {
515179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
516179db1d7SKowalski, Kamil 
517179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
518179db1d7SKowalski, Kamil 
5194a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
5201abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
5211abe55efSEd Tanous     {
522179db1d7SKowalski, Kamil         return false;
523179db1d7SKowalski, Kamil     }
524179db1d7SKowalski, Kamil 
5251abe55efSEd Tanous     if (bits != nullptr)
5261abe55efSEd Tanous     {
527179db1d7SKowalski, Kamil         *bits = 0;
528179db1d7SKowalski, Kamil     }
529179db1d7SKowalski, Kamil 
530179db1d7SKowalski, Kamil     char *endPtr;
531179db1d7SKowalski, Kamil     long previousValue = 255;
532179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
5331abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
5341abe55efSEd Tanous     {
5351abe55efSEd Tanous         if (byte.empty())
5361abe55efSEd Tanous         {
5371db9ca37SKowalski, Kamil             return false;
5381db9ca37SKowalski, Kamil         }
5391db9ca37SKowalski, Kamil 
540179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
5411db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
542179db1d7SKowalski, Kamil 
5434a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
5444a0cb85cSEd Tanous         // is not 100% number
5451abe55efSEd Tanous         if (*endPtr != '\0')
5461abe55efSEd Tanous         {
547179db1d7SKowalski, Kamil             return false;
548179db1d7SKowalski, Kamil         }
549179db1d7SKowalski, Kamil 
550179db1d7SKowalski, Kamil         // Value should be contained in byte
5511abe55efSEd Tanous         if (value < 0 || value > 255)
5521abe55efSEd Tanous         {
553179db1d7SKowalski, Kamil             return false;
554179db1d7SKowalski, Kamil         }
555179db1d7SKowalski, Kamil 
5561abe55efSEd Tanous         if (bits != nullptr)
5571abe55efSEd Tanous         {
558179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
5591abe55efSEd Tanous             if (previousValue != 255 && value != 0)
5601abe55efSEd Tanous             {
561179db1d7SKowalski, Kamil                 return false;
562179db1d7SKowalski, Kamil             }
563179db1d7SKowalski, Kamil 
564179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
565179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
566179db1d7SKowalski, Kamil 
567179db1d7SKowalski, Kamil             // Count bits
5681abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
5691abe55efSEd Tanous             {
5701abe55efSEd Tanous                 if (value & (1 << bitIdx))
5711abe55efSEd Tanous                 {
5721abe55efSEd Tanous                     if (firstZeroInByteHit)
5731abe55efSEd Tanous                     {
574179db1d7SKowalski, Kamil                         // Continuity not preserved
575179db1d7SKowalski, Kamil                         return false;
5761abe55efSEd Tanous                     }
5771abe55efSEd Tanous                     else
5781abe55efSEd Tanous                     {
579179db1d7SKowalski, Kamil                         (*bits)++;
580179db1d7SKowalski, Kamil                     }
5811abe55efSEd Tanous                 }
5821abe55efSEd Tanous                 else
5831abe55efSEd Tanous                 {
584179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
585179db1d7SKowalski, Kamil                 }
586179db1d7SKowalski, Kamil             }
587179db1d7SKowalski, Kamil         }
588179db1d7SKowalski, Kamil 
589179db1d7SKowalski, Kamil         previousValue = value;
590179db1d7SKowalski, Kamil     }
591179db1d7SKowalski, Kamil 
592179db1d7SKowalski, Kamil     return true;
593179db1d7SKowalski, Kamil }
594179db1d7SKowalski, Kamil 
595179db1d7SKowalski, Kamil /**
596b01bf299SEd Tanous  * @brief Changes IPv4 address type property (Address, Gateway)
597b01bf299SEd Tanous  *
598b01bf299SEd Tanous  * @param[in] ifaceId     Id of interface whose IP should be modified
599b01bf299SEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
600b01bf299SEd Tanous  * @param[in] ipHash      DBus Hash id of modified IP
601b01bf299SEd Tanous  * @param[in] name        Name of field in JSON representation
602b01bf299SEd Tanous  * @param[in] newValue    New value that should be written
603b01bf299SEd Tanous  * @param[io] asyncResp   Response object that will be returned to client
604b01bf299SEd Tanous  *
605b01bf299SEd Tanous  * @return true if give IP is valid and has been sent do D-Bus, false
606b01bf299SEd Tanous  * otherwise
607b01bf299SEd Tanous  */
608b01bf299SEd Tanous inline void changeIPv4AddressProperty(
609b01bf299SEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
610b01bf299SEd Tanous     const std::string &name, const std::string &newValue,
611b01bf299SEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
612b01bf299SEd Tanous {
613b01bf299SEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
614b01bf299SEd Tanous                      newValue{std::move(newValue)}](
615b01bf299SEd Tanous                         const boost::system::error_code ec) {
616b01bf299SEd Tanous         if (ec)
617b01bf299SEd Tanous         {
618b01bf299SEd Tanous             messages::internalError(asyncResp->res);
619b01bf299SEd Tanous         }
620b01bf299SEd Tanous         else
621b01bf299SEd Tanous         {
622b01bf299SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
623b01bf299SEd Tanous         }
624b01bf299SEd Tanous     };
625b01bf299SEd Tanous 
626b01bf299SEd Tanous     crow::connections::systemBus->async_method_call(
627b01bf299SEd Tanous         std::move(callback), "xyz.openbmc_project.Network",
628b01bf299SEd Tanous         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
629b01bf299SEd Tanous         "org.freedesktop.DBus.Properties", "Set",
630b01bf299SEd Tanous         "xyz.openbmc_project.Network.IP", name,
631b01bf299SEd Tanous         std::variant<std::string>(newValue));
632b01bf299SEd Tanous }
633b01bf299SEd Tanous 
634b01bf299SEd Tanous /**
635179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
636179db1d7SKowalski, Kamil  *
637179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
6384a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
6391abe55efSEd Tanous  * modified
640179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
641179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
642179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
643179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
644179db1d7SKowalski, Kamil  *
645179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
646179db1d7SKowalski, Kamil  * otherwise
647179db1d7SKowalski, Kamil  */
648b01bf299SEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
6491abe55efSEd Tanous                              const std::string &ipHash,
6501abe55efSEd Tanous                              const std::string &newValue,
651179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
6524a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
6531abe55efSEd Tanous {
6544a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
6551abe55efSEd Tanous                         const boost::system::error_code ec) {
6561abe55efSEd Tanous         if (ec)
6571abe55efSEd Tanous         {
658a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
6591abe55efSEd Tanous         }
6601abe55efSEd Tanous         else
6611abe55efSEd Tanous         {
6624a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
663179db1d7SKowalski, Kamil                 newValue;
664179db1d7SKowalski, Kamil         }
665179db1d7SKowalski, Kamil     };
666179db1d7SKowalski, Kamil 
66755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
668179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
669179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
670179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
671179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
672abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
6734a0cb85cSEd Tanous }
674179db1d7SKowalski, Kamil 
675179db1d7SKowalski, Kamil /**
676179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
677179db1d7SKowalski, Kamil  *
678179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
6794a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
6801abe55efSEd Tanous  * modified
681179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
682179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
683179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
684179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
685179db1d7SKowalski, Kamil  *
686179db1d7SKowalski, Kamil  * @return None
687179db1d7SKowalski, Kamil  */
688b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
6894a0cb85cSEd Tanous                                          const std::string &ipHash,
6904a0cb85cSEd Tanous                                          const std::string &newValueStr,
6914a0cb85cSEd Tanous                                          uint8_t &newValue,
6924a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
6931abe55efSEd Tanous {
6944a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
6951abe55efSEd Tanous                         const boost::system::error_code ec) {
6961abe55efSEd Tanous         if (ec)
6971abe55efSEd Tanous         {
698a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
6991abe55efSEd Tanous         }
7001abe55efSEd Tanous         else
7011abe55efSEd Tanous         {
70255c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
703179db1d7SKowalski, Kamil                 newValueStr;
704179db1d7SKowalski, Kamil         }
705179db1d7SKowalski, Kamil     };
706179db1d7SKowalski, Kamil 
70755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
708179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
709179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
710179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
711179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
712abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
7134a0cb85cSEd Tanous }
714588c3f0dSKowalski, Kamil 
715588c3f0dSKowalski, Kamil /**
716179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
717179db1d7SKowalski, Kamil  *
718179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
7194a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
720179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
721179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
722179db1d7SKowalski, Kamil  *
723179db1d7SKowalski, Kamil  * @return None
724179db1d7SKowalski, Kamil  */
7254a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
726179db1d7SKowalski, Kamil                        unsigned int ipIdx,
7274a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
7281abe55efSEd Tanous {
72955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7304a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
7311abe55efSEd Tanous             if (ec)
7321abe55efSEd Tanous             {
733a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
7341abe55efSEd Tanous             }
7351abe55efSEd Tanous             else
7361abe55efSEd Tanous             {
73755c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
738179db1d7SKowalski, Kamil             }
739179db1d7SKowalski, Kamil         },
740179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
741179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
742179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
743179db1d7SKowalski, Kamil }
744179db1d7SKowalski, Kamil 
745179db1d7SKowalski, Kamil /**
746179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
747179db1d7SKowalski, Kamil  *
748179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
7494a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
750179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
751179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
752179db1d7SKowalski, Kamil  *
753179db1d7SKowalski, Kamil  * @return None
754179db1d7SKowalski, Kamil  */
755b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
756b01bf299SEd Tanous                        uint8_t subnetMask, const std::string &gateway,
757b01bf299SEd Tanous                        const std::string &address,
7584a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
7591abe55efSEd Tanous {
76043b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
7611abe55efSEd Tanous         if (ec)
7621abe55efSEd Tanous         {
763a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
764179db1d7SKowalski, Kamil         }
765179db1d7SKowalski, Kamil     };
766179db1d7SKowalski, Kamil 
76755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
768179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
769179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
770179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
771179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
772179db1d7SKowalski, Kamil         gateway);
773179db1d7SKowalski, Kamil }
774e48c0fc5SRavi Teja 
775e48c0fc5SRavi Teja /**
776e48c0fc5SRavi Teja  * @brief Deletes given IPv6
777e48c0fc5SRavi Teja  *
778e48c0fc5SRavi Teja  * @param[in] ifaceId     Id of interface whose IP should be deleted
779e48c0fc5SRavi Teja  * @param[in] ipHash      DBus Hash id of IP that should be deleted
780e48c0fc5SRavi Teja  * @param[in] ipIdx       Index of IP in input array that should be deleted
781e48c0fc5SRavi Teja  * @param[io] asyncResp   Response object that will be returned to client
782e48c0fc5SRavi Teja  *
783e48c0fc5SRavi Teja  * @return None
784e48c0fc5SRavi Teja  */
785e48c0fc5SRavi Teja inline void deleteIPv6(const std::string &ifaceId, const std::string &ipHash,
786e48c0fc5SRavi Teja                        unsigned int ipIdx,
787e48c0fc5SRavi Teja                        const std::shared_ptr<AsyncResp> asyncResp)
788e48c0fc5SRavi Teja {
789e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
790e48c0fc5SRavi Teja         [ipIdx, asyncResp](const boost::system::error_code ec) {
791e48c0fc5SRavi Teja             if (ec)
792e48c0fc5SRavi Teja             {
793e48c0fc5SRavi Teja                 messages::internalError(asyncResp->res);
794e48c0fc5SRavi Teja             }
795e48c0fc5SRavi Teja             else
796e48c0fc5SRavi Teja             {
797e48c0fc5SRavi Teja                 asyncResp->res.jsonValue["IPv6StaticAddresses"][ipIdx] =
798e48c0fc5SRavi Teja                     nullptr;
799e48c0fc5SRavi Teja             }
800e48c0fc5SRavi Teja         },
801e48c0fc5SRavi Teja         "xyz.openbmc_project.Network",
802e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" + ipHash,
803e48c0fc5SRavi Teja         "xyz.openbmc_project.Object.Delete", "Delete");
804e48c0fc5SRavi Teja }
805e48c0fc5SRavi Teja 
806e48c0fc5SRavi Teja /**
807e48c0fc5SRavi Teja  * @brief Creates IPv6 with given data
808e48c0fc5SRavi Teja  *
809e48c0fc5SRavi Teja  * @param[in] ifaceId      Id of interface whose IP should be added
810e48c0fc5SRavi Teja  * @param[in] ipIdx        Index of IP in input array that should be added
811e48c0fc5SRavi Teja  * @param[in] prefixLength Prefix length that needs to be added
812e48c0fc5SRavi Teja  * @param[in] address      IP address that needs to be added
813e48c0fc5SRavi Teja  * @param[io] asyncResp    Response object that will be returned to client
814e48c0fc5SRavi Teja  *
815e48c0fc5SRavi Teja  * @return None
816e48c0fc5SRavi Teja  */
817e48c0fc5SRavi Teja inline void createIPv6(const std::string &ifaceId, unsigned int ipIdx,
818e48c0fc5SRavi Teja                        uint8_t prefixLength, const std::string &address,
819e48c0fc5SRavi Teja                        std::shared_ptr<AsyncResp> asyncResp)
820e48c0fc5SRavi Teja {
821e48c0fc5SRavi Teja     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
822e48c0fc5SRavi Teja         if (ec)
823e48c0fc5SRavi Teja         {
824e48c0fc5SRavi Teja             messages::internalError(asyncResp->res);
825e48c0fc5SRavi Teja         }
826e48c0fc5SRavi Teja     };
827e48c0fc5SRavi Teja     // Passing null for gateway, as per redfish spec IPv6StaticAddresses object
828e48c0fc5SRavi Teja     // does not have assosiated gateway property
829e48c0fc5SRavi Teja     crow::connections::systemBus->async_method_call(
830e48c0fc5SRavi Teja         std::move(createIpHandler), "xyz.openbmc_project.Network",
831e48c0fc5SRavi Teja         "/xyz/openbmc_project/network/" + ifaceId,
832e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Create", "IP",
833e48c0fc5SRavi Teja         "xyz.openbmc_project.Network.IP.Protocol.IPv6", address, prefixLength,
834e48c0fc5SRavi Teja         "");
835e48c0fc5SRavi Teja }
836e48c0fc5SRavi Teja 
8372a133282Smanojkiraneda using GetAllPropertiesType =
8382a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
8392a133282Smanojkiraneda 
8402a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
8412a133282Smanojkiraneda {
8422a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
8432a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
8442a133282Smanojkiraneda         if (error_code)
8452a133282Smanojkiraneda         {
8462a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
8472a133282Smanojkiraneda             messages::internalError(asyncResp->res);
8482a133282Smanojkiraneda             return;
8492a133282Smanojkiraneda         }
850fda13ad2SSunitha Harish         nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
8512a133282Smanojkiraneda         for (const auto &property : dbus_data)
8522a133282Smanojkiraneda         {
8532a133282Smanojkiraneda             auto value =
8542a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
8552a133282Smanojkiraneda 
8562a133282Smanojkiraneda             if (value == nullptr)
8572a133282Smanojkiraneda             {
8582a133282Smanojkiraneda                 continue;
8592a133282Smanojkiraneda             }
8602a133282Smanojkiraneda             if (property.first == "DNSEnabled")
8612a133282Smanojkiraneda             {
8622a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
8632a133282Smanojkiraneda             }
8642a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
8652a133282Smanojkiraneda             {
8662a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
8672a133282Smanojkiraneda             }
8682a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
8692a133282Smanojkiraneda             {
8702a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
8712a133282Smanojkiraneda             }
8722a133282Smanojkiraneda         }
8732a133282Smanojkiraneda     };
8742a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
8752a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
8762a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
8772a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
8782a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
8792a133282Smanojkiraneda }
880179db1d7SKowalski, Kamil 
881179db1d7SKowalski, Kamil /**
882179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
883179db1d7SKowalski, Kamil  * Object
884179db1d7SKowalski, Kamil  * from EntityManager Network Manager
8854a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
886179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
887179db1d7SKowalski, Kamil  * into JSON
888179db1d7SKowalski, Kamil  */
889179db1d7SKowalski, Kamil template <typename CallbackFunc>
8904a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
8911abe55efSEd Tanous                           CallbackFunc &&callback)
8921abe55efSEd Tanous {
89355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
8944a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
8951abe55efSEd Tanous             const boost::system::error_code error_code,
8964a0cb85cSEd Tanous             const GetManagedObjects &resp) {
89755c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
8984a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
899e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6Data;
900e48c0fc5SRavi Teja             boost::container::flat_set<IPv6AddressData> ipv6StaticData;
901179db1d7SKowalski, Kamil 
9021abe55efSEd Tanous             if (error_code)
9031abe55efSEd Tanous             {
904e48c0fc5SRavi Teja                 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
905179db1d7SKowalski, Kamil                 return;
906179db1d7SKowalski, Kamil             }
907179db1d7SKowalski, Kamil 
9084c9afe43SEd Tanous             bool found =
9094a0cb85cSEd Tanous                 extractEthernetInterfaceData(ethiface_id, resp, ethData);
9104c9afe43SEd Tanous             if (!found)
9114c9afe43SEd Tanous             {
912e48c0fc5SRavi Teja                 callback(false, ethData, ipv4Data, ipv6Data, ipv6StaticData);
9134c9afe43SEd Tanous                 return;
9144c9afe43SEd Tanous             }
9154c9afe43SEd Tanous 
9164a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
917179db1d7SKowalski, Kamil             // Fix global GW
9181abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
9191abe55efSEd Tanous             {
9204a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
9214a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
9221abe55efSEd Tanous                 {
9234a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
924179db1d7SKowalski, Kamil                 }
925179db1d7SKowalski, Kamil             }
926179db1d7SKowalski, Kamil 
927e48c0fc5SRavi Teja             extractIPV6Data(ethiface_id, resp, ipv6Data, ipv6StaticData);
9284a0cb85cSEd Tanous             // Finally make a callback with usefull data
929e48c0fc5SRavi Teja             callback(true, ethData, ipv4Data, ipv6Data, ipv6StaticData);
930179db1d7SKowalski, Kamil         },
931179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
932179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
933179db1d7SKowalski, Kamil };
934179db1d7SKowalski, Kamil 
935179db1d7SKowalski, Kamil /**
9369391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
9379391bb9cSRapkiewicz, Pawel  * Manager
9381abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
9391abe55efSEd Tanous  * into JSON.
9409391bb9cSRapkiewicz, Pawel  */
9419391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
9421abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
9431abe55efSEd Tanous {
94455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
9454a0cb85cSEd Tanous         [callback{std::move(callback)}](
9469391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
9474a0cb85cSEd Tanous             GetManagedObjects &resp) {
9481abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
9491abe55efSEd Tanous             // ethernet interfaces
9504c9afe43SEd Tanous             boost::container::flat_set<std::string> iface_list;
9514a0cb85cSEd Tanous             iface_list.reserve(resp.size());
9521abe55efSEd Tanous             if (error_code)
9531abe55efSEd Tanous             {
9544a0cb85cSEd Tanous                 callback(false, iface_list);
9559391bb9cSRapkiewicz, Pawel                 return;
9569391bb9cSRapkiewicz, Pawel             }
9579391bb9cSRapkiewicz, Pawel 
9589391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
9594a0cb85cSEd Tanous             for (const auto &objpath : resp)
9601abe55efSEd Tanous             {
9619391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
9624a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
9631abe55efSEd Tanous                 {
9641abe55efSEd Tanous                     // If interface is
9654a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
9664a0cb85cSEd Tanous                     // what we're looking for.
9679391bb9cSRapkiewicz, Pawel                     if (interface.first ==
9681abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
9691abe55efSEd Tanous                     {
9704a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
9714a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
9724a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
9734a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
9741abe55efSEd Tanous                         {
9759391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
9764c9afe43SEd Tanous                             iface_list.emplace(iface_id.substr(last_pos + 1));
9779391bb9cSRapkiewicz, Pawel                         }
9789391bb9cSRapkiewicz, Pawel                     }
9799391bb9cSRapkiewicz, Pawel                 }
9809391bb9cSRapkiewicz, Pawel             }
981a434f2bdSEd Tanous             // Finally make a callback with useful data
9824a0cb85cSEd Tanous             callback(true, iface_list);
9839391bb9cSRapkiewicz, Pawel         },
984aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
985aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
9869391bb9cSRapkiewicz, Pawel };
9879391bb9cSRapkiewicz, Pawel 
9889391bb9cSRapkiewicz, Pawel /**
9899391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
9909391bb9cSRapkiewicz, Pawel  */
9911abe55efSEd Tanous class EthernetCollection : public Node
9921abe55efSEd Tanous {
9939391bb9cSRapkiewicz, Pawel   public:
9944a0cb85cSEd Tanous     template <typename CrowApp>
9951abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
9964a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
9971abe55efSEd Tanous     {
998588c3f0dSKowalski, Kamil         entityPrivileges = {
999588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1000e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1001e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1002e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1003e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1004e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
10059391bb9cSRapkiewicz, Pawel     }
10069391bb9cSRapkiewicz, Pawel 
10079391bb9cSRapkiewicz, Pawel   private:
10089391bb9cSRapkiewicz, Pawel     /**
10099391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
10109391bb9cSRapkiewicz, Pawel      */
101155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
10121abe55efSEd Tanous                const std::vector<std::string> &params) override
10131abe55efSEd Tanous     {
10140f74e643SEd Tanous         res.jsonValue["@odata.type"] =
10150f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
10160f74e643SEd Tanous         res.jsonValue["@odata.context"] =
10170f74e643SEd Tanous             "/redfish/v1/"
10180f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
10190f74e643SEd Tanous         res.jsonValue["@odata.id"] =
10200f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
10210f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
10220f74e643SEd Tanous         res.jsonValue["Description"] =
10230f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
10244c9afe43SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
10254a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
10261abe55efSEd Tanous         // preparation
1027f12894f8SJason M. Bills         getEthernetIfaceList(
10284c9afe43SEd Tanous             [asyncResp](
10294c9afe43SEd Tanous                 const bool &success,
10304c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
10314a0cb85cSEd Tanous                 if (!success)
10321abe55efSEd Tanous                 {
10334c9afe43SEd Tanous                     messages::internalError(asyncResp->res);
10344a0cb85cSEd Tanous                     return;
10354a0cb85cSEd Tanous                 }
10364a0cb85cSEd Tanous 
10374c9afe43SEd Tanous                 nlohmann::json &iface_array =
10384c9afe43SEd Tanous                     asyncResp->res.jsonValue["Members"];
10394a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
1040fda13ad2SSunitha Harish                 std::string tag = "_";
10414a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
10421abe55efSEd Tanous                 {
1043fda13ad2SSunitha Harish                     std::size_t found = iface_item.find(tag);
1044fda13ad2SSunitha Harish                     if (found == std::string::npos)
1045fda13ad2SSunitha Harish                     {
10464a0cb85cSEd Tanous                         iface_array.push_back(
10474a0cb85cSEd Tanous                             {{"@odata.id",
10484a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
10494a0cb85cSEd Tanous                                   iface_item}});
10509391bb9cSRapkiewicz, Pawel                     }
1051fda13ad2SSunitha Harish                 }
10524a0cb85cSEd Tanous 
10534c9afe43SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
10544c9afe43SEd Tanous                     iface_array.size();
10554c9afe43SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
10564a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
10579391bb9cSRapkiewicz, Pawel             });
10589391bb9cSRapkiewicz, Pawel     }
10599391bb9cSRapkiewicz, Pawel };
10609391bb9cSRapkiewicz, Pawel 
10619391bb9cSRapkiewicz, Pawel /**
10629391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
10639391bb9cSRapkiewicz, Pawel  */
10641abe55efSEd Tanous class EthernetInterface : public Node
10651abe55efSEd Tanous {
10669391bb9cSRapkiewicz, Pawel   public:
10679391bb9cSRapkiewicz, Pawel     /*
10689391bb9cSRapkiewicz, Pawel      * Default Constructor
10699391bb9cSRapkiewicz, Pawel      */
10704a0cb85cSEd Tanous     template <typename CrowApp>
10711abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
10724a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
10731abe55efSEd Tanous              std::string())
10741abe55efSEd Tanous     {
1075588c3f0dSKowalski, Kamil         entityPrivileges = {
1076588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1077e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
1078e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1079e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1080e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1081e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
10829391bb9cSRapkiewicz, Pawel     }
10839391bb9cSRapkiewicz, Pawel 
1084e439f0f8SKowalski, Kamil   private:
1085bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
10864a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
10871abe55efSEd Tanous     {
1088bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
1089bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
1090bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
10914a0cb85cSEd Tanous                 if (ec)
10924a0cb85cSEd Tanous                 {
1093a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
10941abe55efSEd Tanous                 }
1095bc0bd6e0SEd Tanous             },
1096bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
1097bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
1098bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
1099bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
1100abf2add6SEd Tanous             std::variant<std::string>(hostname));
1101588c3f0dSKowalski, Kamil     }
1102588c3f0dSKowalski, Kamil 
1103d577665bSRatan Gupta     void handleMACAddressPatch(const std::string &ifaceId,
1104d577665bSRatan Gupta                                const std::string &macAddress,
1105d577665bSRatan Gupta                                const std::shared_ptr<AsyncResp> &asyncResp)
1106d577665bSRatan Gupta     {
1107d577665bSRatan Gupta         crow::connections::systemBus->async_method_call(
1108d577665bSRatan Gupta             [asyncResp, macAddress](const boost::system::error_code ec) {
1109d577665bSRatan Gupta                 if (ec)
1110d577665bSRatan Gupta                 {
1111d577665bSRatan Gupta                     messages::internalError(asyncResp->res);
1112d577665bSRatan Gupta                     return;
1113d577665bSRatan Gupta                 }
1114d577665bSRatan Gupta                 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
1115d577665bSRatan Gupta             },
1116d577665bSRatan Gupta             "xyz.openbmc_project.Network",
1117d577665bSRatan Gupta             "/xyz/openbmc_project/network/" + ifaceId,
1118d577665bSRatan Gupta             "org.freedesktop.DBus.Properties", "Set",
1119d577665bSRatan Gupta             "xyz.openbmc_project.Network.MACAddress", "MACAddress",
1120d577665bSRatan Gupta             std::variant<std::string>(macAddress));
1121d577665bSRatan Gupta     }
1122da131a9aSJennifer Lee     void setDHCPEnabled(const std::string &ifaceId,
1123da131a9aSJennifer Lee                         const std::string &propertyName, const bool &value,
1124da131a9aSJennifer Lee                         const std::shared_ptr<AsyncResp> asyncResp)
1125da131a9aSJennifer Lee     {
1126da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1127da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1128da131a9aSJennifer Lee                 if (ec)
1129da131a9aSJennifer Lee                 {
1130da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1131da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1132da131a9aSJennifer Lee                     return;
1133da131a9aSJennifer Lee                 }
1134da131a9aSJennifer Lee             },
1135da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1136da131a9aSJennifer Lee             "/xyz/openbmc_project/network/" + ifaceId,
1137da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1138da131a9aSJennifer Lee             "xyz.openbmc_project.Network.EthernetInterface", propertyName,
1139da131a9aSJennifer Lee             std::variant<bool>{value});
1140da131a9aSJennifer Lee     }
1141da131a9aSJennifer Lee     void setDHCPv4Config(const std::string &propertyName, const bool &value,
1142da131a9aSJennifer Lee                          const std::shared_ptr<AsyncResp> asyncResp)
1143da131a9aSJennifer Lee     {
1144da131a9aSJennifer Lee         BMCWEB_LOG_DEBUG << propertyName << " = " << value;
1145da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
1146da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
1147da131a9aSJennifer Lee                 if (ec)
1148da131a9aSJennifer Lee                 {
1149da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1150da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
1151da131a9aSJennifer Lee                     return;
1152da131a9aSJennifer Lee                 }
1153da131a9aSJennifer Lee             },
1154da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
1155da131a9aSJennifer Lee             "/xyz/openbmc_project/network/config/dhcp",
1156da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
1157da131a9aSJennifer Lee             "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
1158da131a9aSJennifer Lee             std::variant<bool>{value});
1159da131a9aSJennifer Lee     }
1160d577665bSRatan Gupta 
1161da131a9aSJennifer Lee     void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
1162da131a9aSJennifer Lee                            const std::shared_ptr<AsyncResp> asyncResp)
1163da131a9aSJennifer Lee     {
1164da131a9aSJennifer Lee         std::optional<bool> dhcpEnabled;
1165da131a9aSJennifer Lee         std::optional<bool> useDNSServers;
1166da131a9aSJennifer Lee         std::optional<bool> useDomainName;
1167da131a9aSJennifer Lee         std::optional<bool> useNTPServers;
1168da131a9aSJennifer Lee 
1169da131a9aSJennifer Lee         if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1170da131a9aSJennifer Lee                                  dhcpEnabled, "UseDNSServers", useDNSServers,
1171da131a9aSJennifer Lee                                  "UseDomainName", useDomainName,
1172da131a9aSJennifer Lee                                  "UseNTPServers", useNTPServers))
1173da131a9aSJennifer Lee         {
1174da131a9aSJennifer Lee             return;
1175da131a9aSJennifer Lee         }
1176da131a9aSJennifer Lee 
1177da131a9aSJennifer Lee         if (dhcpEnabled)
1178da131a9aSJennifer Lee         {
1179da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1180da131a9aSJennifer Lee             setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1181da131a9aSJennifer Lee         }
1182da131a9aSJennifer Lee 
1183da131a9aSJennifer Lee         if (useDNSServers)
1184da131a9aSJennifer Lee         {
1185da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1186da131a9aSJennifer Lee             setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1187da131a9aSJennifer Lee         }
1188da131a9aSJennifer Lee 
1189da131a9aSJennifer Lee         if (useDomainName)
1190da131a9aSJennifer Lee         {
1191da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1192da131a9aSJennifer Lee             setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1193da131a9aSJennifer Lee         }
1194da131a9aSJennifer Lee 
1195da131a9aSJennifer Lee         if (useNTPServers)
1196da131a9aSJennifer Lee         {
1197da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1198da131a9aSJennifer Lee             setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1199da131a9aSJennifer Lee         }
1200da131a9aSJennifer Lee     }
12014a0cb85cSEd Tanous     void handleIPv4Patch(
1202f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
12034a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
12044a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
12051abe55efSEd Tanous     {
1206f476acbfSRatan Gupta         if (!input.is_array())
1207f476acbfSRatan Gupta         {
1208f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1209f476acbfSRatan Gupta                                              "IPv4Addresses");
1210f476acbfSRatan Gupta             return;
1211f476acbfSRatan Gupta         }
1212f476acbfSRatan Gupta 
12134a0cb85cSEd Tanous         int entryIdx = 0;
12144a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
12154a0cb85cSEd Tanous             ipv4Data.begin();
1216537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
12171abe55efSEd Tanous         {
12184a0cb85cSEd Tanous             std::string pathString =
1219a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
1220179db1d7SKowalski, Kamil 
1221f476acbfSRatan Gupta             if (thisJson.is_null())
1222f476acbfSRatan Gupta             {
1223f476acbfSRatan Gupta                 if (thisData != ipv4Data.end())
1224f476acbfSRatan Gupta                 {
1225f476acbfSRatan Gupta                     deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
1226f476acbfSRatan Gupta                     thisData++;
1227f476acbfSRatan Gupta                 }
1228f476acbfSRatan Gupta                 else
1229f476acbfSRatan Gupta                 {
1230f476acbfSRatan Gupta                     messages::propertyValueFormatError(
1231f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
1232f476acbfSRatan Gupta                     return;
1233f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
1234f476acbfSRatan Gupta                     // list and if unable to update one of the
1235f476acbfSRatan Gupta                     // list value then should we proceed further or
1236f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
1237f476acbfSRatan Gupta                     // till then we stop processing the next list item.
1238f476acbfSRatan Gupta                 }
1239f476acbfSRatan Gupta                 entryIdx++;
1240f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
1241f476acbfSRatan Gupta             }
1242f476acbfSRatan Gupta 
12439474b378SRatan Gupta             if (thisJson.empty())
12449474b378SRatan Gupta             {
12459474b378SRatan Gupta                 if (thisData != ipv4Data.end())
12469474b378SRatan Gupta                 {
12479474b378SRatan Gupta                     thisData++;
12489474b378SRatan Gupta                 }
12499474b378SRatan Gupta                 else
12509474b378SRatan Gupta                 {
12519474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
12529474b378SRatan Gupta                                               pathString + "/Address");
12539474b378SRatan Gupta                     return;
1254f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
12559474b378SRatan Gupta                     // list and if unable to update one of the
12569474b378SRatan Gupta                     // list value then should we proceed further or
12579474b378SRatan Gupta                     // break there, would ask in the redfish forum
12589474b378SRatan Gupta                     // till then we stop processing the next list item.
12599474b378SRatan Gupta                 }
12609474b378SRatan Gupta                 entryIdx++;
12619474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
12629474b378SRatan Gupta             }
12639474b378SRatan Gupta 
1264537174c4SEd Tanous             std::optional<std::string> address;
1265537174c4SEd Tanous             std::optional<std::string> addressOrigin;
1266537174c4SEd Tanous             std::optional<std::string> subnetMask;
1267537174c4SEd Tanous             std::optional<std::string> gateway;
1268537174c4SEd Tanous 
1269537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1270537174c4SEd Tanous                                      address, "AddressOrigin", addressOrigin,
1271537174c4SEd Tanous                                      "SubnetMask", subnetMask, "Gateway",
1272537174c4SEd Tanous                                      gateway))
1273537174c4SEd Tanous             {
1274537174c4SEd Tanous                 return;
1275179db1d7SKowalski, Kamil             }
1276179db1d7SKowalski, Kamil 
1277537174c4SEd Tanous             if (address)
12781abe55efSEd Tanous             {
1279537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
12801abe55efSEd Tanous                 {
1281537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
12824a0cb85cSEd Tanous                                                        pathString + "/Address");
1283537174c4SEd Tanous                     return;
12844a0cb85cSEd Tanous                 }
12854a0cb85cSEd Tanous             }
12864a0cb85cSEd Tanous 
1287537174c4SEd Tanous             uint8_t prefixLength = 0;
1288537174c4SEd Tanous             if (subnetMask)
12894a0cb85cSEd Tanous             {
1290537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
12914a0cb85cSEd Tanous                 {
1292f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1293537174c4SEd Tanous                         asyncResp->res, *subnetMask,
12944a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1295537174c4SEd Tanous                     return;
12964a0cb85cSEd Tanous                 }
12974a0cb85cSEd Tanous             }
12984a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
1299537174c4SEd Tanous             if (addressOrigin)
13004a0cb85cSEd Tanous             {
13014a0cb85cSEd Tanous                 // Get Address origin in proper format
13024a0cb85cSEd Tanous                 addressOriginInDBusFormat =
1303537174c4SEd Tanous                     translateAddressOriginRedfishToDbus(*addressOrigin);
13044a0cb85cSEd Tanous                 if (addressOriginInDBusFormat.empty())
13054a0cb85cSEd Tanous                 {
13064a0cb85cSEd Tanous                     messages::propertyValueNotInList(
1307537174c4SEd Tanous                         asyncResp->res, *addressOrigin,
1308a08b46ccSJason M. Bills                         pathString + "/AddressOrigin");
1309537174c4SEd Tanous                     return;
13104a0cb85cSEd Tanous                 }
13114a0cb85cSEd Tanous             }
13124a0cb85cSEd Tanous 
1313537174c4SEd Tanous             if (gateway)
13144a0cb85cSEd Tanous             {
1315537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
13164a0cb85cSEd Tanous                 {
1317537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1318537174c4SEd Tanous                                                        pathString + "/Gateway");
1319537174c4SEd Tanous                     return;
13204a0cb85cSEd Tanous                 }
13214a0cb85cSEd Tanous             }
13224a0cb85cSEd Tanous 
1323f476acbfSRatan Gupta             // if IP address exist then  modify it.
13244a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
13254a0cb85cSEd Tanous             {
1326179db1d7SKowalski, Kamil                 // Apply changes
1327537174c4SEd Tanous                 if (address)
13281abe55efSEd Tanous                 {
1329f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1330f476acbfSRatan Gupta                                      address{std::string(*address)}](
13314a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
13324a0cb85cSEd Tanous                         if (ec)
13331abe55efSEd Tanous                         {
1334a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
13354a0cb85cSEd Tanous                             return;
13364a0cb85cSEd Tanous                         }
1337f476acbfSRatan Gupta                         asyncResp->res
1338f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1339f476acbfSRatan Gupta                             std::move(address);
13404a0cb85cSEd Tanous                     };
13414a0cb85cSEd Tanous 
13424a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
13434a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1344f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1345f476acbfSRatan Gupta                             thisData->id,
13464a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
13474a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1348537174c4SEd Tanous                         std::variant<std::string>(*address));
1349179db1d7SKowalski, Kamil                 }
1350179db1d7SKowalski, Kamil 
1351537174c4SEd Tanous                 if (subnetMask)
13521abe55efSEd Tanous                 {
13534a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1354537174c4SEd Tanous                                                  thisData->id, *subnetMask,
1355537174c4SEd Tanous                                                  prefixLength, asyncResp);
1356179db1d7SKowalski, Kamil                 }
1357179db1d7SKowalski, Kamil 
1358537174c4SEd Tanous                 if (addressOrigin)
13591abe55efSEd Tanous                 {
13604a0cb85cSEd Tanous                     changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1361f476acbfSRatan Gupta                                      *addressOrigin, addressOriginInDBusFormat,
1362f476acbfSRatan Gupta                                      asyncResp);
1363179db1d7SKowalski, Kamil                 }
1364179db1d7SKowalski, Kamil 
1365537174c4SEd Tanous                 if (gateway)
13661abe55efSEd Tanous                 {
1367f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1368537174c4SEd Tanous                                      gateway{std::string(*gateway)}](
13694a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
13704a0cb85cSEd Tanous                         if (ec)
13711abe55efSEd Tanous                         {
1372a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
13734a0cb85cSEd Tanous                             return;
13744a0cb85cSEd Tanous                         }
1375f476acbfSRatan Gupta                         asyncResp->res
1376f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1377537174c4SEd Tanous                             std::move(gateway);
13784a0cb85cSEd Tanous                     };
13794a0cb85cSEd Tanous 
13804a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
13814a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1382f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1383f476acbfSRatan Gupta                             thisData->id,
13844a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
13854a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1386537174c4SEd Tanous                         std::variant<std::string>(*gateway));
13874a0cb85cSEd Tanous                 }
1388f476acbfSRatan Gupta 
13894a0cb85cSEd Tanous                 thisData++;
13901abe55efSEd Tanous             }
13911abe55efSEd Tanous             else
13921abe55efSEd Tanous             {
13934a0cb85cSEd Tanous                 // Create IPv4 with provided data
1394537174c4SEd Tanous                 if (!gateway)
13951abe55efSEd Tanous                 {
1396a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
13974a0cb85cSEd Tanous                                               pathString + "/Gateway");
13984a0cb85cSEd Tanous                     continue;
13994a0cb85cSEd Tanous                 }
14004a0cb85cSEd Tanous 
1401537174c4SEd Tanous                 if (!address)
14021abe55efSEd Tanous                 {
1403a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
14044a0cb85cSEd Tanous                                               pathString + "/Address");
14054a0cb85cSEd Tanous                     continue;
14064a0cb85cSEd Tanous                 }
14074a0cb85cSEd Tanous 
1408537174c4SEd Tanous                 if (!subnetMask)
14091abe55efSEd Tanous                 {
1410a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
14114a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
14124a0cb85cSEd Tanous                     continue;
1413588c3f0dSKowalski, Kamil                 }
1414588c3f0dSKowalski, Kamil 
1415b01bf299SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1416b01bf299SEd Tanous                            asyncResp);
141795897b20SRatan Gupta 
141895897b20SRatan Gupta                 nlohmann::json &ipv4AddressJson =
141995897b20SRatan Gupta                     asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
142095897b20SRatan Gupta                 ipv4AddressJson["Address"] = *address;
142195897b20SRatan Gupta                 ipv4AddressJson["SubnetMask"] = *subnetMask;
142295897b20SRatan Gupta                 ipv4AddressJson["Gateway"] = *gateway;
14234a0cb85cSEd Tanous             }
14244a0cb85cSEd Tanous             entryIdx++;
14254a0cb85cSEd Tanous         }
14264a0cb85cSEd Tanous     }
14274a0cb85cSEd Tanous 
1428f85837bfSRAJESWARAN THILLAIGOVINDAN     void handleStaticNameServersPatch(
1429f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::string &ifaceId,
1430f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::vector<std::string> &updatedStaticNameServers,
1431f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::shared_ptr<AsyncResp> &asyncResp)
1432f85837bfSRAJESWARAN THILLAIGOVINDAN     {
1433f85837bfSRAJESWARAN THILLAIGOVINDAN         crow::connections::systemBus->async_method_call(
1434f85837bfSRAJESWARAN THILLAIGOVINDAN             [asyncResp,
1435f85837bfSRAJESWARAN THILLAIGOVINDAN              updatedStaticNameServers](const boost::system::error_code ec) {
1436f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (ec)
1437f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1438f85837bfSRAJESWARAN THILLAIGOVINDAN                     messages::internalError(asyncResp->res);
1439f85837bfSRAJESWARAN THILLAIGOVINDAN                     return;
1440f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1441f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["NameServers"] =
1442f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1443f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["StaticNameServers"] =
1444f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1445f85837bfSRAJESWARAN THILLAIGOVINDAN             },
1446f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network",
1447f85837bfSRAJESWARAN THILLAIGOVINDAN             "/xyz/openbmc_project/network/" + ifaceId,
1448f85837bfSRAJESWARAN THILLAIGOVINDAN             "org.freedesktop.DBus.Properties", "Set",
1449f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1450f85837bfSRAJESWARAN THILLAIGOVINDAN             std::variant<std::vector<std::string>>{updatedStaticNameServers});
1451f85837bfSRAJESWARAN THILLAIGOVINDAN     }
1452f85837bfSRAJESWARAN THILLAIGOVINDAN 
1453e48c0fc5SRavi Teja     void handleIPv6StaticAddressesPatch(
1454e48c0fc5SRavi Teja         const std::string &ifaceId, nlohmann::json &input,
1455e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData,
1456e48c0fc5SRavi Teja         const std::shared_ptr<AsyncResp> asyncResp)
1457e48c0fc5SRavi Teja     {
1458e48c0fc5SRavi Teja         if (!input.is_array())
1459e48c0fc5SRavi Teja         {
1460e48c0fc5SRavi Teja             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1461e48c0fc5SRavi Teja                                              "IPv6StaticAddresses");
1462e48c0fc5SRavi Teja             return;
1463e48c0fc5SRavi Teja         }
1464e48c0fc5SRavi Teja 
1465e48c0fc5SRavi Teja         int entryIdx = 0;
1466e48c0fc5SRavi Teja         boost::container::flat_set<IPv6AddressData>::const_iterator thisData =
1467e48c0fc5SRavi Teja             ipv6StaticData.begin();
1468e48c0fc5SRavi Teja         for (nlohmann::json &thisJson : input)
1469e48c0fc5SRavi Teja         {
1470e48c0fc5SRavi Teja             std::string pathString =
1471e48c0fc5SRavi Teja                 "IPv6StaticAddresses/" + std::to_string(entryIdx);
1472e48c0fc5SRavi Teja 
1473e48c0fc5SRavi Teja             if (thisJson.is_null())
1474e48c0fc5SRavi Teja             {
1475e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1476e48c0fc5SRavi Teja                 {
1477e48c0fc5SRavi Teja                     deleteIPv6(ifaceId, thisData->id, entryIdx, asyncResp);
1478e48c0fc5SRavi Teja                     thisData++;
1479e48c0fc5SRavi Teja                 }
1480e48c0fc5SRavi Teja                 else
1481e48c0fc5SRavi Teja                 {
1482e48c0fc5SRavi Teja                     messages::propertyValueFormatError(
1483e48c0fc5SRavi Teja                         asyncResp->res, input.dump(), pathString);
1484e48c0fc5SRavi Teja                     return;
1485e48c0fc5SRavi Teja                 }
1486e48c0fc5SRavi Teja                 entryIdx++;
1487e48c0fc5SRavi Teja                 continue;
1488e48c0fc5SRavi Teja             }
1489e48c0fc5SRavi Teja 
1490e48c0fc5SRavi Teja             if (thisJson.empty())
1491e48c0fc5SRavi Teja             {
1492e48c0fc5SRavi Teja                 if (thisData != ipv6StaticData.end())
1493e48c0fc5SRavi Teja                 {
1494e48c0fc5SRavi Teja                     thisData++;
1495e48c0fc5SRavi Teja                 }
1496e48c0fc5SRavi Teja                 else
1497e48c0fc5SRavi Teja                 {
1498e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1499e48c0fc5SRavi Teja                                               pathString + "/Address");
1500e48c0fc5SRavi Teja                     return;
1501e48c0fc5SRavi Teja                 }
1502e48c0fc5SRavi Teja                 entryIdx++;
1503e48c0fc5SRavi Teja                 continue;
1504e48c0fc5SRavi Teja             }
1505e48c0fc5SRavi Teja 
1506e48c0fc5SRavi Teja             std::optional<std::string> address;
1507e48c0fc5SRavi Teja             std::optional<uint8_t> prefixLength;
1508e48c0fc5SRavi Teja 
1509e48c0fc5SRavi Teja             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1510e48c0fc5SRavi Teja                                      address, "PrefixLength", prefixLength))
1511e48c0fc5SRavi Teja             {
1512e48c0fc5SRavi Teja                 return;
1513e48c0fc5SRavi Teja             }
1514e48c0fc5SRavi Teja 
1515e48c0fc5SRavi Teja             // if IP address exist then  modify it.
1516e48c0fc5SRavi Teja             if (thisData != ipv6StaticData.end())
1517e48c0fc5SRavi Teja             {
1518e48c0fc5SRavi Teja                 // Apply changes
1519e48c0fc5SRavi Teja                 if (address)
1520e48c0fc5SRavi Teja                 {
1521e48c0fc5SRavi Teja                     auto callback = [asyncResp, entryIdx,
1522e48c0fc5SRavi Teja                                      address{std::string(*address)}](
1523e48c0fc5SRavi Teja                                         const boost::system::error_code ec) {
1524e48c0fc5SRavi Teja                         if (ec)
1525e48c0fc5SRavi Teja                         {
1526e48c0fc5SRavi Teja                             messages::internalError(asyncResp->res);
1527e48c0fc5SRavi Teja                             return;
1528e48c0fc5SRavi Teja                         }
1529e48c0fc5SRavi Teja                         asyncResp->res.jsonValue["IPv6StaticAddresses"]
1530e48c0fc5SRavi Teja                                                 [entryIdx]["Address"] =
1531e48c0fc5SRavi Teja                             std::move(address);
1532e48c0fc5SRavi Teja                     };
1533e48c0fc5SRavi Teja 
1534e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1535e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1536e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1537e48c0fc5SRavi Teja                             thisData->id,
1538e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1539e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "Address",
1540e48c0fc5SRavi Teja                         std::variant<std::string>(*address));
1541e48c0fc5SRavi Teja                 }
1542e48c0fc5SRavi Teja 
1543e48c0fc5SRavi Teja                 if (prefixLength)
1544e48c0fc5SRavi Teja                 {
1545e48c0fc5SRavi Teja                     auto callback = [asyncResp, entryIdx,
1546e48c0fc5SRavi Teja                                      prefixLength{uint8_t(*prefixLength)}](
1547e48c0fc5SRavi Teja                                         const boost::system::error_code ec) {
1548e48c0fc5SRavi Teja                         if (ec)
1549e48c0fc5SRavi Teja                         {
1550e48c0fc5SRavi Teja                             messages::internalError(asyncResp->res);
1551e48c0fc5SRavi Teja                             return;
1552e48c0fc5SRavi Teja                         }
1553e48c0fc5SRavi Teja                         asyncResp->res.jsonValue["IPv6StaticAddresses"]
1554e48c0fc5SRavi Teja                                                 [entryIdx]["PrefixLength"] =
1555e48c0fc5SRavi Teja                             std::move(prefixLength);
1556e48c0fc5SRavi Teja                     };
1557e48c0fc5SRavi Teja 
1558e48c0fc5SRavi Teja                     crow::connections::systemBus->async_method_call(
1559e48c0fc5SRavi Teja                         std::move(callback), "xyz.openbmc_project.Network",
1560e48c0fc5SRavi Teja                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv6/" +
1561e48c0fc5SRavi Teja                             thisData->id,
1562e48c0fc5SRavi Teja                         "org.freedesktop.DBus.Properties", "Set",
1563e48c0fc5SRavi Teja                         "xyz.openbmc_project.Network.IP", "PrefixLength",
1564e48c0fc5SRavi Teja                         std::variant<uint8_t>(*prefixLength));
1565e48c0fc5SRavi Teja                 }
1566e48c0fc5SRavi Teja 
1567e48c0fc5SRavi Teja                 thisData++;
1568e48c0fc5SRavi Teja             }
1569e48c0fc5SRavi Teja             else
1570e48c0fc5SRavi Teja             {
1571e48c0fc5SRavi Teja                 // Create IPv6 with provided data
1572e48c0fc5SRavi Teja 
1573e48c0fc5SRavi Teja                 if (!prefixLength)
1574e48c0fc5SRavi Teja                 {
1575e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1576e48c0fc5SRavi Teja                                               pathString + "/PrefixLength");
1577e48c0fc5SRavi Teja                     continue;
1578e48c0fc5SRavi Teja                 }
1579e48c0fc5SRavi Teja 
1580e48c0fc5SRavi Teja                 if (!address)
1581e48c0fc5SRavi Teja                 {
1582e48c0fc5SRavi Teja                     messages::propertyMissing(asyncResp->res,
1583e48c0fc5SRavi Teja                                               pathString + "/Address");
1584e48c0fc5SRavi Teja                     continue;
1585e48c0fc5SRavi Teja                 }
1586e48c0fc5SRavi Teja 
1587e48c0fc5SRavi Teja                 createIPv6(ifaceId, entryIdx, *prefixLength, *address,
1588e48c0fc5SRavi Teja                            asyncResp);
1589e48c0fc5SRavi Teja 
1590e48c0fc5SRavi Teja                 nlohmann::json &ipv6StaticAddressJson =
1591e48c0fc5SRavi Teja                     asyncResp->res.jsonValue["IPv6StaticAddresses"][entryIdx];
1592e48c0fc5SRavi Teja                 ipv6StaticAddressJson["Address"] = *address;
1593e48c0fc5SRavi Teja                 ipv6StaticAddressJson["PrefixLength"] = *prefixLength;
1594e48c0fc5SRavi Teja             }
1595e48c0fc5SRavi Teja             entryIdx++;
1596e48c0fc5SRavi Teja         }
1597e48c0fc5SRavi Teja     }
1598e48c0fc5SRavi Teja 
15990f74e643SEd Tanous     void parseInterfaceData(
16000f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
16010f74e643SEd Tanous         const EthernetInterfaceData &ethData,
1602e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1603e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1604e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
16054a0cb85cSEd Tanous     {
16064a0cb85cSEd Tanous         json_response["Id"] = iface_id;
16074a0cb85cSEd Tanous         json_response["@odata.id"] =
16084a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1609029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1610029573d4SEd Tanous         if (ethData.speed == 0)
1611029573d4SEd Tanous         {
1612029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1613029573d4SEd Tanous             json_response["Status"] = {
1614029573d4SEd Tanous                 {"Health", "OK"},
1615029573d4SEd Tanous                 {"State", "Disabled"},
1616029573d4SEd Tanous             };
1617029573d4SEd Tanous         }
1618029573d4SEd Tanous         else
1619029573d4SEd Tanous         {
1620029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1621029573d4SEd Tanous             json_response["Status"] = {
1622029573d4SEd Tanous                 {"Health", "OK"},
1623029573d4SEd Tanous                 {"State", "Enabled"},
1624029573d4SEd Tanous             };
1625029573d4SEd Tanous         }
16264a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
16274a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1628fda13ad2SSunitha Harish         json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
16292a133282Smanojkiraneda 
16304a0cb85cSEd Tanous         if (!ethData.hostname.empty())
16314a0cb85cSEd Tanous         {
16324a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
16334a0cb85cSEd Tanous         }
16344a0cb85cSEd Tanous 
1635fda13ad2SSunitha Harish         json_response["VLANs"] = {
1636fda13ad2SSunitha Harish             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1637fda13ad2SSunitha Harish                               iface_id + "/VLANs"}};
1638fda13ad2SSunitha Harish 
1639029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
1640f85837bfSRAJESWARAN THILLAIGOVINDAN         json_response["StaticNameServers"] = ethData.nameservers;
16414a0cb85cSEd Tanous 
16424a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
16434a0cb85cSEd Tanous         {
16444a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
16454a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
16464a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
16474a0cb85cSEd Tanous             {
1648fa5053a6SGunnar Mills 
1649fa5053a6SGunnar Mills                 std::string gatewayStr = ipv4_config.gateway;
1650fa5053a6SGunnar Mills                 if (gatewayStr.empty())
1651fa5053a6SGunnar Mills                 {
1652fa5053a6SGunnar Mills                     gatewayStr = "0.0.0.0";
1653fa5053a6SGunnar Mills                 }
1654fa5053a6SGunnar Mills 
16554a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
16564a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1657029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1658fa5053a6SGunnar Mills                                       {"Gateway", gatewayStr}});
16594a0cb85cSEd Tanous             }
16604a0cb85cSEd Tanous         }
16619a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1662e48c0fc5SRavi Teja 
1663e48c0fc5SRavi Teja         nlohmann::json &ipv6_array = json_response["IPv6Addresses"];
1664e48c0fc5SRavi Teja         ipv6_array = nlohmann::json::array();
1665e48c0fc5SRavi Teja         for (auto &ipv6_config : ipv6Data)
1666e48c0fc5SRavi Teja         {
1667e48c0fc5SRavi Teja             ipv6_array.push_back({{"Address", ipv6_config.address},
1668e48c0fc5SRavi Teja                                   {"PrefixLength", ipv6_config.prefixLength},
1669e48c0fc5SRavi Teja                                   {"AddressOrigin", ipv6_config.origin}});
1670e48c0fc5SRavi Teja         }
1671e48c0fc5SRavi Teja 
1672e48c0fc5SRavi Teja         nlohmann::json &ipv6_static_array =
1673e48c0fc5SRavi Teja             json_response["IPv6StaticAddresses"];
1674e48c0fc5SRavi Teja         ipv6_static_array = nlohmann::json::array();
1675e48c0fc5SRavi Teja         for (auto &ipv6_static_config : ipv6StaticData)
1676e48c0fc5SRavi Teja         {
1677e48c0fc5SRavi Teja             ipv6_static_array.push_back(
1678e48c0fc5SRavi Teja                 {{"Address", ipv6_static_config.address},
1679e48c0fc5SRavi Teja                  {"PrefixLength", ipv6_static_config.prefixLength}});
1680e48c0fc5SRavi Teja         }
1681588c3f0dSKowalski, Kamil     }
1682588c3f0dSKowalski, Kamil 
16839391bb9cSRapkiewicz, Pawel     /**
16849391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
16859391bb9cSRapkiewicz, Pawel      */
168655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
16871abe55efSEd Tanous                const std::vector<std::string> &params) override
16881abe55efSEd Tanous     {
16894a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16901abe55efSEd Tanous         if (params.size() != 1)
16911abe55efSEd Tanous         {
1692f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
16939391bb9cSRapkiewicz, Pawel             return;
16949391bb9cSRapkiewicz, Pawel         }
16959391bb9cSRapkiewicz, Pawel 
16964a0cb85cSEd Tanous         getEthernetIfaceData(
16974a0cb85cSEd Tanous             params[0],
16984a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
16994a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1700e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1701e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1702e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1703e48c0fc5SRavi Teja                     &ipv6StaticData) {
17044a0cb85cSEd Tanous                 if (!success)
17051abe55efSEd Tanous                 {
17061abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
17071abe55efSEd Tanous                     // object, and other errors
1708f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1709f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
17104a0cb85cSEd Tanous                     return;
17119391bb9cSRapkiewicz, Pawel                 }
17124c9afe43SEd Tanous 
17134c9afe43SEd Tanous                 // because this has no dependence on the interface at this
17144c9afe43SEd Tanous                 // point, it needs to be done after we know the interface
17154c9afe43SEd Tanous                 // exists, not before.
17164c9afe43SEd Tanous                 getDHCPConfigData(asyncResp);
17174c9afe43SEd Tanous 
17180f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1719fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
17200f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
17210f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
17220f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
17230f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
17240f74e643SEd Tanous                     "Management Network Interface";
17250f74e643SEd Tanous 
17260f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1727e48c0fc5SRavi Teja                                    ipv4Data, ipv6Data, ipv6StaticData);
17289391bb9cSRapkiewicz, Pawel             });
17299391bb9cSRapkiewicz, Pawel     }
17309391bb9cSRapkiewicz, Pawel 
173155c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
17321abe55efSEd Tanous                  const std::vector<std::string> &params) override
17331abe55efSEd Tanous     {
17344a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17351abe55efSEd Tanous         if (params.size() != 1)
17361abe55efSEd Tanous         {
1737f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1738588c3f0dSKowalski, Kamil             return;
1739588c3f0dSKowalski, Kamil         }
1740588c3f0dSKowalski, Kamil 
17414a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1742588c3f0dSKowalski, Kamil 
1743bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1744d577665bSRatan Gupta         std::optional<std::string> macAddress;
17459a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1746f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1747f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1748e48c0fc5SRavi Teja         std::optional<nlohmann::json> ipv6StaticAddresses;
1749f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
17505112e9b4SRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> nameServers;
1751da131a9aSJennifer Lee         std::optional<nlohmann::json> dhcpv4;
17520627a2c7SEd Tanous 
1753fda13ad2SSunitha Harish         if (!json_util::readJson(
1754fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
17556ca6ac12SJohnathan Mantey                 "MACAddress", macAddress, "StaticNameServers",
17566ca6ac12SJohnathan Mantey                 staticNameServers, "IPv6DefaultGateway", ipv6DefaultGateway,
17576ca6ac12SJohnathan Mantey                 "IPv6StaticAddresses", ipv6StaticAddresses, "NameServers",
17586ca6ac12SJohnathan Mantey                 nameServers, "DHCPv4", dhcpv4))
17591abe55efSEd Tanous         {
1760588c3f0dSKowalski, Kamil             return;
1761588c3f0dSKowalski, Kamil         }
1762f15aad37SRatan Gupta 
1763da131a9aSJennifer Lee         if (dhcpv4)
1764da131a9aSJennifer Lee         {
1765da131a9aSJennifer Lee             handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1766da131a9aSJennifer Lee         }
1767da131a9aSJennifer Lee 
17684a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1769588c3f0dSKowalski, Kamil         // preparation
17704a0cb85cSEd Tanous         getEthernetIfaceData(
17714a0cb85cSEd Tanous             iface_id,
1772fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1773fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
17740627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
17759a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1776e48c0fc5SRavi Teja              ipv6StaticAddresses = std::move(ipv6StaticAddresses),
17775112e9b4SRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers),
17785112e9b4SRAJESWARAN THILLAIGOVINDAN              nameServers = std::move(nameServers)](
17794a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1780e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1781e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1782e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1783e48c0fc5SRavi Teja                     &ipv6StaticData) {
17841abe55efSEd Tanous                 if (!success)
17851abe55efSEd Tanous                 {
1786588c3f0dSKowalski, Kamil                     // ... otherwise return error
17871abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
17881abe55efSEd Tanous                     // object, and other errors
1789fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1790fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1791588c3f0dSKowalski, Kamil                     return;
1792588c3f0dSKowalski, Kamil                 }
1793588c3f0dSKowalski, Kamil 
17940f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
1795e48c0fc5SRavi Teja                                    ipv4Data, ipv6Data, ipv6StaticData);
1796588c3f0dSKowalski, Kamil 
17970627a2c7SEd Tanous                 if (hostname)
17981abe55efSEd Tanous                 {
17990627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
18001abe55efSEd Tanous                 }
18010627a2c7SEd Tanous 
1802d577665bSRatan Gupta                 if (macAddress)
1803d577665bSRatan Gupta                 {
1804d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1805d577665bSRatan Gupta                 }
1806d577665bSRatan Gupta 
18070627a2c7SEd Tanous                 if (ipv4Addresses)
18081abe55efSEd Tanous                 {
1809537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1810537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1811537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1812537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1813537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1814537174c4SEd Tanous                     // on that, but could be done more efficiently
1815f476acbfSRatan Gupta                     nlohmann::json ipv4 = std::move(*ipv4Addresses);
1816537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
18171abe55efSEd Tanous                 }
18180627a2c7SEd Tanous 
18195112e9b4SRAJESWARAN THILLAIGOVINDAN                 if (nameServers)
18205112e9b4SRAJESWARAN THILLAIGOVINDAN                 {
18215112e9b4SRAJESWARAN THILLAIGOVINDAN                     // Data.Permissions is read-only
18225112e9b4SRAJESWARAN THILLAIGOVINDAN                     messages::propertyNotWritable(asyncResp->res,
18235112e9b4SRAJESWARAN THILLAIGOVINDAN                                                   "NameServers");
18245112e9b4SRAJESWARAN THILLAIGOVINDAN                 }
18255112e9b4SRAJESWARAN THILLAIGOVINDAN 
1826f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1827f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1828f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1829f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1830f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
18319a6fc6feSRavi Teja 
18329a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
18339a6fc6feSRavi Teja                 {
18349a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
18359a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
18369a6fc6feSRavi Teja                 }
1837e48c0fc5SRavi Teja 
1838e48c0fc5SRavi Teja                 if (ipv6StaticAddresses)
1839e48c0fc5SRavi Teja                 {
1840e48c0fc5SRavi Teja                     nlohmann::json ipv6Static = std::move(*ipv6StaticAddresses);
1841e48c0fc5SRavi Teja                     handleIPv6StaticAddressesPatch(iface_id, ipv6Static,
1842e48c0fc5SRavi Teja                                                    ipv6StaticData, asyncResp);
1843e48c0fc5SRavi Teja 
1844e48c0fc5SRavi Teja                     // call getEthernetIfaceData to populate updated static
1845e48c0fc5SRavi Teja                     // addresses data to "IPv6Addresses" json collection
1846e48c0fc5SRavi Teja                     getEthernetIfaceData(
1847e48c0fc5SRavi Teja                         iface_id,
1848e48c0fc5SRavi Teja                         [this, asyncResp, iface_id](
1849e48c0fc5SRavi Teja                             const bool &success,
1850e48c0fc5SRavi Teja                             const EthernetInterfaceData &ethData,
1851e48c0fc5SRavi Teja                             const boost::container::flat_set<IPv4AddressData>
1852e48c0fc5SRavi Teja                                 &ipv4Data,
1853e48c0fc5SRavi Teja                             const boost::container::flat_set<IPv6AddressData>
1854e48c0fc5SRavi Teja                                 &ipv6Data,
1855e48c0fc5SRavi Teja                             const boost::container::flat_set<IPv6AddressData>
1856e48c0fc5SRavi Teja                                 &ipv6StaticData) {
1857e48c0fc5SRavi Teja                             if (!success)
1858e48c0fc5SRavi Teja                             {
1859e48c0fc5SRavi Teja                                 messages::resourceNotFound(asyncResp->res,
1860e48c0fc5SRavi Teja                                                            "Ethernet Interface",
1861e48c0fc5SRavi Teja                                                            iface_id);
1862e48c0fc5SRavi Teja                                 return;
1863e48c0fc5SRavi Teja                             }
1864e48c0fc5SRavi Teja 
1865e48c0fc5SRavi Teja                             parseInterfaceData(asyncResp->res.jsonValue,
1866e48c0fc5SRavi Teja                                                iface_id, ethData, ipv4Data,
1867e48c0fc5SRavi Teja                                                ipv6Data, ipv6StaticData);
1868e48c0fc5SRavi Teja                         });
1869e48c0fc5SRavi Teja                 }
1870588c3f0dSKowalski, Kamil             });
1871588c3f0dSKowalski, Kamil     }
18729391bb9cSRapkiewicz, Pawel };
18739391bb9cSRapkiewicz, Pawel 
1874e439f0f8SKowalski, Kamil /**
18754a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
18764a0cb85cSEd Tanous  * Schema
1877e439f0f8SKowalski, Kamil  */
18781abe55efSEd Tanous class VlanNetworkInterface : public Node
18791abe55efSEd Tanous {
1880e439f0f8SKowalski, Kamil   public:
1881e439f0f8SKowalski, Kamil     /*
1882e439f0f8SKowalski, Kamil      * Default Constructor
1883e439f0f8SKowalski, Kamil      */
1884e439f0f8SKowalski, Kamil     template <typename CrowApp>
18851abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
18864a0cb85cSEd Tanous         Node(app,
18870f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
18881abe55efSEd Tanous              std::string(), std::string())
18891abe55efSEd Tanous     {
1890e439f0f8SKowalski, Kamil         entityPrivileges = {
1891e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1892e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1893e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1894e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1895e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1896e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1897e439f0f8SKowalski, Kamil     }
1898e439f0f8SKowalski, Kamil 
1899e439f0f8SKowalski, Kamil   private:
19000f74e643SEd Tanous     void parseInterfaceData(
19010f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
19020f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
1903e48c0fc5SRavi Teja         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1904e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1905e48c0fc5SRavi Teja         const boost::container::flat_set<IPv6AddressData> &ipv6StaticData)
19061abe55efSEd Tanous     {
1907e439f0f8SKowalski, Kamil         // Fill out obvious data...
19084a0cb85cSEd Tanous         json_response["Id"] = iface_id;
19094a0cb85cSEd Tanous         json_response["@odata.id"] =
19104a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
19114a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1912e439f0f8SKowalski, Kamil 
19134a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1914fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
19154a0cb85cSEd Tanous         {
1916fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
19174a0cb85cSEd Tanous         }
1918e439f0f8SKowalski, Kamil     }
1919e439f0f8SKowalski, Kamil 
1920fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
19211abe55efSEd Tanous     {
19221abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
19231abe55efSEd Tanous         {
1924927a505aSKowalski, Kamil             return false;
19251abe55efSEd Tanous         }
19261abe55efSEd Tanous         else
19271abe55efSEd Tanous         {
1928927a505aSKowalski, Kamil             return true;
1929927a505aSKowalski, Kamil         }
1930927a505aSKowalski, Kamil     }
1931927a505aSKowalski, Kamil 
1932e439f0f8SKowalski, Kamil     /**
1933e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1934e439f0f8SKowalski, Kamil      */
193555c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
19361abe55efSEd Tanous                const std::vector<std::string> &params) override
19371abe55efSEd Tanous     {
19384a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19394a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1940e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1941e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1942e439f0f8SKowalski, Kamil         // impossible.
19431abe55efSEd Tanous         if (params.size() != 2)
19441abe55efSEd Tanous         {
1945f12894f8SJason M. Bills             messages::internalError(res);
1946e439f0f8SKowalski, Kamil             res.end();
1947e439f0f8SKowalski, Kamil             return;
1948e439f0f8SKowalski, Kamil         }
1949e439f0f8SKowalski, Kamil 
19504a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
19514a0cb85cSEd Tanous         const std::string &iface_id = params[1];
19520f74e643SEd Tanous         res.jsonValue["@odata.type"] =
19530f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
19540f74e643SEd Tanous         res.jsonValue["@odata.context"] =
19550f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
19560f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1957e439f0f8SKowalski, Kamil 
1958fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
19591abe55efSEd Tanous         {
1960a434f2bdSEd Tanous             return;
1961a434f2bdSEd Tanous         }
1962a434f2bdSEd Tanous 
1963e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1964e439f0f8SKowalski, Kamil         // preparation
19654a0cb85cSEd Tanous         getEthernetIfaceData(
1966fda13ad2SSunitha Harish             params[1],
1967fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1968fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
19694a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
1970e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
1971e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
1972e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
1973e48c0fc5SRavi Teja                     &ipv6StaticData) {
1974fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
19751abe55efSEd Tanous                 {
19760f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
19770f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
1978e48c0fc5SRavi Teja                                        ipv4Data, ipv6Data, ipv6StaticData);
19791abe55efSEd Tanous                 }
19801abe55efSEd Tanous                 else
19811abe55efSEd Tanous                 {
1982e439f0f8SKowalski, Kamil                     // ... otherwise return error
19831abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
19841abe55efSEd Tanous                     // object, and other errors
1985f12894f8SJason M. Bills                     messages::resourceNotFound(
1986f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1987e439f0f8SKowalski, Kamil                 }
1988e439f0f8SKowalski, Kamil             });
1989e439f0f8SKowalski, Kamil     }
1990e439f0f8SKowalski, Kamil 
199155c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
19921abe55efSEd Tanous                  const std::vector<std::string> &params) override
19931abe55efSEd Tanous     {
19944a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
19951abe55efSEd Tanous         if (params.size() != 2)
19961abe55efSEd Tanous         {
1997f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1998e439f0f8SKowalski, Kamil             return;
1999e439f0f8SKowalski, Kamil         }
2000e439f0f8SKowalski, Kamil 
2001d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
200255c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
2003927a505aSKowalski, Kamil 
2004fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
20051abe55efSEd Tanous         {
2006fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2007fda13ad2SSunitha Harish                                        ifaceId);
2008927a505aSKowalski, Kamil             return;
2009927a505aSKowalski, Kamil         }
2010927a505aSKowalski, Kamil 
20110627a2c7SEd Tanous         bool vlanEnable = false;
20120627a2c7SEd Tanous         uint64_t vlanId = 0;
20130627a2c7SEd Tanous 
20140627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
20150627a2c7SEd Tanous                                  vlanId))
20161abe55efSEd Tanous         {
2017927a505aSKowalski, Kamil             return;
2018927a505aSKowalski, Kamil         }
2019927a505aSKowalski, Kamil 
2020927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
2021927a505aSKowalski, Kamil         // preparation
2022e48c0fc5SRavi Teja         getEthernetIfaceData(
2023e48c0fc5SRavi Teja             params[1],
2024e48c0fc5SRavi Teja             [this, asyncResp, parentIfaceId{std::string(params[0])},
2025e48c0fc5SRavi Teja              ifaceId{std::string(params[1])}, &vlanEnable, &vlanId](
2026e48c0fc5SRavi Teja                 const bool &success, const EthernetInterfaceData &ethData,
2027e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2028e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2029e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
2030e48c0fc5SRavi Teja                     &ipv6StaticData) {
203108244d02SSunitha Harish                 if (success && !ethData.vlan_id.empty())
203208244d02SSunitha Harish                 {
203308244d02SSunitha Harish                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
2034e48c0fc5SRavi Teja                                        ifaceId, ethData, ipv4Data, ipv6Data,
2035e48c0fc5SRavi Teja                                        ipv6StaticData);
203608244d02SSunitha Harish                     auto callback =
203708244d02SSunitha Harish                         [asyncResp](const boost::system::error_code ec) {
203808244d02SSunitha Harish                             if (ec)
203908244d02SSunitha Harish                             {
204008244d02SSunitha Harish                                 messages::internalError(asyncResp->res);
204108244d02SSunitha Harish                             }
204208244d02SSunitha Harish                         };
204308244d02SSunitha Harish 
204408244d02SSunitha Harish                     if (vlanEnable == true)
204508244d02SSunitha Harish                     {
204608244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
204708244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
204808244d02SSunitha Harish                             "/xyz/openbmc_project/network/" + ifaceId,
204908244d02SSunitha Harish                             "org.freedesktop.DBus.Properties", "Set",
205008244d02SSunitha Harish                             "xyz.openbmc_project.Network.VLAN", "Id",
205108244d02SSunitha Harish                             std::variant<uint32_t>(vlanId));
205208244d02SSunitha Harish                     }
205308244d02SSunitha Harish                     else
205408244d02SSunitha Harish                     {
2055e48c0fc5SRavi Teja                         BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the "
2056e48c0fc5SRavi Teja                                             "vlan interface";
205708244d02SSunitha Harish                         crow::connections::systemBus->async_method_call(
205808244d02SSunitha Harish                             std::move(callback), "xyz.openbmc_project.Network",
2059e48c0fc5SRavi Teja                             std::string("/xyz/openbmc_project/network/") +
2060e48c0fc5SRavi Teja                                 ifaceId,
206108244d02SSunitha Harish                             "xyz.openbmc_project.Object.Delete", "Delete");
206208244d02SSunitha Harish                     }
206308244d02SSunitha Harish                 }
206408244d02SSunitha Harish                 else
20651abe55efSEd Tanous                 {
20661abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
20671abe55efSEd Tanous                     // object, and other errors
2068e48c0fc5SRavi Teja                     messages::resourceNotFound(
2069e48c0fc5SRavi Teja                         asyncResp->res, "VLAN Network Interface", ifaceId);
2070927a505aSKowalski, Kamil                     return;
2071927a505aSKowalski, Kamil                 }
2072927a505aSKowalski, Kamil             });
2073e439f0f8SKowalski, Kamil     }
2074e439f0f8SKowalski, Kamil 
207555c7b7a2SEd Tanous     void doDelete(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() != 2)
20801abe55efSEd Tanous         {
2081f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2082e439f0f8SKowalski, Kamil             return;
2083e439f0f8SKowalski, Kamil         }
2084e439f0f8SKowalski, Kamil 
2085d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
208655c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
2087927a505aSKowalski, Kamil 
2088fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
20891abe55efSEd Tanous         {
2090fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
2091fda13ad2SSunitha Harish                                        ifaceId);
2092927a505aSKowalski, Kamil             return;
2093927a505aSKowalski, Kamil         }
2094927a505aSKowalski, Kamil 
2095927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
2096927a505aSKowalski, Kamil         // preparation
2097f12894f8SJason M. Bills         getEthernetIfaceData(
2098fda13ad2SSunitha Harish             params[1],
2099fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
2100fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
2101f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
2102e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv4AddressData> &ipv4Data,
2103e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData> &ipv6Data,
2104e48c0fc5SRavi Teja                 const boost::container::flat_set<IPv6AddressData>
2105e48c0fc5SRavi Teja                     &ipv6StaticData) {
2106fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
21071abe55efSEd Tanous                 {
21080f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
2109e48c0fc5SRavi Teja                                        ifaceId, ethData, ipv4Data, ipv6Data,
2110e48c0fc5SRavi Teja                                        ipv6StaticData);
2111927a505aSKowalski, Kamil 
2112f12894f8SJason M. Bills                     auto callback =
2113f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
21141abe55efSEd Tanous                             if (ec)
21151abe55efSEd Tanous                             {
2116f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
2117927a505aSKowalski, Kamil                             }
21184a0cb85cSEd Tanous                         };
21194a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
21204a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
21214a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
21224a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
21231abe55efSEd Tanous                 }
21241abe55efSEd Tanous                 else
21251abe55efSEd Tanous                 {
2126927a505aSKowalski, Kamil                     // ... otherwise return error
2127f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
2128f12894f8SJason M. Bills                     // object, and other errors
2129f12894f8SJason M. Bills                     messages::resourceNotFound(
2130f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
2131927a505aSKowalski, Kamil                 }
2132927a505aSKowalski, Kamil             });
2133e439f0f8SKowalski, Kamil     }
2134e439f0f8SKowalski, Kamil };
2135e439f0f8SKowalski, Kamil 
2136e439f0f8SKowalski, Kamil /**
2137e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
2138e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
2139e439f0f8SKowalski, Kamil  */
21401abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
21411abe55efSEd Tanous {
2142e439f0f8SKowalski, Kamil   public:
2143e439f0f8SKowalski, Kamil     template <typename CrowApp>
21441abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
21454a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
21464a0cb85cSEd Tanous              std::string())
21471abe55efSEd Tanous     {
2148e439f0f8SKowalski, Kamil         entityPrivileges = {
2149e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
2150e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
2151e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2152e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2153e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2154e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2155e439f0f8SKowalski, Kamil     }
2156e439f0f8SKowalski, Kamil 
2157e439f0f8SKowalski, Kamil   private:
2158e439f0f8SKowalski, Kamil     /**
2159e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
2160e439f0f8SKowalski, Kamil      */
216155c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
21621abe55efSEd Tanous                const std::vector<std::string> &params) override
21631abe55efSEd Tanous     {
21644a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
21651abe55efSEd Tanous         if (params.size() != 1)
21661abe55efSEd Tanous         {
2167e439f0f8SKowalski, Kamil             // This means there is a problem with the router
2168f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2169e439f0f8SKowalski, Kamil             return;
2170e439f0f8SKowalski, Kamil         }
2171e439f0f8SKowalski, Kamil 
21724a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
2173e439f0f8SKowalski, Kamil 
21744a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
21751abe55efSEd Tanous         // preparation
2176f12894f8SJason M. Bills         getEthernetIfaceList(
217743b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
21781abe55efSEd Tanous                 const bool &success,
21794c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
21804a0cb85cSEd Tanous                 if (!success)
21811abe55efSEd Tanous                 {
2182f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
21834a0cb85cSEd Tanous                     return;
21841abe55efSEd Tanous                 }
21854c9afe43SEd Tanous 
21864c9afe43SEd Tanous                 if (iface_list.find(rootInterfaceName) == iface_list.end())
21874c9afe43SEd Tanous                 {
21884c9afe43SEd Tanous                     messages::resourceNotFound(asyncResp->res,
21894c9afe43SEd Tanous                                                "VLanNetworkInterfaceCollection",
21904c9afe43SEd Tanous                                                rootInterfaceName);
21914c9afe43SEd Tanous                     return;
21924c9afe43SEd Tanous                 }
21934c9afe43SEd Tanous 
21940f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
21950f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
21960f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
21970f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
21980f74e643SEd Tanous                     "/redfish/v1/$metadata"
21990f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
22000f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
22010f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
22020f74e643SEd Tanous                     "VLAN Network Interface Collection";
22034a0cb85cSEd Tanous 
22044a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
22054a0cb85cSEd Tanous 
22064a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
22071abe55efSEd Tanous                 {
22084a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
22094a0cb85cSEd Tanous                     {
22104a0cb85cSEd Tanous                         iface_array.push_back(
22114a0cb85cSEd Tanous                             {{"@odata.id",
22124a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
22134a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
2214e439f0f8SKowalski, Kamil                     }
2215e439f0f8SKowalski, Kamil                 }
2216e439f0f8SKowalski, Kamil 
22174a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
22184a0cb85cSEd Tanous                     iface_array.size();
22194a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
22204a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
22214a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
22224a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
2223e439f0f8SKowalski, Kamil             });
2224e439f0f8SKowalski, Kamil     }
2225e439f0f8SKowalski, Kamil 
222655c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
22271abe55efSEd Tanous                 const std::vector<std::string> &params) override
22281abe55efSEd Tanous     {
22294a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
22301abe55efSEd Tanous         if (params.size() != 1)
22311abe55efSEd Tanous         {
2232f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2233e439f0f8SKowalski, Kamil             return;
2234e439f0f8SKowalski, Kamil         }
2235fda13ad2SSunitha Harish         bool vlanEnable = false;
22360627a2c7SEd Tanous         uint32_t vlanId = 0;
2237fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
2238fda13ad2SSunitha Harish                                  vlanEnable))
22391abe55efSEd Tanous         {
22404a0cb85cSEd Tanous             return;
2241e439f0f8SKowalski, Kamil         }
2242fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
2243fda13ad2SSunitha Harish         if (!vlanId)
2244fda13ad2SSunitha Harish         {
2245fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
2246fda13ad2SSunitha Harish         }
2247fda13ad2SSunitha Harish         if (!vlanEnable)
2248fda13ad2SSunitha Harish         {
2249fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
2250fda13ad2SSunitha Harish         }
2251fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
2252fda13ad2SSunitha Harish         {
2253fda13ad2SSunitha Harish             return;
2254fda13ad2SSunitha Harish         }
2255fda13ad2SSunitha Harish 
22564a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
22574a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
22581abe55efSEd Tanous             if (ec)
22591abe55efSEd Tanous             {
22604a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
22614a0cb85cSEd Tanous                 // phosphor-network responses
2262f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
22634a0cb85cSEd Tanous                 return;
22641abe55efSEd Tanous             }
2265f12894f8SJason M. Bills             messages::created(asyncResp->res);
2266e439f0f8SKowalski, Kamil         };
22674a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
22684a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
22694a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
22704a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
22710627a2c7SEd Tanous             rootInterfaceName, vlanId);
22724a0cb85cSEd Tanous     }
22734a0cb85cSEd Tanous };
22749391bb9cSRapkiewicz, Pawel } // namespace redfish
2275