xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision da131a9a053f304528cae6573f97bb6f3db951b2)
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 /**
749391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
759391bb9cSRapkiewicz, Pawel  * available from DBus
769391bb9cSRapkiewicz, Pawel  */
771abe55efSEd Tanous struct EthernetInterfaceData
781abe55efSEd Tanous {
794a0cb85cSEd Tanous     uint32_t speed;
804a0cb85cSEd Tanous     bool auto_neg;
812a133282Smanojkiraneda     bool DHCPEnabled;
824a0cb85cSEd Tanous     std::string hostname;
834a0cb85cSEd Tanous     std::string default_gateway;
849a6fc6feSRavi Teja     std::string ipv6_default_gateway;
854a0cb85cSEd Tanous     std::string mac_address;
86fda13ad2SSunitha Harish     std::vector<std::uint32_t> vlan_id;
87029573d4SEd Tanous     std::vector<std::string> nameservers;
889391bb9cSRapkiewicz, Pawel };
899391bb9cSRapkiewicz, Pawel 
909391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
919391bb9cSRapkiewicz, Pawel // into full dot notation
921abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
931abe55efSEd Tanous {
949391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
959391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
969391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
979391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
989391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
999391bb9cSRapkiewicz, Pawel     return netmask;
1009391bb9cSRapkiewicz, Pawel }
1019391bb9cSRapkiewicz, Pawel 
1024a0cb85cSEd Tanous inline std::string
1034a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1044a0cb85cSEd Tanous                                         bool isIPv4)
1051abe55efSEd Tanous {
1064a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1071abe55efSEd Tanous     {
1084a0cb85cSEd Tanous         return "Static";
1099391bb9cSRapkiewicz, Pawel     }
1104a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1111abe55efSEd Tanous     {
1124a0cb85cSEd Tanous         if (isIPv4)
1131abe55efSEd Tanous         {
1144a0cb85cSEd Tanous             return "IPv4LinkLocal";
1151abe55efSEd Tanous         }
1161abe55efSEd Tanous         else
1171abe55efSEd Tanous         {
1184a0cb85cSEd Tanous             return "LinkLocal";
1199391bb9cSRapkiewicz, Pawel         }
1209391bb9cSRapkiewicz, Pawel     }
1214a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1221abe55efSEd Tanous     {
1234a0cb85cSEd Tanous         if (isIPv4)
1244a0cb85cSEd Tanous         {
1254a0cb85cSEd Tanous             return "DHCP";
1264a0cb85cSEd Tanous         }
1274a0cb85cSEd Tanous         else
1284a0cb85cSEd Tanous         {
1294a0cb85cSEd Tanous             return "DHCPv6";
1304a0cb85cSEd Tanous         }
1314a0cb85cSEd Tanous     }
1324a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1334a0cb85cSEd Tanous     {
1344a0cb85cSEd Tanous         return "SLAAC";
1354a0cb85cSEd Tanous     }
1364a0cb85cSEd Tanous     return "";
1374a0cb85cSEd Tanous }
1384a0cb85cSEd Tanous 
1394a0cb85cSEd Tanous inline std::string
1404a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1414a0cb85cSEd Tanous {
1424a0cb85cSEd Tanous     if (inputOrigin == "Static")
1434a0cb85cSEd Tanous     {
1444a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1454a0cb85cSEd Tanous     }
1464a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1474a0cb85cSEd Tanous     {
1484a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1494a0cb85cSEd Tanous     }
1504a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1514a0cb85cSEd Tanous     {
1524a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1534a0cb85cSEd Tanous     }
1544a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1554a0cb85cSEd Tanous     {
1564a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1574a0cb85cSEd Tanous     }
1584a0cb85cSEd Tanous     return "";
1594a0cb85cSEd Tanous }
1604a0cb85cSEd Tanous 
1614c9afe43SEd Tanous inline bool extractEthernetInterfaceData(const std::string &ethiface_id,
1624a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1634a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1644a0cb85cSEd Tanous {
1654c9afe43SEd Tanous     bool idFound = false;
1664a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1674a0cb85cSEd Tanous     {
1684a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1694a0cb85cSEd Tanous         {
170029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
171029573d4SEd Tanous             {
1724c9afe43SEd Tanous                 idFound = true;
1734a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1744a0cb85cSEd Tanous                 {
1754a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1764a0cb85cSEd Tanous                     {
1774a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1784a0cb85cSEd Tanous                         {
1794a0cb85cSEd Tanous                             const std::string *mac =
180abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1814a0cb85cSEd Tanous                             if (mac != nullptr)
1824a0cb85cSEd Tanous                             {
1834a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1844a0cb85cSEd Tanous                             }
1854a0cb85cSEd Tanous                         }
1864a0cb85cSEd Tanous                     }
1874a0cb85cSEd Tanous                 }
1884a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1894a0cb85cSEd Tanous                 {
1904a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1914a0cb85cSEd Tanous                     {
1924a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1934a0cb85cSEd Tanous                         {
1941b6b96c5SEd Tanous                             const uint32_t *id =
195abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1964a0cb85cSEd Tanous                             if (id != nullptr)
1974a0cb85cSEd Tanous                             {
198fda13ad2SSunitha Harish                                 ethData.vlan_id.push_back(*id);
1994a0cb85cSEd Tanous                             }
2004a0cb85cSEd Tanous                         }
2014a0cb85cSEd Tanous                     }
2024a0cb85cSEd Tanous                 }
2034a0cb85cSEd Tanous                 else if (ifacePair.first ==
2044a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2054a0cb85cSEd Tanous                 {
2064a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2074a0cb85cSEd Tanous                     {
2084a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2094a0cb85cSEd Tanous                         {
2104a0cb85cSEd Tanous                             const bool *auto_neg =
211abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2124a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2134a0cb85cSEd Tanous                             {
2144a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2154a0cb85cSEd Tanous                             }
2164a0cb85cSEd Tanous                         }
2174a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2184a0cb85cSEd Tanous                         {
2194a0cb85cSEd Tanous                             const uint32_t *speed =
220abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2214a0cb85cSEd Tanous                             if (speed != nullptr)
2224a0cb85cSEd Tanous                             {
2234a0cb85cSEd Tanous                                 ethData.speed = *speed;
2244a0cb85cSEd Tanous                             }
2254a0cb85cSEd Tanous                         }
226f85837bfSRAJESWARAN THILLAIGOVINDAN                         else if (propertyPair.first == "Nameservers")
227029573d4SEd Tanous                         {
228029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
229029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
230029573d4SEd Tanous                                     std::vector<std::string>>(
231029573d4SEd Tanous                                     &propertyPair.second);
232029573d4SEd Tanous                             if (nameservers != nullptr)
233029573d4SEd Tanous                             {
234029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2354a0cb85cSEd Tanous                             }
2364a0cb85cSEd Tanous                         }
2372a133282Smanojkiraneda                         else if (propertyPair.first == "DHCPEnabled")
2382a133282Smanojkiraneda                         {
2392a133282Smanojkiraneda                             const bool *DHCPEnabled =
2402a133282Smanojkiraneda                                 std::get_if<bool>(&propertyPair.second);
2412a133282Smanojkiraneda                             if (DHCPEnabled != nullptr)
2422a133282Smanojkiraneda                             {
2432a133282Smanojkiraneda                                 ethData.DHCPEnabled = *DHCPEnabled;
2442a133282Smanojkiraneda                             }
2452a133282Smanojkiraneda                         }
246029573d4SEd Tanous                     }
247029573d4SEd Tanous                 }
248029573d4SEd Tanous             }
249029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
250029573d4SEd Tanous             // to check eth number
251029573d4SEd Tanous             if (ifacePair.first ==
2524a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2534a0cb85cSEd Tanous             {
2544a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2554a0cb85cSEd Tanous                 {
2564a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2574a0cb85cSEd Tanous                     {
2584a0cb85cSEd Tanous                         const std::string *hostname =
259029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
260029573d4SEd Tanous                                 &propertyPair.second);
2614a0cb85cSEd Tanous                         if (hostname != nullptr)
2624a0cb85cSEd Tanous                         {
2634a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2644a0cb85cSEd Tanous                         }
2654a0cb85cSEd Tanous                     }
2664a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2674a0cb85cSEd Tanous                     {
2684a0cb85cSEd Tanous                         const std::string *defaultGateway =
269029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
270029573d4SEd Tanous                                 &propertyPair.second);
2714a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2724a0cb85cSEd Tanous                         {
2734a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2744a0cb85cSEd Tanous                         }
2754a0cb85cSEd Tanous                     }
2769a6fc6feSRavi Teja                     else if (propertyPair.first == "DefaultGateway6")
2779a6fc6feSRavi Teja                     {
2789a6fc6feSRavi Teja                         const std::string *defaultGateway6 =
2799a6fc6feSRavi Teja                             sdbusplus::message::variant_ns::get_if<std::string>(
2809a6fc6feSRavi Teja                                 &propertyPair.second);
2819a6fc6feSRavi Teja                         if (defaultGateway6 != nullptr)
2829a6fc6feSRavi Teja                         {
2839a6fc6feSRavi Teja                             ethData.ipv6_default_gateway = *defaultGateway6;
2849a6fc6feSRavi Teja                         }
2859a6fc6feSRavi Teja                     }
2864a0cb85cSEd Tanous                 }
2874a0cb85cSEd Tanous             }
2884a0cb85cSEd Tanous         }
2894a0cb85cSEd Tanous     }
2904c9afe43SEd Tanous     return idFound;
2914a0cb85cSEd Tanous }
2924a0cb85cSEd Tanous 
2934a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2944a0cb85cSEd Tanous inline void
2954a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2964a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2974a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2984a0cb85cSEd Tanous {
2994a0cb85cSEd Tanous     const std::string ipv4PathStart =
3004a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
3014a0cb85cSEd Tanous 
3024a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
3034a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
3044a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
3054a0cb85cSEd Tanous     {
3064a0cb85cSEd Tanous         // Check if proper pattern for object path appears
3074a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
3084a0cb85cSEd Tanous         {
3094a0cb85cSEd Tanous             for (auto &interface : objpath.second)
3104a0cb85cSEd Tanous             {
3114a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
3124a0cb85cSEd Tanous                 {
3134a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
3144a0cb85cSEd Tanous                     // appropriate
3154a0cb85cSEd Tanous                     std::pair<
3164a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
3174a0cb85cSEd Tanous                         bool>
3184a0cb85cSEd Tanous                         it = ipv4_config.insert(
319b01bf299SEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
3204a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
3214a0cb85cSEd Tanous                     for (auto &property : interface.second)
3224a0cb85cSEd Tanous                     {
3234a0cb85cSEd Tanous                         if (property.first == "Address")
3244a0cb85cSEd Tanous                         {
3254a0cb85cSEd Tanous                             const std::string *address =
326abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3274a0cb85cSEd Tanous                             if (address != nullptr)
3284a0cb85cSEd Tanous                             {
3294a0cb85cSEd Tanous                                 ipv4_address.address = *address;
3304a0cb85cSEd Tanous                             }
3314a0cb85cSEd Tanous                         }
3324a0cb85cSEd Tanous                         else if (property.first == "Gateway")
3334a0cb85cSEd Tanous                         {
3344a0cb85cSEd Tanous                             const std::string *gateway =
335abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3364a0cb85cSEd Tanous                             if (gateway != nullptr)
3374a0cb85cSEd Tanous                             {
3384a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
3394a0cb85cSEd Tanous                             }
3404a0cb85cSEd Tanous                         }
3414a0cb85cSEd Tanous                         else if (property.first == "Origin")
3424a0cb85cSEd Tanous                         {
3434a0cb85cSEd Tanous                             const std::string *origin =
344abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3454a0cb85cSEd Tanous                             if (origin != nullptr)
3464a0cb85cSEd Tanous                             {
3474a0cb85cSEd Tanous                                 ipv4_address.origin =
3484a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3494a0cb85cSEd Tanous                                                                         true);
3504a0cb85cSEd Tanous                             }
3514a0cb85cSEd Tanous                         }
3524a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3534a0cb85cSEd Tanous                         {
3544a0cb85cSEd Tanous                             const uint8_t *mask =
355abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
3564a0cb85cSEd Tanous                             if (mask != nullptr)
3574a0cb85cSEd Tanous                             {
3584a0cb85cSEd Tanous                                 // convert it to the string
3594a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3604a0cb85cSEd Tanous                             }
3614a0cb85cSEd Tanous                         }
3624a0cb85cSEd Tanous                         else
3634a0cb85cSEd Tanous                         {
3644a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3654a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3664a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3674a0cb85cSEd Tanous                         }
3684a0cb85cSEd Tanous                     }
3694a0cb85cSEd Tanous                     // Check if given address is local, or global
3704a0cb85cSEd Tanous                     ipv4_address.linktype =
3714a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3724a0cb85cSEd Tanous                             ? LinkType::Global
3734a0cb85cSEd Tanous                             : LinkType::Local;
3744a0cb85cSEd Tanous                 }
3754a0cb85cSEd Tanous             }
3764a0cb85cSEd Tanous         }
3774a0cb85cSEd Tanous     }
3784a0cb85cSEd Tanous }
379588c3f0dSKowalski, Kamil 
380588c3f0dSKowalski, Kamil /**
381588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
382588c3f0dSKowalski, Kamil  *
383588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
384588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
385588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
386588c3f0dSKowalski, Kamil  *
387588c3f0dSKowalski, Kamil  * @return None.
388588c3f0dSKowalski, Kamil  */
389588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3904a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3911abe55efSEd Tanous                   CallbackFunc &&callback)
3921abe55efSEd Tanous {
39355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
394588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
395588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
396588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
397588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
398abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
3994a0cb85cSEd Tanous }
400588c3f0dSKowalski, Kamil 
401588c3f0dSKowalski, Kamil /**
402179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
403179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
404179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
405179db1d7SKowalski, Kamil  *
406179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
407179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
408179db1d7SKowalski, Kamil  *
409179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
410179db1d7SKowalski, Kamil  */
4114a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
4121abe55efSEd Tanous                                        uint8_t *bits = nullptr)
4131abe55efSEd Tanous {
414179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
415179db1d7SKowalski, Kamil 
416179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
417179db1d7SKowalski, Kamil 
4184a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
4191abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
4201abe55efSEd Tanous     {
421179db1d7SKowalski, Kamil         return false;
422179db1d7SKowalski, Kamil     }
423179db1d7SKowalski, Kamil 
4241abe55efSEd Tanous     if (bits != nullptr)
4251abe55efSEd Tanous     {
426179db1d7SKowalski, Kamil         *bits = 0;
427179db1d7SKowalski, Kamil     }
428179db1d7SKowalski, Kamil 
429179db1d7SKowalski, Kamil     char *endPtr;
430179db1d7SKowalski, Kamil     long previousValue = 255;
431179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
4321abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
4331abe55efSEd Tanous     {
4341abe55efSEd Tanous         if (byte.empty())
4351abe55efSEd Tanous         {
4361db9ca37SKowalski, Kamil             return false;
4371db9ca37SKowalski, Kamil         }
4381db9ca37SKowalski, Kamil 
439179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4401db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
441179db1d7SKowalski, Kamil 
4424a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4434a0cb85cSEd Tanous         // is not 100% number
4441abe55efSEd Tanous         if (*endPtr != '\0')
4451abe55efSEd Tanous         {
446179db1d7SKowalski, Kamil             return false;
447179db1d7SKowalski, Kamil         }
448179db1d7SKowalski, Kamil 
449179db1d7SKowalski, Kamil         // Value should be contained in byte
4501abe55efSEd Tanous         if (value < 0 || value > 255)
4511abe55efSEd Tanous         {
452179db1d7SKowalski, Kamil             return false;
453179db1d7SKowalski, Kamil         }
454179db1d7SKowalski, Kamil 
4551abe55efSEd Tanous         if (bits != nullptr)
4561abe55efSEd Tanous         {
457179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4581abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4591abe55efSEd Tanous             {
460179db1d7SKowalski, Kamil                 return false;
461179db1d7SKowalski, Kamil             }
462179db1d7SKowalski, Kamil 
463179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
464179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
465179db1d7SKowalski, Kamil 
466179db1d7SKowalski, Kamil             // Count bits
4671abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4681abe55efSEd Tanous             {
4691abe55efSEd Tanous                 if (value & (1 << bitIdx))
4701abe55efSEd Tanous                 {
4711abe55efSEd Tanous                     if (firstZeroInByteHit)
4721abe55efSEd Tanous                     {
473179db1d7SKowalski, Kamil                         // Continuity not preserved
474179db1d7SKowalski, Kamil                         return false;
4751abe55efSEd Tanous                     }
4761abe55efSEd Tanous                     else
4771abe55efSEd Tanous                     {
478179db1d7SKowalski, Kamil                         (*bits)++;
479179db1d7SKowalski, Kamil                     }
4801abe55efSEd Tanous                 }
4811abe55efSEd Tanous                 else
4821abe55efSEd Tanous                 {
483179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
484179db1d7SKowalski, Kamil                 }
485179db1d7SKowalski, Kamil             }
486179db1d7SKowalski, Kamil         }
487179db1d7SKowalski, Kamil 
488179db1d7SKowalski, Kamil         previousValue = value;
489179db1d7SKowalski, Kamil     }
490179db1d7SKowalski, Kamil 
491179db1d7SKowalski, Kamil     return true;
492179db1d7SKowalski, Kamil }
493179db1d7SKowalski, Kamil 
494179db1d7SKowalski, Kamil /**
495b01bf299SEd Tanous  * @brief Changes IPv4 address type property (Address, Gateway)
496b01bf299SEd Tanous  *
497b01bf299SEd Tanous  * @param[in] ifaceId     Id of interface whose IP should be modified
498b01bf299SEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
499b01bf299SEd Tanous  * @param[in] ipHash      DBus Hash id of modified IP
500b01bf299SEd Tanous  * @param[in] name        Name of field in JSON representation
501b01bf299SEd Tanous  * @param[in] newValue    New value that should be written
502b01bf299SEd Tanous  * @param[io] asyncResp   Response object that will be returned to client
503b01bf299SEd Tanous  *
504b01bf299SEd Tanous  * @return true if give IP is valid and has been sent do D-Bus, false
505b01bf299SEd Tanous  * otherwise
506b01bf299SEd Tanous  */
507b01bf299SEd Tanous inline void changeIPv4AddressProperty(
508b01bf299SEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
509b01bf299SEd Tanous     const std::string &name, const std::string &newValue,
510b01bf299SEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
511b01bf299SEd Tanous {
512b01bf299SEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
513b01bf299SEd Tanous                      newValue{std::move(newValue)}](
514b01bf299SEd Tanous                         const boost::system::error_code ec) {
515b01bf299SEd Tanous         if (ec)
516b01bf299SEd Tanous         {
517b01bf299SEd Tanous             messages::internalError(asyncResp->res);
518b01bf299SEd Tanous         }
519b01bf299SEd Tanous         else
520b01bf299SEd Tanous         {
521b01bf299SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
522b01bf299SEd Tanous         }
523b01bf299SEd Tanous     };
524b01bf299SEd Tanous 
525b01bf299SEd Tanous     crow::connections::systemBus->async_method_call(
526b01bf299SEd Tanous         std::move(callback), "xyz.openbmc_project.Network",
527b01bf299SEd Tanous         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
528b01bf299SEd Tanous         "org.freedesktop.DBus.Properties", "Set",
529b01bf299SEd Tanous         "xyz.openbmc_project.Network.IP", name,
530b01bf299SEd Tanous         std::variant<std::string>(newValue));
531b01bf299SEd Tanous }
532b01bf299SEd Tanous 
533b01bf299SEd Tanous /**
534179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
535179db1d7SKowalski, Kamil  *
536179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
5374a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5381abe55efSEd Tanous  * modified
539179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
540179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
541179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
542179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
543179db1d7SKowalski, Kamil  *
544179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
545179db1d7SKowalski, Kamil  * otherwise
546179db1d7SKowalski, Kamil  */
547b01bf299SEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5481abe55efSEd Tanous                              const std::string &ipHash,
5491abe55efSEd Tanous                              const std::string &newValue,
550179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5514a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5521abe55efSEd Tanous {
5534a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5541abe55efSEd Tanous                         const boost::system::error_code ec) {
5551abe55efSEd Tanous         if (ec)
5561abe55efSEd Tanous         {
557a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5581abe55efSEd Tanous         }
5591abe55efSEd Tanous         else
5601abe55efSEd Tanous         {
5614a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
562179db1d7SKowalski, Kamil                 newValue;
563179db1d7SKowalski, Kamil         }
564179db1d7SKowalski, Kamil     };
565179db1d7SKowalski, Kamil 
56655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
567179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
568179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
569179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
570179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
571abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
5724a0cb85cSEd Tanous }
573179db1d7SKowalski, Kamil 
574179db1d7SKowalski, Kamil /**
575179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
576179db1d7SKowalski, Kamil  *
577179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5784a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5791abe55efSEd Tanous  * modified
580179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
581179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
582179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
583179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
584179db1d7SKowalski, Kamil  *
585179db1d7SKowalski, Kamil  * @return None
586179db1d7SKowalski, Kamil  */
587b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5884a0cb85cSEd Tanous                                          const std::string &ipHash,
5894a0cb85cSEd Tanous                                          const std::string &newValueStr,
5904a0cb85cSEd Tanous                                          uint8_t &newValue,
5914a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5921abe55efSEd Tanous {
5934a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5941abe55efSEd Tanous                         const boost::system::error_code ec) {
5951abe55efSEd Tanous         if (ec)
5961abe55efSEd Tanous         {
597a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5981abe55efSEd Tanous         }
5991abe55efSEd Tanous         else
6001abe55efSEd Tanous         {
60155c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
602179db1d7SKowalski, Kamil                 newValueStr;
603179db1d7SKowalski, Kamil         }
604179db1d7SKowalski, Kamil     };
605179db1d7SKowalski, Kamil 
60655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
607179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
608179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
609179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
610179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
611abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
6124a0cb85cSEd Tanous }
613588c3f0dSKowalski, Kamil 
614588c3f0dSKowalski, Kamil /**
615179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
616179db1d7SKowalski, Kamil  *
617179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6184a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
619179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
620179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
621179db1d7SKowalski, Kamil  *
622179db1d7SKowalski, Kamil  * @return None
623179db1d7SKowalski, Kamil  */
6244a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
625179db1d7SKowalski, Kamil                        unsigned int ipIdx,
6264a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6271abe55efSEd Tanous {
62855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6294a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6301abe55efSEd Tanous             if (ec)
6311abe55efSEd Tanous             {
632a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6331abe55efSEd Tanous             }
6341abe55efSEd Tanous             else
6351abe55efSEd Tanous             {
63655c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
637179db1d7SKowalski, Kamil             }
638179db1d7SKowalski, Kamil         },
639179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
640179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
641179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
642179db1d7SKowalski, Kamil }
643179db1d7SKowalski, Kamil 
644179db1d7SKowalski, Kamil /**
645179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
646179db1d7SKowalski, Kamil  *
647179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6484a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
649179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
650179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
651179db1d7SKowalski, Kamil  *
652179db1d7SKowalski, Kamil  * @return None
653179db1d7SKowalski, Kamil  */
654b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
655b01bf299SEd Tanous                        uint8_t subnetMask, const std::string &gateway,
656b01bf299SEd Tanous                        const std::string &address,
6574a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6581abe55efSEd Tanous {
65943b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
6601abe55efSEd Tanous         if (ec)
6611abe55efSEd Tanous         {
662a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
663179db1d7SKowalski, Kamil         }
664179db1d7SKowalski, Kamil     };
665179db1d7SKowalski, Kamil 
66655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
667179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
668179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
669179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
670179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
671179db1d7SKowalski, Kamil         gateway);
672179db1d7SKowalski, Kamil }
6732a133282Smanojkiraneda using GetAllPropertiesType =
6742a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
6752a133282Smanojkiraneda 
6762a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
6772a133282Smanojkiraneda {
6782a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
6792a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
6802a133282Smanojkiraneda         if (error_code)
6812a133282Smanojkiraneda         {
6822a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
6832a133282Smanojkiraneda             messages::internalError(asyncResp->res);
6842a133282Smanojkiraneda             return;
6852a133282Smanojkiraneda         }
686fda13ad2SSunitha Harish         nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
6872a133282Smanojkiraneda         for (const auto &property : dbus_data)
6882a133282Smanojkiraneda         {
6892a133282Smanojkiraneda             auto value =
6902a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
6912a133282Smanojkiraneda 
6922a133282Smanojkiraneda             if (value == nullptr)
6932a133282Smanojkiraneda             {
6942a133282Smanojkiraneda                 continue;
6952a133282Smanojkiraneda             }
6962a133282Smanojkiraneda             if (property.first == "DNSEnabled")
6972a133282Smanojkiraneda             {
6982a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
6992a133282Smanojkiraneda             }
7002a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
7012a133282Smanojkiraneda             {
7022a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
7032a133282Smanojkiraneda             }
7042a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
7052a133282Smanojkiraneda             {
7062a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
7072a133282Smanojkiraneda             }
7082a133282Smanojkiraneda         }
7092a133282Smanojkiraneda     };
7102a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
7112a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
7122a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
7132a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
7142a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
7152a133282Smanojkiraneda }
716179db1d7SKowalski, Kamil 
717179db1d7SKowalski, Kamil /**
718179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
719179db1d7SKowalski, Kamil  * Object
720179db1d7SKowalski, Kamil  * from EntityManager Network Manager
7214a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
722179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
723179db1d7SKowalski, Kamil  * into JSON
724179db1d7SKowalski, Kamil  */
725179db1d7SKowalski, Kamil template <typename CallbackFunc>
7264a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
7271abe55efSEd Tanous                           CallbackFunc &&callback)
7281abe55efSEd Tanous {
72955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7304a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
7311abe55efSEd Tanous             const boost::system::error_code error_code,
7324a0cb85cSEd Tanous             const GetManagedObjects &resp) {
73355c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
7344a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
735179db1d7SKowalski, Kamil 
7361abe55efSEd Tanous             if (error_code)
7371abe55efSEd Tanous             {
73855c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
739179db1d7SKowalski, Kamil                 return;
740179db1d7SKowalski, Kamil             }
741179db1d7SKowalski, Kamil 
7424c9afe43SEd Tanous             bool found =
7434a0cb85cSEd Tanous                 extractEthernetInterfaceData(ethiface_id, resp, ethData);
7444c9afe43SEd Tanous             if (!found)
7454c9afe43SEd Tanous             {
7464c9afe43SEd Tanous                 callback(false, ethData, ipv4Data);
7474c9afe43SEd Tanous                 return;
7484c9afe43SEd Tanous             }
7494c9afe43SEd Tanous 
7504a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
751179db1d7SKowalski, Kamil 
752179db1d7SKowalski, Kamil             // Fix global GW
7531abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
7541abe55efSEd Tanous             {
7554a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
7564a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
7571abe55efSEd Tanous                 {
7584a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
759179db1d7SKowalski, Kamil                 }
760179db1d7SKowalski, Kamil             }
761179db1d7SKowalski, Kamil 
7624a0cb85cSEd Tanous             // Finally make a callback with usefull data
76355c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
764179db1d7SKowalski, Kamil         },
765179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
766179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
767179db1d7SKowalski, Kamil };
768179db1d7SKowalski, Kamil 
769179db1d7SKowalski, Kamil /**
7709391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
7719391bb9cSRapkiewicz, Pawel  * Manager
7721abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
7731abe55efSEd Tanous  * into JSON.
7749391bb9cSRapkiewicz, Pawel  */
7759391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7761abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7771abe55efSEd Tanous {
77855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7794a0cb85cSEd Tanous         [callback{std::move(callback)}](
7809391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
7814a0cb85cSEd Tanous             GetManagedObjects &resp) {
7821abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7831abe55efSEd Tanous             // ethernet interfaces
7844c9afe43SEd Tanous             boost::container::flat_set<std::string> iface_list;
7854a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7861abe55efSEd Tanous             if (error_code)
7871abe55efSEd Tanous             {
7884a0cb85cSEd Tanous                 callback(false, iface_list);
7899391bb9cSRapkiewicz, Pawel                 return;
7909391bb9cSRapkiewicz, Pawel             }
7919391bb9cSRapkiewicz, Pawel 
7929391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7934a0cb85cSEd Tanous             for (const auto &objpath : resp)
7941abe55efSEd Tanous             {
7959391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7964a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7971abe55efSEd Tanous                 {
7981abe55efSEd Tanous                     // If interface is
7994a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
8004a0cb85cSEd Tanous                     // what we're looking for.
8019391bb9cSRapkiewicz, Pawel                     if (interface.first ==
8021abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
8031abe55efSEd Tanous                     {
8044a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
8054a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
8064a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
8074a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
8081abe55efSEd Tanous                         {
8099391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
8104c9afe43SEd Tanous                             iface_list.emplace(iface_id.substr(last_pos + 1));
8119391bb9cSRapkiewicz, Pawel                         }
8129391bb9cSRapkiewicz, Pawel                     }
8139391bb9cSRapkiewicz, Pawel                 }
8149391bb9cSRapkiewicz, Pawel             }
815a434f2bdSEd Tanous             // Finally make a callback with useful data
8164a0cb85cSEd Tanous             callback(true, iface_list);
8179391bb9cSRapkiewicz, Pawel         },
818aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
819aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8209391bb9cSRapkiewicz, Pawel };
8219391bb9cSRapkiewicz, Pawel 
8229391bb9cSRapkiewicz, Pawel /**
8239391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
8249391bb9cSRapkiewicz, Pawel  */
8251abe55efSEd Tanous class EthernetCollection : public Node
8261abe55efSEd Tanous {
8279391bb9cSRapkiewicz, Pawel   public:
8284a0cb85cSEd Tanous     template <typename CrowApp>
8291abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
8304a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
8311abe55efSEd Tanous     {
832588c3f0dSKowalski, Kamil         entityPrivileges = {
833588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
834e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
835e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
836e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
837e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
838e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8399391bb9cSRapkiewicz, Pawel     }
8409391bb9cSRapkiewicz, Pawel 
8419391bb9cSRapkiewicz, Pawel   private:
8429391bb9cSRapkiewicz, Pawel     /**
8439391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8449391bb9cSRapkiewicz, Pawel      */
84555c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
8461abe55efSEd Tanous                const std::vector<std::string> &params) override
8471abe55efSEd Tanous     {
8480f74e643SEd Tanous         res.jsonValue["@odata.type"] =
8490f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
8500f74e643SEd Tanous         res.jsonValue["@odata.context"] =
8510f74e643SEd Tanous             "/redfish/v1/"
8520f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
8530f74e643SEd Tanous         res.jsonValue["@odata.id"] =
8540f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
8550f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
8560f74e643SEd Tanous         res.jsonValue["Description"] =
8570f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
8584c9afe43SEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
8594a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
8601abe55efSEd Tanous         // preparation
861f12894f8SJason M. Bills         getEthernetIfaceList(
8624c9afe43SEd Tanous             [asyncResp](
8634c9afe43SEd Tanous                 const bool &success,
8644c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
8654a0cb85cSEd Tanous                 if (!success)
8661abe55efSEd Tanous                 {
8674c9afe43SEd Tanous                     messages::internalError(asyncResp->res);
8684a0cb85cSEd Tanous                     return;
8694a0cb85cSEd Tanous                 }
8704a0cb85cSEd Tanous 
8714c9afe43SEd Tanous                 nlohmann::json &iface_array =
8724c9afe43SEd Tanous                     asyncResp->res.jsonValue["Members"];
8734a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
874fda13ad2SSunitha Harish                 std::string tag = "_";
8754a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
8761abe55efSEd Tanous                 {
877fda13ad2SSunitha Harish                     std::size_t found = iface_item.find(tag);
878fda13ad2SSunitha Harish                     if (found == std::string::npos)
879fda13ad2SSunitha Harish                     {
8804a0cb85cSEd Tanous                         iface_array.push_back(
8814a0cb85cSEd Tanous                             {{"@odata.id",
8824a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
8834a0cb85cSEd Tanous                                   iface_item}});
8849391bb9cSRapkiewicz, Pawel                     }
885fda13ad2SSunitha Harish                 }
8864a0cb85cSEd Tanous 
8874c9afe43SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
8884c9afe43SEd Tanous                     iface_array.size();
8894c9afe43SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
8904a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
8919391bb9cSRapkiewicz, Pawel             });
8929391bb9cSRapkiewicz, Pawel     }
8939391bb9cSRapkiewicz, Pawel };
8949391bb9cSRapkiewicz, Pawel 
8959391bb9cSRapkiewicz, Pawel /**
8969391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8979391bb9cSRapkiewicz, Pawel  */
8981abe55efSEd Tanous class EthernetInterface : public Node
8991abe55efSEd Tanous {
9009391bb9cSRapkiewicz, Pawel   public:
9019391bb9cSRapkiewicz, Pawel     /*
9029391bb9cSRapkiewicz, Pawel      * Default Constructor
9039391bb9cSRapkiewicz, Pawel      */
9044a0cb85cSEd Tanous     template <typename CrowApp>
9051abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
9064a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
9071abe55efSEd Tanous              std::string())
9081abe55efSEd Tanous     {
909588c3f0dSKowalski, Kamil         entityPrivileges = {
910588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
911e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
912e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
913e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
914e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
915e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
9169391bb9cSRapkiewicz, Pawel     }
9179391bb9cSRapkiewicz, Pawel 
918e439f0f8SKowalski, Kamil   private:
919bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
9204a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
9211abe55efSEd Tanous     {
922bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
923bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
924bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
9254a0cb85cSEd Tanous                 if (ec)
9264a0cb85cSEd Tanous                 {
927a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
9281abe55efSEd Tanous                 }
929bc0bd6e0SEd Tanous             },
930bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
931bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
932bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
933bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
934abf2add6SEd Tanous             std::variant<std::string>(hostname));
935588c3f0dSKowalski, Kamil     }
936588c3f0dSKowalski, Kamil 
937d577665bSRatan Gupta     void handleMACAddressPatch(const std::string &ifaceId,
938d577665bSRatan Gupta                                const std::string &macAddress,
939d577665bSRatan Gupta                                const std::shared_ptr<AsyncResp> &asyncResp)
940d577665bSRatan Gupta     {
941d577665bSRatan Gupta         crow::connections::systemBus->async_method_call(
942d577665bSRatan Gupta             [asyncResp, macAddress](const boost::system::error_code ec) {
943d577665bSRatan Gupta                 if (ec)
944d577665bSRatan Gupta                 {
945d577665bSRatan Gupta                     messages::internalError(asyncResp->res);
946d577665bSRatan Gupta                     return;
947d577665bSRatan Gupta                 }
948d577665bSRatan Gupta                 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
949d577665bSRatan Gupta             },
950d577665bSRatan Gupta             "xyz.openbmc_project.Network",
951d577665bSRatan Gupta             "/xyz/openbmc_project/network/" + ifaceId,
952d577665bSRatan Gupta             "org.freedesktop.DBus.Properties", "Set",
953d577665bSRatan Gupta             "xyz.openbmc_project.Network.MACAddress", "MACAddress",
954d577665bSRatan Gupta             std::variant<std::string>(macAddress));
955d577665bSRatan Gupta     }
956*da131a9aSJennifer Lee     void setDHCPEnabled(const std::string &ifaceId,
957*da131a9aSJennifer Lee                         const std::string &propertyName, const bool &value,
958*da131a9aSJennifer Lee                         const std::shared_ptr<AsyncResp> asyncResp)
959*da131a9aSJennifer Lee     {
960*da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
961*da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
962*da131a9aSJennifer Lee                 if (ec)
963*da131a9aSJennifer Lee                 {
964*da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
965*da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
966*da131a9aSJennifer Lee                     return;
967*da131a9aSJennifer Lee                 }
968*da131a9aSJennifer Lee             },
969*da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
970*da131a9aSJennifer Lee             "/xyz/openbmc_project/network/" + ifaceId,
971*da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
972*da131a9aSJennifer Lee             "xyz.openbmc_project.Network.EthernetInterface", propertyName,
973*da131a9aSJennifer Lee             std::variant<bool>{value});
974*da131a9aSJennifer Lee     }
975*da131a9aSJennifer Lee     void setDHCPv4Config(const std::string &propertyName, const bool &value,
976*da131a9aSJennifer Lee                          const std::shared_ptr<AsyncResp> asyncResp)
977*da131a9aSJennifer Lee     {
978*da131a9aSJennifer Lee         BMCWEB_LOG_DEBUG << propertyName << " = " << value;
979*da131a9aSJennifer Lee         crow::connections::systemBus->async_method_call(
980*da131a9aSJennifer Lee             [asyncResp](const boost::system::error_code ec) {
981*da131a9aSJennifer Lee                 if (ec)
982*da131a9aSJennifer Lee                 {
983*da131a9aSJennifer Lee                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
984*da131a9aSJennifer Lee                     messages::internalError(asyncResp->res);
985*da131a9aSJennifer Lee                     return;
986*da131a9aSJennifer Lee                 }
987*da131a9aSJennifer Lee             },
988*da131a9aSJennifer Lee             "xyz.openbmc_project.Network",
989*da131a9aSJennifer Lee             "/xyz/openbmc_project/network/config/dhcp",
990*da131a9aSJennifer Lee             "org.freedesktop.DBus.Properties", "Set",
991*da131a9aSJennifer Lee             "xyz.openbmc_project.Network.DHCPConfiguration", propertyName,
992*da131a9aSJennifer Lee             std::variant<bool>{value});
993*da131a9aSJennifer Lee     }
994d577665bSRatan Gupta 
995*da131a9aSJennifer Lee     void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input,
996*da131a9aSJennifer Lee                            const std::shared_ptr<AsyncResp> asyncResp)
997*da131a9aSJennifer Lee     {
998*da131a9aSJennifer Lee         std::optional<bool> dhcpEnabled;
999*da131a9aSJennifer Lee         std::optional<bool> useDNSServers;
1000*da131a9aSJennifer Lee         std::optional<bool> useDomainName;
1001*da131a9aSJennifer Lee         std::optional<bool> useNTPServers;
1002*da131a9aSJennifer Lee 
1003*da131a9aSJennifer Lee         if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled",
1004*da131a9aSJennifer Lee                                  dhcpEnabled, "UseDNSServers", useDNSServers,
1005*da131a9aSJennifer Lee                                  "UseDomainName", useDomainName,
1006*da131a9aSJennifer Lee                                  "UseNTPServers", useNTPServers))
1007*da131a9aSJennifer Lee         {
1008*da131a9aSJennifer Lee             return;
1009*da131a9aSJennifer Lee         }
1010*da131a9aSJennifer Lee 
1011*da131a9aSJennifer Lee         if (dhcpEnabled)
1012*da131a9aSJennifer Lee         {
1013*da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DHCPEnabled...";
1014*da131a9aSJennifer Lee             setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp);
1015*da131a9aSJennifer Lee         }
1016*da131a9aSJennifer Lee 
1017*da131a9aSJennifer Lee         if (useDNSServers)
1018*da131a9aSJennifer Lee         {
1019*da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set DNSEnabled...";
1020*da131a9aSJennifer Lee             setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp);
1021*da131a9aSJennifer Lee         }
1022*da131a9aSJennifer Lee 
1023*da131a9aSJennifer Lee         if (useDomainName)
1024*da131a9aSJennifer Lee         {
1025*da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set HostNameEnabled...";
1026*da131a9aSJennifer Lee             setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp);
1027*da131a9aSJennifer Lee         }
1028*da131a9aSJennifer Lee 
1029*da131a9aSJennifer Lee         if (useNTPServers)
1030*da131a9aSJennifer Lee         {
1031*da131a9aSJennifer Lee             BMCWEB_LOG_DEBUG << "set NTPEnabled...";
1032*da131a9aSJennifer Lee             setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp);
1033*da131a9aSJennifer Lee         }
1034*da131a9aSJennifer Lee     }
10354a0cb85cSEd Tanous     void handleIPv4Patch(
1036f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
10374a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
10384a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
10391abe55efSEd Tanous     {
1040f476acbfSRatan Gupta         if (!input.is_array())
1041f476acbfSRatan Gupta         {
1042f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
1043f476acbfSRatan Gupta                                              "IPv4Addresses");
1044f476acbfSRatan Gupta             return;
1045f476acbfSRatan Gupta         }
1046f476acbfSRatan Gupta 
10474a0cb85cSEd Tanous         int entryIdx = 0;
10484a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
10494a0cb85cSEd Tanous             ipv4Data.begin();
1050537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
10511abe55efSEd Tanous         {
10524a0cb85cSEd Tanous             std::string pathString =
1053a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
1054179db1d7SKowalski, Kamil 
1055f476acbfSRatan Gupta             if (thisJson.is_null())
1056f476acbfSRatan Gupta             {
1057f476acbfSRatan Gupta                 if (thisData != ipv4Data.end())
1058f476acbfSRatan Gupta                 {
1059f476acbfSRatan Gupta                     deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
1060f476acbfSRatan Gupta                     thisData++;
1061f476acbfSRatan Gupta                 }
1062f476acbfSRatan Gupta                 else
1063f476acbfSRatan Gupta                 {
1064f476acbfSRatan Gupta                     messages::propertyValueFormatError(
1065f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
1066f476acbfSRatan Gupta                     return;
1067f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
1068f476acbfSRatan Gupta                     // list and if unable to update one of the
1069f476acbfSRatan Gupta                     // list value then should we proceed further or
1070f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
1071f476acbfSRatan Gupta                     // till then we stop processing the next list item.
1072f476acbfSRatan Gupta                 }
1073f476acbfSRatan Gupta                 entryIdx++;
1074f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
1075f476acbfSRatan Gupta             }
1076f476acbfSRatan Gupta 
10779474b378SRatan Gupta             if (thisJson.empty())
10789474b378SRatan Gupta             {
10799474b378SRatan Gupta                 if (thisData != ipv4Data.end())
10809474b378SRatan Gupta                 {
10819474b378SRatan Gupta                     thisData++;
10829474b378SRatan Gupta                 }
10839474b378SRatan Gupta                 else
10849474b378SRatan Gupta                 {
10859474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
10869474b378SRatan Gupta                                               pathString + "/Address");
10879474b378SRatan Gupta                     return;
1088f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
10899474b378SRatan Gupta                     // list and if unable to update one of the
10909474b378SRatan Gupta                     // list value then should we proceed further or
10919474b378SRatan Gupta                     // break there, would ask in the redfish forum
10929474b378SRatan Gupta                     // till then we stop processing the next list item.
10939474b378SRatan Gupta                 }
10949474b378SRatan Gupta                 entryIdx++;
10959474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
10969474b378SRatan Gupta             }
10979474b378SRatan Gupta 
1098537174c4SEd Tanous             std::optional<std::string> address;
1099537174c4SEd Tanous             std::optional<std::string> addressOrigin;
1100537174c4SEd Tanous             std::optional<std::string> subnetMask;
1101537174c4SEd Tanous             std::optional<std::string> gateway;
1102537174c4SEd Tanous 
1103537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1104537174c4SEd Tanous                                      address, "AddressOrigin", addressOrigin,
1105537174c4SEd Tanous                                      "SubnetMask", subnetMask, "Gateway",
1106537174c4SEd Tanous                                      gateway))
1107537174c4SEd Tanous             {
1108537174c4SEd Tanous                 return;
1109179db1d7SKowalski, Kamil             }
1110179db1d7SKowalski, Kamil 
1111537174c4SEd Tanous             if (address)
11121abe55efSEd Tanous             {
1113537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
11141abe55efSEd Tanous                 {
1115537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
11164a0cb85cSEd Tanous                                                        pathString + "/Address");
1117537174c4SEd Tanous                     return;
11184a0cb85cSEd Tanous                 }
11194a0cb85cSEd Tanous             }
11204a0cb85cSEd Tanous 
1121537174c4SEd Tanous             uint8_t prefixLength = 0;
1122537174c4SEd Tanous             if (subnetMask)
11234a0cb85cSEd Tanous             {
1124537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
11254a0cb85cSEd Tanous                 {
1126f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1127537174c4SEd Tanous                         asyncResp->res, *subnetMask,
11284a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1129537174c4SEd Tanous                     return;
11304a0cb85cSEd Tanous                 }
11314a0cb85cSEd Tanous             }
11324a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
1133537174c4SEd Tanous             if (addressOrigin)
11344a0cb85cSEd Tanous             {
11354a0cb85cSEd Tanous                 // Get Address origin in proper format
11364a0cb85cSEd Tanous                 addressOriginInDBusFormat =
1137537174c4SEd Tanous                     translateAddressOriginRedfishToDbus(*addressOrigin);
11384a0cb85cSEd Tanous                 if (addressOriginInDBusFormat.empty())
11394a0cb85cSEd Tanous                 {
11404a0cb85cSEd Tanous                     messages::propertyValueNotInList(
1141537174c4SEd Tanous                         asyncResp->res, *addressOrigin,
1142a08b46ccSJason M. Bills                         pathString + "/AddressOrigin");
1143537174c4SEd Tanous                     return;
11444a0cb85cSEd Tanous                 }
11454a0cb85cSEd Tanous             }
11464a0cb85cSEd Tanous 
1147537174c4SEd Tanous             if (gateway)
11484a0cb85cSEd Tanous             {
1149537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
11504a0cb85cSEd Tanous                 {
1151537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1152537174c4SEd Tanous                                                        pathString + "/Gateway");
1153537174c4SEd Tanous                     return;
11544a0cb85cSEd Tanous                 }
11554a0cb85cSEd Tanous             }
11564a0cb85cSEd Tanous 
1157f476acbfSRatan Gupta             // if IP address exist then  modify it.
11584a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
11594a0cb85cSEd Tanous             {
1160179db1d7SKowalski, Kamil                 // Apply changes
1161537174c4SEd Tanous                 if (address)
11621abe55efSEd Tanous                 {
1163f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1164f476acbfSRatan Gupta                                      address{std::string(*address)}](
11654a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
11664a0cb85cSEd Tanous                         if (ec)
11671abe55efSEd Tanous                         {
1168a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
11694a0cb85cSEd Tanous                             return;
11704a0cb85cSEd Tanous                         }
1171f476acbfSRatan Gupta                         asyncResp->res
1172f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1173f476acbfSRatan Gupta                             std::move(address);
11744a0cb85cSEd Tanous                     };
11754a0cb85cSEd Tanous 
11764a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
11774a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1178f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1179f476acbfSRatan Gupta                             thisData->id,
11804a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
11814a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1182537174c4SEd Tanous                         std::variant<std::string>(*address));
1183179db1d7SKowalski, Kamil                 }
1184179db1d7SKowalski, Kamil 
1185537174c4SEd Tanous                 if (subnetMask)
11861abe55efSEd Tanous                 {
11874a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1188537174c4SEd Tanous                                                  thisData->id, *subnetMask,
1189537174c4SEd Tanous                                                  prefixLength, asyncResp);
1190179db1d7SKowalski, Kamil                 }
1191179db1d7SKowalski, Kamil 
1192537174c4SEd Tanous                 if (addressOrigin)
11931abe55efSEd Tanous                 {
11944a0cb85cSEd Tanous                     changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1195f476acbfSRatan Gupta                                      *addressOrigin, addressOriginInDBusFormat,
1196f476acbfSRatan Gupta                                      asyncResp);
1197179db1d7SKowalski, Kamil                 }
1198179db1d7SKowalski, Kamil 
1199537174c4SEd Tanous                 if (gateway)
12001abe55efSEd Tanous                 {
1201f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1202537174c4SEd Tanous                                      gateway{std::string(*gateway)}](
12034a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
12044a0cb85cSEd Tanous                         if (ec)
12051abe55efSEd Tanous                         {
1206a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
12074a0cb85cSEd Tanous                             return;
12084a0cb85cSEd Tanous                         }
1209f476acbfSRatan Gupta                         asyncResp->res
1210f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1211537174c4SEd Tanous                             std::move(gateway);
12124a0cb85cSEd Tanous                     };
12134a0cb85cSEd Tanous 
12144a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
12154a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1216f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1217f476acbfSRatan Gupta                             thisData->id,
12184a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
12194a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1220537174c4SEd Tanous                         std::variant<std::string>(*gateway));
12214a0cb85cSEd Tanous                 }
1222f476acbfSRatan Gupta 
12234a0cb85cSEd Tanous                 thisData++;
12241abe55efSEd Tanous             }
12251abe55efSEd Tanous             else
12261abe55efSEd Tanous             {
12274a0cb85cSEd Tanous                 // Create IPv4 with provided data
1228537174c4SEd Tanous                 if (!gateway)
12291abe55efSEd Tanous                 {
1230a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
12314a0cb85cSEd Tanous                                               pathString + "/Gateway");
12324a0cb85cSEd Tanous                     continue;
12334a0cb85cSEd Tanous                 }
12344a0cb85cSEd Tanous 
1235537174c4SEd Tanous                 if (!address)
12361abe55efSEd Tanous                 {
1237a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
12384a0cb85cSEd Tanous                                               pathString + "/Address");
12394a0cb85cSEd Tanous                     continue;
12404a0cb85cSEd Tanous                 }
12414a0cb85cSEd Tanous 
1242537174c4SEd Tanous                 if (!subnetMask)
12431abe55efSEd Tanous                 {
1244a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
12454a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
12464a0cb85cSEd Tanous                     continue;
1247588c3f0dSKowalski, Kamil                 }
1248588c3f0dSKowalski, Kamil 
1249b01bf299SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1250b01bf299SEd Tanous                            asyncResp);
125195897b20SRatan Gupta 
125295897b20SRatan Gupta                 nlohmann::json &ipv4AddressJson =
125395897b20SRatan Gupta                     asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
125495897b20SRatan Gupta                 ipv4AddressJson["Address"] = *address;
125595897b20SRatan Gupta                 ipv4AddressJson["SubnetMask"] = *subnetMask;
125695897b20SRatan Gupta                 ipv4AddressJson["Gateway"] = *gateway;
12574a0cb85cSEd Tanous             }
12584a0cb85cSEd Tanous             entryIdx++;
12594a0cb85cSEd Tanous         }
12604a0cb85cSEd Tanous     }
12614a0cb85cSEd Tanous 
1262f85837bfSRAJESWARAN THILLAIGOVINDAN     void handleStaticNameServersPatch(
1263f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::string &ifaceId,
1264f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::vector<std::string> &updatedStaticNameServers,
1265f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::shared_ptr<AsyncResp> &asyncResp)
1266f85837bfSRAJESWARAN THILLAIGOVINDAN     {
1267f85837bfSRAJESWARAN THILLAIGOVINDAN         crow::connections::systemBus->async_method_call(
1268f85837bfSRAJESWARAN THILLAIGOVINDAN             [asyncResp,
1269f85837bfSRAJESWARAN THILLAIGOVINDAN              updatedStaticNameServers](const boost::system::error_code ec) {
1270f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (ec)
1271f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1272f85837bfSRAJESWARAN THILLAIGOVINDAN                     messages::internalError(asyncResp->res);
1273f85837bfSRAJESWARAN THILLAIGOVINDAN                     return;
1274f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1275f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["NameServers"] =
1276f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1277f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["StaticNameServers"] =
1278f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1279f85837bfSRAJESWARAN THILLAIGOVINDAN             },
1280f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network",
1281f85837bfSRAJESWARAN THILLAIGOVINDAN             "/xyz/openbmc_project/network/" + ifaceId,
1282f85837bfSRAJESWARAN THILLAIGOVINDAN             "org.freedesktop.DBus.Properties", "Set",
1283f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1284f85837bfSRAJESWARAN THILLAIGOVINDAN             std::variant<std::vector<std::string>>{updatedStaticNameServers});
1285f85837bfSRAJESWARAN THILLAIGOVINDAN     }
1286f85837bfSRAJESWARAN THILLAIGOVINDAN 
12870f74e643SEd Tanous     void parseInterfaceData(
12880f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
12890f74e643SEd Tanous         const EthernetInterfaceData &ethData,
12904a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
12914a0cb85cSEd Tanous     {
12924a0cb85cSEd Tanous         json_response["Id"] = iface_id;
12934a0cb85cSEd Tanous         json_response["@odata.id"] =
12944a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1295029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1296029573d4SEd Tanous         if (ethData.speed == 0)
1297029573d4SEd Tanous         {
1298029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1299029573d4SEd Tanous             json_response["Status"] = {
1300029573d4SEd Tanous                 {"Health", "OK"},
1301029573d4SEd Tanous                 {"State", "Disabled"},
1302029573d4SEd Tanous             };
1303029573d4SEd Tanous         }
1304029573d4SEd Tanous         else
1305029573d4SEd Tanous         {
1306029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1307029573d4SEd Tanous             json_response["Status"] = {
1308029573d4SEd Tanous                 {"Health", "OK"},
1309029573d4SEd Tanous                 {"State", "Enabled"},
1310029573d4SEd Tanous             };
1311029573d4SEd Tanous         }
13124a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
13134a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1314fda13ad2SSunitha Harish         json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
13152a133282Smanojkiraneda 
13164a0cb85cSEd Tanous         if (!ethData.hostname.empty())
13174a0cb85cSEd Tanous         {
13184a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
13194a0cb85cSEd Tanous         }
13204a0cb85cSEd Tanous 
1321fda13ad2SSunitha Harish         json_response["VLANs"] = {
1322fda13ad2SSunitha Harish             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1323fda13ad2SSunitha Harish                               iface_id + "/VLANs"}};
1324fda13ad2SSunitha Harish 
1325029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
1326f85837bfSRAJESWARAN THILLAIGOVINDAN         json_response["StaticNameServers"] = ethData.nameservers;
13274a0cb85cSEd Tanous 
13284a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
13294a0cb85cSEd Tanous         {
13304a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
13314a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
13324a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
13334a0cb85cSEd Tanous             {
1334fa5053a6SGunnar Mills 
1335fa5053a6SGunnar Mills                 std::string gatewayStr = ipv4_config.gateway;
1336fa5053a6SGunnar Mills                 if (gatewayStr.empty())
1337fa5053a6SGunnar Mills                 {
1338fa5053a6SGunnar Mills                     gatewayStr = "0.0.0.0";
1339fa5053a6SGunnar Mills                 }
1340fa5053a6SGunnar Mills 
13414a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
13424a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1343029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1344fa5053a6SGunnar Mills                                       {"Gateway", gatewayStr}});
13454a0cb85cSEd Tanous             }
13464a0cb85cSEd Tanous         }
13479a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1348588c3f0dSKowalski, Kamil     }
1349588c3f0dSKowalski, Kamil 
13509391bb9cSRapkiewicz, Pawel     /**
13519391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
13529391bb9cSRapkiewicz, Pawel      */
135355c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
13541abe55efSEd Tanous                const std::vector<std::string> &params) override
13551abe55efSEd Tanous     {
13564a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13571abe55efSEd Tanous         if (params.size() != 1)
13581abe55efSEd Tanous         {
1359f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
13609391bb9cSRapkiewicz, Pawel             return;
13619391bb9cSRapkiewicz, Pawel         }
13629391bb9cSRapkiewicz, Pawel 
13634a0cb85cSEd Tanous         getEthernetIfaceData(
13644a0cb85cSEd Tanous             params[0],
13654a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
13664a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13674a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13684a0cb85cSEd Tanous                 if (!success)
13691abe55efSEd Tanous                 {
13701abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13711abe55efSEd Tanous                     // object, and other errors
1372f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1373f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
13744a0cb85cSEd Tanous                     return;
13759391bb9cSRapkiewicz, Pawel                 }
13764c9afe43SEd Tanous 
13774c9afe43SEd Tanous                 // because this has no dependence on the interface at this
13784c9afe43SEd Tanous                 // point, it needs to be done after we know the interface
13794c9afe43SEd Tanous                 // exists, not before.
13804c9afe43SEd Tanous                 getDHCPConfigData(asyncResp);
13814c9afe43SEd Tanous 
13820f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1383fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
13840f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
13850f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
13860f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
13870f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
13880f74e643SEd Tanous                     "Management Network Interface";
13890f74e643SEd Tanous 
13900f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
13910f74e643SEd Tanous                                    ipv4Data);
13929391bb9cSRapkiewicz, Pawel             });
13939391bb9cSRapkiewicz, Pawel     }
13949391bb9cSRapkiewicz, Pawel 
139555c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
13961abe55efSEd Tanous                  const std::vector<std::string> &params) override
13971abe55efSEd Tanous     {
13984a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13991abe55efSEd Tanous         if (params.size() != 1)
14001abe55efSEd Tanous         {
1401f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1402588c3f0dSKowalski, Kamil             return;
1403588c3f0dSKowalski, Kamil         }
1404588c3f0dSKowalski, Kamil 
14054a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1406588c3f0dSKowalski, Kamil 
1407bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1408d577665bSRatan Gupta         std::optional<std::string> macAddress;
14099a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1410f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1411f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1412f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
14135112e9b4SRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> nameServers;
1414*da131a9aSJennifer Lee         std::optional<nlohmann::json> dhcpv4;
14150627a2c7SEd Tanous 
1416fda13ad2SSunitha Harish         if (!json_util::readJson(
1417fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
1418f85837bfSRAJESWARAN THILLAIGOVINDAN                 "IPv6Addresses", ipv6Addresses, "MACAddress", macAddress,
14199a6fc6feSRavi Teja                 "StaticNameServers", staticNameServers, "IPv6DefaultGateway",
1420*da131a9aSJennifer Lee                 ipv6DefaultGateway, "NameServers", nameServers, "DHCPv4",
1421*da131a9aSJennifer Lee                 dhcpv4))
14221abe55efSEd Tanous         {
1423588c3f0dSKowalski, Kamil             return;
1424588c3f0dSKowalski, Kamil         }
1425f15aad37SRatan Gupta 
1426*da131a9aSJennifer Lee         if (dhcpv4)
1427*da131a9aSJennifer Lee         {
1428*da131a9aSJennifer Lee             handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp);
1429*da131a9aSJennifer Lee         }
1430*da131a9aSJennifer Lee 
14314a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1432588c3f0dSKowalski, Kamil         // preparation
14334a0cb85cSEd Tanous         getEthernetIfaceData(
14344a0cb85cSEd Tanous             iface_id,
1435fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1436fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
14370627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
1438f85837bfSRAJESWARAN THILLAIGOVINDAN              ipv6Addresses = std::move(ipv6Addresses),
14399a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
14405112e9b4SRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers),
14415112e9b4SRAJESWARAN THILLAIGOVINDAN              nameServers = std::move(nameServers)](
14424a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14434a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14441abe55efSEd Tanous                 if (!success)
14451abe55efSEd Tanous                 {
1446588c3f0dSKowalski, Kamil                     // ... otherwise return error
14471abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14481abe55efSEd Tanous                     // object, and other errors
1449fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1450fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1451588c3f0dSKowalski, Kamil                     return;
1452588c3f0dSKowalski, Kamil                 }
1453588c3f0dSKowalski, Kamil 
14540f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
14550f74e643SEd Tanous                                    ipv4Data);
1456588c3f0dSKowalski, Kamil 
14570627a2c7SEd Tanous                 if (hostname)
14581abe55efSEd Tanous                 {
14590627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
14601abe55efSEd Tanous                 }
14610627a2c7SEd Tanous 
1462d577665bSRatan Gupta                 if (macAddress)
1463d577665bSRatan Gupta                 {
1464d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1465d577665bSRatan Gupta                 }
1466d577665bSRatan Gupta 
14670627a2c7SEd Tanous                 if (ipv4Addresses)
14681abe55efSEd Tanous                 {
1469537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1470537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1471537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1472537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1473537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1474537174c4SEd Tanous                     // on that, but could be done more efficiently
1475f476acbfSRatan Gupta                     nlohmann::json ipv4 = std::move(*ipv4Addresses);
1476537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
14771abe55efSEd Tanous                 }
14780627a2c7SEd Tanous 
14795112e9b4SRAJESWARAN THILLAIGOVINDAN                 if (nameServers)
14805112e9b4SRAJESWARAN THILLAIGOVINDAN                 {
14815112e9b4SRAJESWARAN THILLAIGOVINDAN                     // Data.Permissions is read-only
14825112e9b4SRAJESWARAN THILLAIGOVINDAN                     messages::propertyNotWritable(asyncResp->res,
14835112e9b4SRAJESWARAN THILLAIGOVINDAN                                                   "NameServers");
14845112e9b4SRAJESWARAN THILLAIGOVINDAN                 }
14855112e9b4SRAJESWARAN THILLAIGOVINDAN 
14860627a2c7SEd Tanous                 if (ipv6Addresses)
14871abe55efSEd Tanous                 {
1488179db1d7SKowalski, Kamil                     // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1489a08b46ccSJason M. Bills                     messages::propertyNotWritable(asyncResp->res,
14900627a2c7SEd Tanous                                                   "IPv6Addresses");
1491588c3f0dSKowalski, Kamil                 }
1492f85837bfSRAJESWARAN THILLAIGOVINDAN 
1493f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1494f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1495f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1496f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1497f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
14989a6fc6feSRavi Teja 
14999a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
15009a6fc6feSRavi Teja                 {
15019a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
15029a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
15039a6fc6feSRavi Teja                 }
1504588c3f0dSKowalski, Kamil             });
1505588c3f0dSKowalski, Kamil     }
15069391bb9cSRapkiewicz, Pawel };
15079391bb9cSRapkiewicz, Pawel 
1508e439f0f8SKowalski, Kamil /**
15094a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
15104a0cb85cSEd Tanous  * Schema
1511e439f0f8SKowalski, Kamil  */
15121abe55efSEd Tanous class VlanNetworkInterface : public Node
15131abe55efSEd Tanous {
1514e439f0f8SKowalski, Kamil   public:
1515e439f0f8SKowalski, Kamil     /*
1516e439f0f8SKowalski, Kamil      * Default Constructor
1517e439f0f8SKowalski, Kamil      */
1518e439f0f8SKowalski, Kamil     template <typename CrowApp>
15191abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
15204a0cb85cSEd Tanous         Node(app,
15210f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
15221abe55efSEd Tanous              std::string(), std::string())
15231abe55efSEd Tanous     {
1524e439f0f8SKowalski, Kamil         entityPrivileges = {
1525e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1526e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1527e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1528e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1529e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1530e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1531e439f0f8SKowalski, Kamil     }
1532e439f0f8SKowalski, Kamil 
1533e439f0f8SKowalski, Kamil   private:
15340f74e643SEd Tanous     void parseInterfaceData(
15350f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
15360f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
15374a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
15381abe55efSEd Tanous     {
1539e439f0f8SKowalski, Kamil         // Fill out obvious data...
15404a0cb85cSEd Tanous         json_response["Id"] = iface_id;
15414a0cb85cSEd Tanous         json_response["@odata.id"] =
15424a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
15434a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1544e439f0f8SKowalski, Kamil 
15454a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1546fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
15474a0cb85cSEd Tanous         {
1548fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
15494a0cb85cSEd Tanous         }
1550e439f0f8SKowalski, Kamil     }
1551e439f0f8SKowalski, Kamil 
1552fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
15531abe55efSEd Tanous     {
15541abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
15551abe55efSEd Tanous         {
1556927a505aSKowalski, Kamil             return false;
15571abe55efSEd Tanous         }
15581abe55efSEd Tanous         else
15591abe55efSEd Tanous         {
1560927a505aSKowalski, Kamil             return true;
1561927a505aSKowalski, Kamil         }
1562927a505aSKowalski, Kamil     }
1563927a505aSKowalski, Kamil 
1564e439f0f8SKowalski, Kamil     /**
1565e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1566e439f0f8SKowalski, Kamil      */
156755c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15681abe55efSEd Tanous                const std::vector<std::string> &params) override
15691abe55efSEd Tanous     {
15704a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15714a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1572e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1573e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1574e439f0f8SKowalski, Kamil         // impossible.
15751abe55efSEd Tanous         if (params.size() != 2)
15761abe55efSEd Tanous         {
1577f12894f8SJason M. Bills             messages::internalError(res);
1578e439f0f8SKowalski, Kamil             res.end();
1579e439f0f8SKowalski, Kamil             return;
1580e439f0f8SKowalski, Kamil         }
1581e439f0f8SKowalski, Kamil 
15824a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
15834a0cb85cSEd Tanous         const std::string &iface_id = params[1];
15840f74e643SEd Tanous         res.jsonValue["@odata.type"] =
15850f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
15860f74e643SEd Tanous         res.jsonValue["@odata.context"] =
15870f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
15880f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1589e439f0f8SKowalski, Kamil 
1590fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
15911abe55efSEd Tanous         {
1592a434f2bdSEd Tanous             return;
1593a434f2bdSEd Tanous         }
1594a434f2bdSEd Tanous 
1595e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1596e439f0f8SKowalski, Kamil         // preparation
15974a0cb85cSEd Tanous         getEthernetIfaceData(
1598fda13ad2SSunitha Harish             params[1],
1599fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1600fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
16014a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
16024a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1603fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
16041abe55efSEd Tanous                 {
16050f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
16060f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
16070f74e643SEd Tanous                                        ipv4Data);
16081abe55efSEd Tanous                 }
16091abe55efSEd Tanous                 else
16101abe55efSEd Tanous                 {
1611e439f0f8SKowalski, Kamil                     // ... otherwise return error
16121abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
16131abe55efSEd Tanous                     // object, and other errors
1614f12894f8SJason M. Bills                     messages::resourceNotFound(
1615f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1616e439f0f8SKowalski, Kamil                 }
1617e439f0f8SKowalski, Kamil             });
1618e439f0f8SKowalski, Kamil     }
1619e439f0f8SKowalski, Kamil 
162055c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
16211abe55efSEd Tanous                  const std::vector<std::string> &params) override
16221abe55efSEd Tanous     {
16234a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16241abe55efSEd Tanous         if (params.size() != 2)
16251abe55efSEd Tanous         {
1626f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1627e439f0f8SKowalski, Kamil             return;
1628e439f0f8SKowalski, Kamil         }
1629e439f0f8SKowalski, Kamil 
1630d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
163155c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1632927a505aSKowalski, Kamil 
1633fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
16341abe55efSEd Tanous         {
1635fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1636fda13ad2SSunitha Harish                                        ifaceId);
1637927a505aSKowalski, Kamil             return;
1638927a505aSKowalski, Kamil         }
1639927a505aSKowalski, Kamil 
16400627a2c7SEd Tanous         bool vlanEnable = false;
16410627a2c7SEd Tanous         uint64_t vlanId = 0;
16420627a2c7SEd Tanous 
16430627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
16440627a2c7SEd Tanous                                  vlanId))
16451abe55efSEd Tanous         {
1646927a505aSKowalski, Kamil             return;
1647927a505aSKowalski, Kamil         }
1648927a505aSKowalski, Kamil 
1649927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1650927a505aSKowalski, Kamil         // preparation
165108244d02SSunitha Harish         getEthernetIfaceData(params[1], [this, asyncResp,
165208244d02SSunitha Harish                                          parentIfaceId{std::string(params[0])},
165308244d02SSunitha Harish                                          ifaceId{std::string(params[1])},
165408244d02SSunitha Harish                                          &vlanEnable, &vlanId](
165508244d02SSunitha Harish                                             const bool &success,
165608244d02SSunitha Harish                                             const EthernetInterfaceData
165708244d02SSunitha Harish                                                 &ethData,
165808244d02SSunitha Harish                                             const boost::container::flat_set<
165908244d02SSunitha Harish                                                 IPv4AddressData> &ipv4Data) {
166008244d02SSunitha Harish             if (success && !ethData.vlan_id.empty())
166108244d02SSunitha Harish             {
166208244d02SSunitha Harish                 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
166308244d02SSunitha Harish                                    ifaceId, ethData, ipv4Data);
166408244d02SSunitha Harish                 auto callback =
166508244d02SSunitha Harish                     [asyncResp](const boost::system::error_code ec) {
166608244d02SSunitha Harish                         if (ec)
166708244d02SSunitha Harish                         {
166808244d02SSunitha Harish                             messages::internalError(asyncResp->res);
166908244d02SSunitha Harish                         }
167008244d02SSunitha Harish                     };
167108244d02SSunitha Harish 
167208244d02SSunitha Harish                 if (vlanEnable == true)
167308244d02SSunitha Harish                 {
167408244d02SSunitha Harish                     crow::connections::systemBus->async_method_call(
167508244d02SSunitha Harish                         std::move(callback), "xyz.openbmc_project.Network",
167608244d02SSunitha Harish                         "/xyz/openbmc_project/network/" + ifaceId,
167708244d02SSunitha Harish                         "org.freedesktop.DBus.Properties", "Set",
167808244d02SSunitha Harish                         "xyz.openbmc_project.Network.VLAN", "Id",
167908244d02SSunitha Harish                         std::variant<uint32_t>(vlanId));
168008244d02SSunitha Harish                 }
168108244d02SSunitha Harish                 else
168208244d02SSunitha Harish                 {
168308244d02SSunitha Harish                     BMCWEB_LOG_DEBUG
168408244d02SSunitha Harish                         << "vlanEnable is false. Deleting the vlan interface";
168508244d02SSunitha Harish                     crow::connections::systemBus->async_method_call(
168608244d02SSunitha Harish                         std::move(callback), "xyz.openbmc_project.Network",
168708244d02SSunitha Harish                         std::string("/xyz/openbmc_project/network/") + ifaceId,
168808244d02SSunitha Harish                         "xyz.openbmc_project.Object.Delete", "Delete");
168908244d02SSunitha Harish                 }
169008244d02SSunitha Harish             }
169108244d02SSunitha Harish             else
16921abe55efSEd Tanous             {
16931abe55efSEd Tanous                 // TODO(Pawel)consider distinguish between non existing
16941abe55efSEd Tanous                 // object, and other errors
169508244d02SSunitha Harish                 messages::resourceNotFound(asyncResp->res,
169608244d02SSunitha Harish                                            "VLAN Network Interface", ifaceId);
1697927a505aSKowalski, Kamil                 return;
1698927a505aSKowalski, Kamil             }
1699927a505aSKowalski, Kamil         });
1700e439f0f8SKowalski, Kamil     }
1701e439f0f8SKowalski, Kamil 
170255c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
17031abe55efSEd Tanous                   const std::vector<std::string> &params) override
17041abe55efSEd Tanous     {
17054a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17061abe55efSEd Tanous         if (params.size() != 2)
17071abe55efSEd Tanous         {
1708f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1709e439f0f8SKowalski, Kamil             return;
1710e439f0f8SKowalski, Kamil         }
1711e439f0f8SKowalski, Kamil 
1712d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
171355c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1714927a505aSKowalski, Kamil 
1715fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
17161abe55efSEd Tanous         {
1717fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1718fda13ad2SSunitha Harish                                        ifaceId);
1719927a505aSKowalski, Kamil             return;
1720927a505aSKowalski, Kamil         }
1721927a505aSKowalski, Kamil 
1722927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1723927a505aSKowalski, Kamil         // preparation
1724f12894f8SJason M. Bills         getEthernetIfaceData(
1725fda13ad2SSunitha Harish             params[1],
1726fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
1727fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
1728f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1729f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1730fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
17311abe55efSEd Tanous                 {
17320f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
17330f74e643SEd Tanous                                        ifaceId, ethData, ipv4Data);
1734927a505aSKowalski, Kamil 
1735f12894f8SJason M. Bills                     auto callback =
1736f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
17371abe55efSEd Tanous                             if (ec)
17381abe55efSEd Tanous                             {
1739f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1740927a505aSKowalski, Kamil                             }
17414a0cb85cSEd Tanous                         };
17424a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
17434a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
17444a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
17454a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
17461abe55efSEd Tanous                 }
17471abe55efSEd Tanous                 else
17481abe55efSEd Tanous                 {
1749927a505aSKowalski, Kamil                     // ... otherwise return error
1750f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1751f12894f8SJason M. Bills                     // object, and other errors
1752f12894f8SJason M. Bills                     messages::resourceNotFound(
1753f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1754927a505aSKowalski, Kamil                 }
1755927a505aSKowalski, Kamil             });
1756e439f0f8SKowalski, Kamil     }
1757e439f0f8SKowalski, Kamil };
1758e439f0f8SKowalski, Kamil 
1759e439f0f8SKowalski, Kamil /**
1760e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1761e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1762e439f0f8SKowalski, Kamil  */
17631abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
17641abe55efSEd Tanous {
1765e439f0f8SKowalski, Kamil   public:
1766e439f0f8SKowalski, Kamil     template <typename CrowApp>
17671abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
17684a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
17694a0cb85cSEd Tanous              std::string())
17701abe55efSEd Tanous     {
1771e439f0f8SKowalski, Kamil         entityPrivileges = {
1772e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1773e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1774e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1775e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1776e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1777e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1778e439f0f8SKowalski, Kamil     }
1779e439f0f8SKowalski, Kamil 
1780e439f0f8SKowalski, Kamil   private:
1781e439f0f8SKowalski, Kamil     /**
1782e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1783e439f0f8SKowalski, Kamil      */
178455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
17851abe55efSEd Tanous                const std::vector<std::string> &params) override
17861abe55efSEd Tanous     {
17874a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17881abe55efSEd Tanous         if (params.size() != 1)
17891abe55efSEd Tanous         {
1790e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1791f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1792e439f0f8SKowalski, Kamil             return;
1793e439f0f8SKowalski, Kamil         }
1794e439f0f8SKowalski, Kamil 
17954a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1796e439f0f8SKowalski, Kamil 
17974a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
17981abe55efSEd Tanous         // preparation
1799f12894f8SJason M. Bills         getEthernetIfaceList(
180043b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
18011abe55efSEd Tanous                 const bool &success,
18024c9afe43SEd Tanous                 const boost::container::flat_set<std::string> &iface_list) {
18034a0cb85cSEd Tanous                 if (!success)
18041abe55efSEd Tanous                 {
1805f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
18064a0cb85cSEd Tanous                     return;
18071abe55efSEd Tanous                 }
18084c9afe43SEd Tanous 
18094c9afe43SEd Tanous                 if (iface_list.find(rootInterfaceName) == iface_list.end())
18104c9afe43SEd Tanous                 {
18114c9afe43SEd Tanous                     messages::resourceNotFound(asyncResp->res,
18124c9afe43SEd Tanous                                                "VLanNetworkInterfaceCollection",
18134c9afe43SEd Tanous                                                rootInterfaceName);
18144c9afe43SEd Tanous                     return;
18154c9afe43SEd Tanous                 }
18164c9afe43SEd Tanous 
18170f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
18180f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
18190f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
18200f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
18210f74e643SEd Tanous                     "/redfish/v1/$metadata"
18220f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
18230f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
18240f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
18250f74e643SEd Tanous                     "VLAN Network Interface Collection";
18264a0cb85cSEd Tanous 
18274a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
18284a0cb85cSEd Tanous 
18294a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
18301abe55efSEd Tanous                 {
18314a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
18324a0cb85cSEd Tanous                     {
18334a0cb85cSEd Tanous                         iface_array.push_back(
18344a0cb85cSEd Tanous                             {{"@odata.id",
18354a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
18364a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1837e439f0f8SKowalski, Kamil                     }
1838e439f0f8SKowalski, Kamil                 }
1839e439f0f8SKowalski, Kamil 
18404a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
18414a0cb85cSEd Tanous                     iface_array.size();
18424a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
18434a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
18444a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
18454a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1846e439f0f8SKowalski, Kamil             });
1847e439f0f8SKowalski, Kamil     }
1848e439f0f8SKowalski, Kamil 
184955c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
18501abe55efSEd Tanous                 const std::vector<std::string> &params) override
18511abe55efSEd Tanous     {
18524a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
18531abe55efSEd Tanous         if (params.size() != 1)
18541abe55efSEd Tanous         {
1855f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1856e439f0f8SKowalski, Kamil             return;
1857e439f0f8SKowalski, Kamil         }
1858fda13ad2SSunitha Harish         bool vlanEnable = false;
18590627a2c7SEd Tanous         uint32_t vlanId = 0;
1860fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
1861fda13ad2SSunitha Harish                                  vlanEnable))
18621abe55efSEd Tanous         {
18634a0cb85cSEd Tanous             return;
1864e439f0f8SKowalski, Kamil         }
1865fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
1866fda13ad2SSunitha Harish         if (!vlanId)
1867fda13ad2SSunitha Harish         {
1868fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
1869fda13ad2SSunitha Harish         }
1870fda13ad2SSunitha Harish         if (!vlanEnable)
1871fda13ad2SSunitha Harish         {
1872fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
1873fda13ad2SSunitha Harish         }
1874fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1875fda13ad2SSunitha Harish         {
1876fda13ad2SSunitha Harish             return;
1877fda13ad2SSunitha Harish         }
1878fda13ad2SSunitha Harish 
18794a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
18804a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
18811abe55efSEd Tanous             if (ec)
18821abe55efSEd Tanous             {
18834a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
18844a0cb85cSEd Tanous                 // phosphor-network responses
1885f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
18864a0cb85cSEd Tanous                 return;
18871abe55efSEd Tanous             }
1888f12894f8SJason M. Bills             messages::created(asyncResp->res);
1889e439f0f8SKowalski, Kamil         };
18904a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
18914a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
18924a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
18934a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
18940627a2c7SEd Tanous             rootInterfaceName, vlanId);
18954a0cb85cSEd Tanous     }
18964a0cb85cSEd Tanous };
18979391bb9cSRapkiewicz, Pawel } // namespace redfish
1898