xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 9a6fc6fe4ad7ad2e3b028419bdb081a42e88ff0a)
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;
84*9a6fc6feSRavi 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 
1614a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
1624a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1634a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1644a0cb85cSEd Tanous {
1654a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1664a0cb85cSEd Tanous     {
1674a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1684a0cb85cSEd Tanous         {
169029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
170029573d4SEd Tanous             {
1714a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1724a0cb85cSEd Tanous                 {
1734a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1744a0cb85cSEd Tanous                     {
1754a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1764a0cb85cSEd Tanous                         {
1774a0cb85cSEd Tanous                             const std::string *mac =
178abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1794a0cb85cSEd Tanous                             if (mac != nullptr)
1804a0cb85cSEd Tanous                             {
1814a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1824a0cb85cSEd Tanous                             }
1834a0cb85cSEd Tanous                         }
1844a0cb85cSEd Tanous                     }
1854a0cb85cSEd Tanous                 }
1864a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1874a0cb85cSEd Tanous                 {
1884a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1894a0cb85cSEd Tanous                     {
1904a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1914a0cb85cSEd Tanous                         {
1921b6b96c5SEd Tanous                             const uint32_t *id =
193abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1944a0cb85cSEd Tanous                             if (id != nullptr)
1954a0cb85cSEd Tanous                             {
196fda13ad2SSunitha Harish                                 ethData.vlan_id.push_back(*id);
1974a0cb85cSEd Tanous                             }
1984a0cb85cSEd Tanous                         }
1994a0cb85cSEd Tanous                     }
2004a0cb85cSEd Tanous                 }
2014a0cb85cSEd Tanous                 else if (ifacePair.first ==
2024a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2034a0cb85cSEd Tanous                 {
2044a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2054a0cb85cSEd Tanous                     {
2064a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2074a0cb85cSEd Tanous                         {
2084a0cb85cSEd Tanous                             const bool *auto_neg =
209abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2104a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2114a0cb85cSEd Tanous                             {
2124a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2134a0cb85cSEd Tanous                             }
2144a0cb85cSEd Tanous                         }
2154a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2164a0cb85cSEd Tanous                         {
2174a0cb85cSEd Tanous                             const uint32_t *speed =
218abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2194a0cb85cSEd Tanous                             if (speed != nullptr)
2204a0cb85cSEd Tanous                             {
2214a0cb85cSEd Tanous                                 ethData.speed = *speed;
2224a0cb85cSEd Tanous                             }
2234a0cb85cSEd Tanous                         }
224f85837bfSRAJESWARAN THILLAIGOVINDAN                         else if (propertyPair.first == "Nameservers")
225029573d4SEd Tanous                         {
226029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
227029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
228029573d4SEd Tanous                                     std::vector<std::string>>(
229029573d4SEd Tanous                                     &propertyPair.second);
230029573d4SEd Tanous                             if (nameservers != nullptr)
231029573d4SEd Tanous                             {
232029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2334a0cb85cSEd Tanous                             }
2344a0cb85cSEd Tanous                         }
2352a133282Smanojkiraneda                         else if (propertyPair.first == "DHCPEnabled")
2362a133282Smanojkiraneda                         {
2372a133282Smanojkiraneda                             const bool *DHCPEnabled =
2382a133282Smanojkiraneda                                 std::get_if<bool>(&propertyPair.second);
2392a133282Smanojkiraneda                             if (DHCPEnabled != nullptr)
2402a133282Smanojkiraneda                             {
2412a133282Smanojkiraneda                                 ethData.DHCPEnabled = *DHCPEnabled;
2422a133282Smanojkiraneda                             }
2432a133282Smanojkiraneda                         }
244029573d4SEd Tanous                     }
245029573d4SEd Tanous                 }
246029573d4SEd Tanous             }
247029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
248029573d4SEd Tanous             // to check eth number
249029573d4SEd Tanous             if (ifacePair.first ==
2504a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2514a0cb85cSEd Tanous             {
2524a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2534a0cb85cSEd Tanous                 {
2544a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2554a0cb85cSEd Tanous                     {
2564a0cb85cSEd Tanous                         const std::string *hostname =
257029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
258029573d4SEd Tanous                                 &propertyPair.second);
2594a0cb85cSEd Tanous                         if (hostname != nullptr)
2604a0cb85cSEd Tanous                         {
2614a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2624a0cb85cSEd Tanous                         }
2634a0cb85cSEd Tanous                     }
2644a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2654a0cb85cSEd Tanous                     {
2664a0cb85cSEd Tanous                         const std::string *defaultGateway =
267029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
268029573d4SEd Tanous                                 &propertyPair.second);
2694a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2704a0cb85cSEd Tanous                         {
2714a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2724a0cb85cSEd Tanous                         }
2734a0cb85cSEd Tanous                     }
274*9a6fc6feSRavi Teja                     else if (propertyPair.first == "DefaultGateway6")
275*9a6fc6feSRavi Teja                     {
276*9a6fc6feSRavi Teja                         const std::string *defaultGateway6 =
277*9a6fc6feSRavi Teja                             sdbusplus::message::variant_ns::get_if<std::string>(
278*9a6fc6feSRavi Teja                                 &propertyPair.second);
279*9a6fc6feSRavi Teja                         if (defaultGateway6 != nullptr)
280*9a6fc6feSRavi Teja                         {
281*9a6fc6feSRavi Teja                             ethData.ipv6_default_gateway = *defaultGateway6;
282*9a6fc6feSRavi Teja                         }
283*9a6fc6feSRavi Teja                     }
2844a0cb85cSEd Tanous                 }
2854a0cb85cSEd Tanous             }
2864a0cb85cSEd Tanous         }
2874a0cb85cSEd Tanous     }
2884a0cb85cSEd Tanous }
2894a0cb85cSEd Tanous 
2904a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2914a0cb85cSEd Tanous inline void
2924a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2934a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2944a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2954a0cb85cSEd Tanous {
2964a0cb85cSEd Tanous     const std::string ipv4PathStart =
2974a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
2984a0cb85cSEd Tanous 
2994a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
3004a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
3014a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
3024a0cb85cSEd Tanous     {
3034a0cb85cSEd Tanous         // Check if proper pattern for object path appears
3044a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
3054a0cb85cSEd Tanous         {
3064a0cb85cSEd Tanous             for (auto &interface : objpath.second)
3074a0cb85cSEd Tanous             {
3084a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
3094a0cb85cSEd Tanous                 {
3104a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
3114a0cb85cSEd Tanous                     // appropriate
3124a0cb85cSEd Tanous                     std::pair<
3134a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
3144a0cb85cSEd Tanous                         bool>
3154a0cb85cSEd Tanous                         it = ipv4_config.insert(
316b01bf299SEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
3174a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
3184a0cb85cSEd Tanous                     for (auto &property : interface.second)
3194a0cb85cSEd Tanous                     {
3204a0cb85cSEd Tanous                         if (property.first == "Address")
3214a0cb85cSEd Tanous                         {
3224a0cb85cSEd Tanous                             const std::string *address =
323abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3244a0cb85cSEd Tanous                             if (address != nullptr)
3254a0cb85cSEd Tanous                             {
3264a0cb85cSEd Tanous                                 ipv4_address.address = *address;
3274a0cb85cSEd Tanous                             }
3284a0cb85cSEd Tanous                         }
3294a0cb85cSEd Tanous                         else if (property.first == "Gateway")
3304a0cb85cSEd Tanous                         {
3314a0cb85cSEd Tanous                             const std::string *gateway =
332abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3334a0cb85cSEd Tanous                             if (gateway != nullptr)
3344a0cb85cSEd Tanous                             {
3354a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
3364a0cb85cSEd Tanous                             }
3374a0cb85cSEd Tanous                         }
3384a0cb85cSEd Tanous                         else if (property.first == "Origin")
3394a0cb85cSEd Tanous                         {
3404a0cb85cSEd Tanous                             const std::string *origin =
341abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3424a0cb85cSEd Tanous                             if (origin != nullptr)
3434a0cb85cSEd Tanous                             {
3444a0cb85cSEd Tanous                                 ipv4_address.origin =
3454a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3464a0cb85cSEd Tanous                                                                         true);
3474a0cb85cSEd Tanous                             }
3484a0cb85cSEd Tanous                         }
3494a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3504a0cb85cSEd Tanous                         {
3514a0cb85cSEd Tanous                             const uint8_t *mask =
352abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
3534a0cb85cSEd Tanous                             if (mask != nullptr)
3544a0cb85cSEd Tanous                             {
3554a0cb85cSEd Tanous                                 // convert it to the string
3564a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3574a0cb85cSEd Tanous                             }
3584a0cb85cSEd Tanous                         }
3594a0cb85cSEd Tanous                         else
3604a0cb85cSEd Tanous                         {
3614a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3624a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3634a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3644a0cb85cSEd Tanous                         }
3654a0cb85cSEd Tanous                     }
3664a0cb85cSEd Tanous                     // Check if given address is local, or global
3674a0cb85cSEd Tanous                     ipv4_address.linktype =
3684a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3694a0cb85cSEd Tanous                             ? LinkType::Global
3704a0cb85cSEd Tanous                             : LinkType::Local;
3714a0cb85cSEd Tanous                 }
3724a0cb85cSEd Tanous             }
3734a0cb85cSEd Tanous         }
3744a0cb85cSEd Tanous     }
3754a0cb85cSEd Tanous }
376588c3f0dSKowalski, Kamil 
377588c3f0dSKowalski, Kamil /**
378588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
379588c3f0dSKowalski, Kamil  *
380588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
381588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
382588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
383588c3f0dSKowalski, Kamil  *
384588c3f0dSKowalski, Kamil  * @return None.
385588c3f0dSKowalski, Kamil  */
386588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3874a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3881abe55efSEd Tanous                   CallbackFunc &&callback)
3891abe55efSEd Tanous {
39055c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
391588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
392588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
393588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
394588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
395abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
3964a0cb85cSEd Tanous }
397588c3f0dSKowalski, Kamil 
398588c3f0dSKowalski, Kamil /**
399179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
400179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
401179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
402179db1d7SKowalski, Kamil  *
403179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
404179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
405179db1d7SKowalski, Kamil  *
406179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
407179db1d7SKowalski, Kamil  */
4084a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
4091abe55efSEd Tanous                                        uint8_t *bits = nullptr)
4101abe55efSEd Tanous {
411179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
412179db1d7SKowalski, Kamil 
413179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
414179db1d7SKowalski, Kamil 
4154a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
4161abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
4171abe55efSEd Tanous     {
418179db1d7SKowalski, Kamil         return false;
419179db1d7SKowalski, Kamil     }
420179db1d7SKowalski, Kamil 
4211abe55efSEd Tanous     if (bits != nullptr)
4221abe55efSEd Tanous     {
423179db1d7SKowalski, Kamil         *bits = 0;
424179db1d7SKowalski, Kamil     }
425179db1d7SKowalski, Kamil 
426179db1d7SKowalski, Kamil     char *endPtr;
427179db1d7SKowalski, Kamil     long previousValue = 255;
428179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
4291abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
4301abe55efSEd Tanous     {
4311abe55efSEd Tanous         if (byte.empty())
4321abe55efSEd Tanous         {
4331db9ca37SKowalski, Kamil             return false;
4341db9ca37SKowalski, Kamil         }
4351db9ca37SKowalski, Kamil 
436179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4371db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
438179db1d7SKowalski, Kamil 
4394a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4404a0cb85cSEd Tanous         // is not 100% number
4411abe55efSEd Tanous         if (*endPtr != '\0')
4421abe55efSEd Tanous         {
443179db1d7SKowalski, Kamil             return false;
444179db1d7SKowalski, Kamil         }
445179db1d7SKowalski, Kamil 
446179db1d7SKowalski, Kamil         // Value should be contained in byte
4471abe55efSEd Tanous         if (value < 0 || value > 255)
4481abe55efSEd Tanous         {
449179db1d7SKowalski, Kamil             return false;
450179db1d7SKowalski, Kamil         }
451179db1d7SKowalski, Kamil 
4521abe55efSEd Tanous         if (bits != nullptr)
4531abe55efSEd Tanous         {
454179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4551abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4561abe55efSEd Tanous             {
457179db1d7SKowalski, Kamil                 return false;
458179db1d7SKowalski, Kamil             }
459179db1d7SKowalski, Kamil 
460179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
461179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
462179db1d7SKowalski, Kamil 
463179db1d7SKowalski, Kamil             // Count bits
4641abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4651abe55efSEd Tanous             {
4661abe55efSEd Tanous                 if (value & (1 << bitIdx))
4671abe55efSEd Tanous                 {
4681abe55efSEd Tanous                     if (firstZeroInByteHit)
4691abe55efSEd Tanous                     {
470179db1d7SKowalski, Kamil                         // Continuity not preserved
471179db1d7SKowalski, Kamil                         return false;
4721abe55efSEd Tanous                     }
4731abe55efSEd Tanous                     else
4741abe55efSEd Tanous                     {
475179db1d7SKowalski, Kamil                         (*bits)++;
476179db1d7SKowalski, Kamil                     }
4771abe55efSEd Tanous                 }
4781abe55efSEd Tanous                 else
4791abe55efSEd Tanous                 {
480179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
481179db1d7SKowalski, Kamil                 }
482179db1d7SKowalski, Kamil             }
483179db1d7SKowalski, Kamil         }
484179db1d7SKowalski, Kamil 
485179db1d7SKowalski, Kamil         previousValue = value;
486179db1d7SKowalski, Kamil     }
487179db1d7SKowalski, Kamil 
488179db1d7SKowalski, Kamil     return true;
489179db1d7SKowalski, Kamil }
490179db1d7SKowalski, Kamil 
491179db1d7SKowalski, Kamil /**
492b01bf299SEd Tanous  * @brief Changes IPv4 address type property (Address, Gateway)
493b01bf299SEd Tanous  *
494b01bf299SEd Tanous  * @param[in] ifaceId     Id of interface whose IP should be modified
495b01bf299SEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
496b01bf299SEd Tanous  * @param[in] ipHash      DBus Hash id of modified IP
497b01bf299SEd Tanous  * @param[in] name        Name of field in JSON representation
498b01bf299SEd Tanous  * @param[in] newValue    New value that should be written
499b01bf299SEd Tanous  * @param[io] asyncResp   Response object that will be returned to client
500b01bf299SEd Tanous  *
501b01bf299SEd Tanous  * @return true if give IP is valid and has been sent do D-Bus, false
502b01bf299SEd Tanous  * otherwise
503b01bf299SEd Tanous  */
504b01bf299SEd Tanous inline void changeIPv4AddressProperty(
505b01bf299SEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
506b01bf299SEd Tanous     const std::string &name, const std::string &newValue,
507b01bf299SEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
508b01bf299SEd Tanous {
509b01bf299SEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
510b01bf299SEd Tanous                      newValue{std::move(newValue)}](
511b01bf299SEd Tanous                         const boost::system::error_code ec) {
512b01bf299SEd Tanous         if (ec)
513b01bf299SEd Tanous         {
514b01bf299SEd Tanous             messages::internalError(asyncResp->res);
515b01bf299SEd Tanous         }
516b01bf299SEd Tanous         else
517b01bf299SEd Tanous         {
518b01bf299SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
519b01bf299SEd Tanous         }
520b01bf299SEd Tanous     };
521b01bf299SEd Tanous 
522b01bf299SEd Tanous     crow::connections::systemBus->async_method_call(
523b01bf299SEd Tanous         std::move(callback), "xyz.openbmc_project.Network",
524b01bf299SEd Tanous         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
525b01bf299SEd Tanous         "org.freedesktop.DBus.Properties", "Set",
526b01bf299SEd Tanous         "xyz.openbmc_project.Network.IP", name,
527b01bf299SEd Tanous         std::variant<std::string>(newValue));
528b01bf299SEd Tanous }
529b01bf299SEd Tanous 
530b01bf299SEd Tanous /**
531179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
532179db1d7SKowalski, Kamil  *
533179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
5344a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5351abe55efSEd Tanous  * modified
536179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
537179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
538179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
539179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
540179db1d7SKowalski, Kamil  *
541179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
542179db1d7SKowalski, Kamil  * otherwise
543179db1d7SKowalski, Kamil  */
544b01bf299SEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5451abe55efSEd Tanous                              const std::string &ipHash,
5461abe55efSEd Tanous                              const std::string &newValue,
547179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5484a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5491abe55efSEd Tanous {
5504a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5511abe55efSEd Tanous                         const boost::system::error_code ec) {
5521abe55efSEd Tanous         if (ec)
5531abe55efSEd Tanous         {
554a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5551abe55efSEd Tanous         }
5561abe55efSEd Tanous         else
5571abe55efSEd Tanous         {
5584a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
559179db1d7SKowalski, Kamil                 newValue;
560179db1d7SKowalski, Kamil         }
561179db1d7SKowalski, Kamil     };
562179db1d7SKowalski, Kamil 
56355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
564179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
565179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
566179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
567179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
568abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
5694a0cb85cSEd Tanous }
570179db1d7SKowalski, Kamil 
571179db1d7SKowalski, Kamil /**
572179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
573179db1d7SKowalski, Kamil  *
574179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5754a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5761abe55efSEd Tanous  * modified
577179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
578179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
579179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
580179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
581179db1d7SKowalski, Kamil  *
582179db1d7SKowalski, Kamil  * @return None
583179db1d7SKowalski, Kamil  */
584b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5854a0cb85cSEd Tanous                                          const std::string &ipHash,
5864a0cb85cSEd Tanous                                          const std::string &newValueStr,
5874a0cb85cSEd Tanous                                          uint8_t &newValue,
5884a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5891abe55efSEd Tanous {
5904a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5911abe55efSEd Tanous                         const boost::system::error_code ec) {
5921abe55efSEd Tanous         if (ec)
5931abe55efSEd Tanous         {
594a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5951abe55efSEd Tanous         }
5961abe55efSEd Tanous         else
5971abe55efSEd Tanous         {
59855c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
599179db1d7SKowalski, Kamil                 newValueStr;
600179db1d7SKowalski, Kamil         }
601179db1d7SKowalski, Kamil     };
602179db1d7SKowalski, Kamil 
60355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
604179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
605179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
606179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
607179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
608abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
6094a0cb85cSEd Tanous }
610588c3f0dSKowalski, Kamil 
611588c3f0dSKowalski, Kamil /**
612179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
613179db1d7SKowalski, Kamil  *
614179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6154a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
616179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
617179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
618179db1d7SKowalski, Kamil  *
619179db1d7SKowalski, Kamil  * @return None
620179db1d7SKowalski, Kamil  */
6214a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
622179db1d7SKowalski, Kamil                        unsigned int ipIdx,
6234a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6241abe55efSEd Tanous {
62555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6264a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6271abe55efSEd Tanous             if (ec)
6281abe55efSEd Tanous             {
629a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6301abe55efSEd Tanous             }
6311abe55efSEd Tanous             else
6321abe55efSEd Tanous             {
63355c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
634179db1d7SKowalski, Kamil             }
635179db1d7SKowalski, Kamil         },
636179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
637179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
638179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
639179db1d7SKowalski, Kamil }
640179db1d7SKowalski, Kamil 
641179db1d7SKowalski, Kamil /**
642179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
643179db1d7SKowalski, Kamil  *
644179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6454a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
646179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
647179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
648179db1d7SKowalski, Kamil  *
649179db1d7SKowalski, Kamil  * @return None
650179db1d7SKowalski, Kamil  */
651b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
652b01bf299SEd Tanous                        uint8_t subnetMask, const std::string &gateway,
653b01bf299SEd Tanous                        const std::string &address,
6544a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6551abe55efSEd Tanous {
65643b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
6571abe55efSEd Tanous         if (ec)
6581abe55efSEd Tanous         {
659a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
660179db1d7SKowalski, Kamil         }
661179db1d7SKowalski, Kamil     };
662179db1d7SKowalski, Kamil 
66355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
664179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
665179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
666179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
667179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
668179db1d7SKowalski, Kamil         gateway);
669179db1d7SKowalski, Kamil }
6702a133282Smanojkiraneda using GetAllPropertiesType =
6712a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
6722a133282Smanojkiraneda 
6732a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
6742a133282Smanojkiraneda {
6752a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
6762a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
6772a133282Smanojkiraneda         if (error_code)
6782a133282Smanojkiraneda         {
6792a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
6802a133282Smanojkiraneda             messages::internalError(asyncResp->res);
6812a133282Smanojkiraneda             return;
6822a133282Smanojkiraneda         }
683fda13ad2SSunitha Harish         nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"];
6842a133282Smanojkiraneda         for (const auto &property : dbus_data)
6852a133282Smanojkiraneda         {
6862a133282Smanojkiraneda             auto value =
6872a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
6882a133282Smanojkiraneda 
6892a133282Smanojkiraneda             if (value == nullptr)
6902a133282Smanojkiraneda             {
6912a133282Smanojkiraneda                 continue;
6922a133282Smanojkiraneda             }
6932a133282Smanojkiraneda             if (property.first == "DNSEnabled")
6942a133282Smanojkiraneda             {
6952a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
6962a133282Smanojkiraneda             }
6972a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
6982a133282Smanojkiraneda             {
6992a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
7002a133282Smanojkiraneda             }
7012a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
7022a133282Smanojkiraneda             {
7032a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
7042a133282Smanojkiraneda             }
7052a133282Smanojkiraneda         }
7062a133282Smanojkiraneda     };
7072a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
7082a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
7092a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
7102a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
7112a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
7122a133282Smanojkiraneda }
713179db1d7SKowalski, Kamil 
714179db1d7SKowalski, Kamil /**
715179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
716179db1d7SKowalski, Kamil  * Object
717179db1d7SKowalski, Kamil  * from EntityManager Network Manager
7184a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
719179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
720179db1d7SKowalski, Kamil  * into JSON
721179db1d7SKowalski, Kamil  */
722179db1d7SKowalski, Kamil template <typename CallbackFunc>
7234a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
7241abe55efSEd Tanous                           CallbackFunc &&callback)
7251abe55efSEd Tanous {
72655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7274a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
7281abe55efSEd Tanous             const boost::system::error_code error_code,
7294a0cb85cSEd Tanous             const GetManagedObjects &resp) {
73055c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
7314a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
732179db1d7SKowalski, Kamil 
7331abe55efSEd Tanous             if (error_code)
7341abe55efSEd Tanous             {
73555c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
736179db1d7SKowalski, Kamil                 return;
737179db1d7SKowalski, Kamil             }
738179db1d7SKowalski, Kamil 
7394a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
7404a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
741179db1d7SKowalski, Kamil 
742179db1d7SKowalski, Kamil             // Fix global GW
7431abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
7441abe55efSEd Tanous             {
7454a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
7464a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
7471abe55efSEd Tanous                 {
7484a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
749179db1d7SKowalski, Kamil                 }
750179db1d7SKowalski, Kamil             }
751179db1d7SKowalski, Kamil 
7524a0cb85cSEd Tanous             // Finally make a callback with usefull data
75355c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
754179db1d7SKowalski, Kamil         },
755179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
756179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
757179db1d7SKowalski, Kamil };
758179db1d7SKowalski, Kamil 
759179db1d7SKowalski, Kamil /**
7609391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
7619391bb9cSRapkiewicz, Pawel  * Manager
7621abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
7631abe55efSEd Tanous  * into JSON.
7649391bb9cSRapkiewicz, Pawel  */
7659391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7661abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7671abe55efSEd Tanous {
76855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7694a0cb85cSEd Tanous         [callback{std::move(callback)}](
7709391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
7714a0cb85cSEd Tanous             GetManagedObjects &resp) {
7721abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7731abe55efSEd Tanous             // ethernet interfaces
7744a0cb85cSEd Tanous             std::vector<std::string> iface_list;
7754a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7761abe55efSEd Tanous             if (error_code)
7771abe55efSEd Tanous             {
7784a0cb85cSEd Tanous                 callback(false, iface_list);
7799391bb9cSRapkiewicz, Pawel                 return;
7809391bb9cSRapkiewicz, Pawel             }
7819391bb9cSRapkiewicz, Pawel 
7829391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7834a0cb85cSEd Tanous             for (const auto &objpath : resp)
7841abe55efSEd Tanous             {
7859391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7864a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7871abe55efSEd Tanous                 {
7881abe55efSEd Tanous                     // If interface is
7894a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
7904a0cb85cSEd Tanous                     // what we're looking for.
7919391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7921abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7931abe55efSEd Tanous                     {
7944a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
7954a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
7964a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
7974a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7981abe55efSEd Tanous                         {
7999391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
8004a0cb85cSEd Tanous                             iface_list.emplace_back(
8014a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
8029391bb9cSRapkiewicz, Pawel                         }
8039391bb9cSRapkiewicz, Pawel                     }
8049391bb9cSRapkiewicz, Pawel                 }
8059391bb9cSRapkiewicz, Pawel             }
806a434f2bdSEd Tanous             // Finally make a callback with useful data
8074a0cb85cSEd Tanous             callback(true, iface_list);
8089391bb9cSRapkiewicz, Pawel         },
809aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
810aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8119391bb9cSRapkiewicz, Pawel };
8129391bb9cSRapkiewicz, Pawel 
8139391bb9cSRapkiewicz, Pawel /**
8149391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
8159391bb9cSRapkiewicz, Pawel  */
8161abe55efSEd Tanous class EthernetCollection : public Node
8171abe55efSEd Tanous {
8189391bb9cSRapkiewicz, Pawel   public:
8194a0cb85cSEd Tanous     template <typename CrowApp>
8201abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
8214a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
8221abe55efSEd Tanous     {
823588c3f0dSKowalski, Kamil         entityPrivileges = {
824588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
825e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
826e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
827e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
828e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
829e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8309391bb9cSRapkiewicz, Pawel     }
8319391bb9cSRapkiewicz, Pawel 
8329391bb9cSRapkiewicz, Pawel   private:
8339391bb9cSRapkiewicz, Pawel     /**
8349391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8359391bb9cSRapkiewicz, Pawel      */
83655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
8371abe55efSEd Tanous                const std::vector<std::string> &params) override
8381abe55efSEd Tanous     {
8390f74e643SEd Tanous         res.jsonValue["@odata.type"] =
8400f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
8410f74e643SEd Tanous         res.jsonValue["@odata.context"] =
8420f74e643SEd Tanous             "/redfish/v1/"
8430f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
8440f74e643SEd Tanous         res.jsonValue["@odata.id"] =
8450f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
8460f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
8470f74e643SEd Tanous         res.jsonValue["Description"] =
8480f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
8490f74e643SEd Tanous 
8504a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
8511abe55efSEd Tanous         // preparation
852f12894f8SJason M. Bills         getEthernetIfaceList(
853f12894f8SJason M. Bills             [&res](const bool &success,
8541abe55efSEd Tanous                    const std::vector<std::string> &iface_list) {
8554a0cb85cSEd Tanous                 if (!success)
8561abe55efSEd Tanous                 {
857f12894f8SJason M. Bills                     messages::internalError(res);
8584a0cb85cSEd Tanous                     res.end();
8594a0cb85cSEd Tanous                     return;
8604a0cb85cSEd Tanous                 }
8614a0cb85cSEd Tanous 
8624a0cb85cSEd Tanous                 nlohmann::json &iface_array = res.jsonValue["Members"];
8634a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
864fda13ad2SSunitha Harish                 std::string tag = "_";
8654a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
8661abe55efSEd Tanous                 {
867fda13ad2SSunitha Harish                     std::size_t found = iface_item.find(tag);
868fda13ad2SSunitha Harish                     if (found == std::string::npos)
869fda13ad2SSunitha Harish                     {
8704a0cb85cSEd Tanous                         iface_array.push_back(
8714a0cb85cSEd Tanous                             {{"@odata.id",
8724a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
8734a0cb85cSEd Tanous                                   iface_item}});
8749391bb9cSRapkiewicz, Pawel                     }
875fda13ad2SSunitha Harish                 }
8764a0cb85cSEd Tanous 
8774a0cb85cSEd Tanous                 res.jsonValue["Members@odata.count"] = iface_array.size();
8784a0cb85cSEd Tanous                 res.jsonValue["@odata.id"] =
8794a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
8809391bb9cSRapkiewicz, Pawel                 res.end();
8819391bb9cSRapkiewicz, Pawel             });
8829391bb9cSRapkiewicz, Pawel     }
8839391bb9cSRapkiewicz, Pawel };
8849391bb9cSRapkiewicz, Pawel 
8859391bb9cSRapkiewicz, Pawel /**
8869391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8879391bb9cSRapkiewicz, Pawel  */
8881abe55efSEd Tanous class EthernetInterface : public Node
8891abe55efSEd Tanous {
8909391bb9cSRapkiewicz, Pawel   public:
8919391bb9cSRapkiewicz, Pawel     /*
8929391bb9cSRapkiewicz, Pawel      * Default Constructor
8939391bb9cSRapkiewicz, Pawel      */
8944a0cb85cSEd Tanous     template <typename CrowApp>
8951abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
8964a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8971abe55efSEd Tanous              std::string())
8981abe55efSEd Tanous     {
899588c3f0dSKowalski, Kamil         entityPrivileges = {
900588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
901e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
902e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
903e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
904e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
905e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
9069391bb9cSRapkiewicz, Pawel     }
9079391bb9cSRapkiewicz, Pawel 
908e439f0f8SKowalski, Kamil   private:
909bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
9104a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
9111abe55efSEd Tanous     {
912bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
913bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
914bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
9154a0cb85cSEd Tanous                 if (ec)
9164a0cb85cSEd Tanous                 {
917a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
9181abe55efSEd Tanous                 }
919bc0bd6e0SEd Tanous             },
920bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
921bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
922bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
923bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
924abf2add6SEd Tanous             std::variant<std::string>(hostname));
925588c3f0dSKowalski, Kamil     }
926588c3f0dSKowalski, Kamil 
927d577665bSRatan Gupta     void handleMACAddressPatch(const std::string &ifaceId,
928d577665bSRatan Gupta                                const std::string &macAddress,
929d577665bSRatan Gupta                                const std::shared_ptr<AsyncResp> &asyncResp)
930d577665bSRatan Gupta     {
931d577665bSRatan Gupta         crow::connections::systemBus->async_method_call(
932d577665bSRatan Gupta             [asyncResp, macAddress](const boost::system::error_code ec) {
933d577665bSRatan Gupta                 if (ec)
934d577665bSRatan Gupta                 {
935d577665bSRatan Gupta                     messages::internalError(asyncResp->res);
936d577665bSRatan Gupta                     return;
937d577665bSRatan Gupta                 }
938d577665bSRatan Gupta                 asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress);
939d577665bSRatan Gupta             },
940d577665bSRatan Gupta             "xyz.openbmc_project.Network",
941d577665bSRatan Gupta             "/xyz/openbmc_project/network/" + ifaceId,
942d577665bSRatan Gupta             "org.freedesktop.DBus.Properties", "Set",
943d577665bSRatan Gupta             "xyz.openbmc_project.Network.MACAddress", "MACAddress",
944d577665bSRatan Gupta             std::variant<std::string>(macAddress));
945d577665bSRatan Gupta     }
946d577665bSRatan Gupta 
9474a0cb85cSEd Tanous     void handleIPv4Patch(
948f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
9494a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
9504a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
9511abe55efSEd Tanous     {
952f476acbfSRatan Gupta         if (!input.is_array())
953f476acbfSRatan Gupta         {
954f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
955f476acbfSRatan Gupta                                              "IPv4Addresses");
956f476acbfSRatan Gupta             return;
957f476acbfSRatan Gupta         }
958f476acbfSRatan Gupta 
9594a0cb85cSEd Tanous         int entryIdx = 0;
9604a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
9614a0cb85cSEd Tanous             ipv4Data.begin();
962537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
9631abe55efSEd Tanous         {
9644a0cb85cSEd Tanous             std::string pathString =
965a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
966179db1d7SKowalski, Kamil 
967f476acbfSRatan Gupta             if (thisJson.is_null())
968f476acbfSRatan Gupta             {
969f476acbfSRatan Gupta                 if (thisData != ipv4Data.end())
970f476acbfSRatan Gupta                 {
971f476acbfSRatan Gupta                     deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
972f476acbfSRatan Gupta                     thisData++;
973f476acbfSRatan Gupta                 }
974f476acbfSRatan Gupta                 else
975f476acbfSRatan Gupta                 {
976f476acbfSRatan Gupta                     messages::propertyValueFormatError(
977f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
978f476acbfSRatan Gupta                     return;
979f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
980f476acbfSRatan Gupta                     // list and if unable to update one of the
981f476acbfSRatan Gupta                     // list value then should we proceed further or
982f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
983f476acbfSRatan Gupta                     // till then we stop processing the next list item.
984f476acbfSRatan Gupta                 }
985f476acbfSRatan Gupta                 entryIdx++;
986f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
987f476acbfSRatan Gupta             }
988f476acbfSRatan Gupta 
9899474b378SRatan Gupta             if (thisJson.empty())
9909474b378SRatan Gupta             {
9919474b378SRatan Gupta                 if (thisData != ipv4Data.end())
9929474b378SRatan Gupta                 {
9939474b378SRatan Gupta                     thisData++;
9949474b378SRatan Gupta                 }
9959474b378SRatan Gupta                 else
9969474b378SRatan Gupta                 {
9979474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
9989474b378SRatan Gupta                                               pathString + "/Address");
9999474b378SRatan Gupta                     return;
1000f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
10019474b378SRatan Gupta                     // list and if unable to update one of the
10029474b378SRatan Gupta                     // list value then should we proceed further or
10039474b378SRatan Gupta                     // break there, would ask in the redfish forum
10049474b378SRatan Gupta                     // till then we stop processing the next list item.
10059474b378SRatan Gupta                 }
10069474b378SRatan Gupta                 entryIdx++;
10079474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
10089474b378SRatan Gupta             }
10099474b378SRatan Gupta 
1010537174c4SEd Tanous             std::optional<std::string> address;
1011537174c4SEd Tanous             std::optional<std::string> addressOrigin;
1012537174c4SEd Tanous             std::optional<std::string> subnetMask;
1013537174c4SEd Tanous             std::optional<std::string> gateway;
1014537174c4SEd Tanous 
1015537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1016537174c4SEd Tanous                                      address, "AddressOrigin", addressOrigin,
1017537174c4SEd Tanous                                      "SubnetMask", subnetMask, "Gateway",
1018537174c4SEd Tanous                                      gateway))
1019537174c4SEd Tanous             {
1020537174c4SEd Tanous                 return;
1021179db1d7SKowalski, Kamil             }
1022179db1d7SKowalski, Kamil 
1023537174c4SEd Tanous             if (address)
10241abe55efSEd Tanous             {
1025537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
10261abe55efSEd Tanous                 {
1027537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
10284a0cb85cSEd Tanous                                                        pathString + "/Address");
1029537174c4SEd Tanous                     return;
10304a0cb85cSEd Tanous                 }
10314a0cb85cSEd Tanous             }
10324a0cb85cSEd Tanous 
1033537174c4SEd Tanous             uint8_t prefixLength = 0;
1034537174c4SEd Tanous             if (subnetMask)
10354a0cb85cSEd Tanous             {
1036537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
10374a0cb85cSEd Tanous                 {
1038f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1039537174c4SEd Tanous                         asyncResp->res, *subnetMask,
10404a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1041537174c4SEd Tanous                     return;
10424a0cb85cSEd Tanous                 }
10434a0cb85cSEd Tanous             }
10444a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
1045537174c4SEd Tanous             if (addressOrigin)
10464a0cb85cSEd Tanous             {
10474a0cb85cSEd Tanous                 // Get Address origin in proper format
10484a0cb85cSEd Tanous                 addressOriginInDBusFormat =
1049537174c4SEd Tanous                     translateAddressOriginRedfishToDbus(*addressOrigin);
10504a0cb85cSEd Tanous                 if (addressOriginInDBusFormat.empty())
10514a0cb85cSEd Tanous                 {
10524a0cb85cSEd Tanous                     messages::propertyValueNotInList(
1053537174c4SEd Tanous                         asyncResp->res, *addressOrigin,
1054a08b46ccSJason M. Bills                         pathString + "/AddressOrigin");
1055537174c4SEd Tanous                     return;
10564a0cb85cSEd Tanous                 }
10574a0cb85cSEd Tanous             }
10584a0cb85cSEd Tanous 
1059537174c4SEd Tanous             if (gateway)
10604a0cb85cSEd Tanous             {
1061537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
10624a0cb85cSEd Tanous                 {
1063537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1064537174c4SEd Tanous                                                        pathString + "/Gateway");
1065537174c4SEd Tanous                     return;
10664a0cb85cSEd Tanous                 }
10674a0cb85cSEd Tanous             }
10684a0cb85cSEd Tanous 
1069f476acbfSRatan Gupta             // if IP address exist then  modify it.
10704a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
10714a0cb85cSEd Tanous             {
1072179db1d7SKowalski, Kamil                 // Apply changes
1073537174c4SEd Tanous                 if (address)
10741abe55efSEd Tanous                 {
1075f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1076f476acbfSRatan Gupta                                      address{std::string(*address)}](
10774a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
10784a0cb85cSEd Tanous                         if (ec)
10791abe55efSEd Tanous                         {
1080a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
10814a0cb85cSEd Tanous                             return;
10824a0cb85cSEd Tanous                         }
1083f476acbfSRatan Gupta                         asyncResp->res
1084f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1085f476acbfSRatan Gupta                             std::move(address);
10864a0cb85cSEd Tanous                     };
10874a0cb85cSEd Tanous 
10884a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
10894a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1090f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1091f476acbfSRatan Gupta                             thisData->id,
10924a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
10934a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1094537174c4SEd Tanous                         std::variant<std::string>(*address));
1095179db1d7SKowalski, Kamil                 }
1096179db1d7SKowalski, Kamil 
1097537174c4SEd Tanous                 if (subnetMask)
10981abe55efSEd Tanous                 {
10994a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1100537174c4SEd Tanous                                                  thisData->id, *subnetMask,
1101537174c4SEd Tanous                                                  prefixLength, asyncResp);
1102179db1d7SKowalski, Kamil                 }
1103179db1d7SKowalski, Kamil 
1104537174c4SEd Tanous                 if (addressOrigin)
11051abe55efSEd Tanous                 {
11064a0cb85cSEd Tanous                     changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1107f476acbfSRatan Gupta                                      *addressOrigin, addressOriginInDBusFormat,
1108f476acbfSRatan Gupta                                      asyncResp);
1109179db1d7SKowalski, Kamil                 }
1110179db1d7SKowalski, Kamil 
1111537174c4SEd Tanous                 if (gateway)
11121abe55efSEd Tanous                 {
1113f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1114537174c4SEd Tanous                                      gateway{std::string(*gateway)}](
11154a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
11164a0cb85cSEd Tanous                         if (ec)
11171abe55efSEd Tanous                         {
1118a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
11194a0cb85cSEd Tanous                             return;
11204a0cb85cSEd Tanous                         }
1121f476acbfSRatan Gupta                         asyncResp->res
1122f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1123537174c4SEd Tanous                             std::move(gateway);
11244a0cb85cSEd Tanous                     };
11254a0cb85cSEd Tanous 
11264a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
11274a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1128f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1129f476acbfSRatan Gupta                             thisData->id,
11304a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
11314a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1132537174c4SEd Tanous                         std::variant<std::string>(*gateway));
11334a0cb85cSEd Tanous                 }
1134f476acbfSRatan Gupta 
11354a0cb85cSEd Tanous                 thisData++;
11361abe55efSEd Tanous             }
11371abe55efSEd Tanous             else
11381abe55efSEd Tanous             {
11394a0cb85cSEd Tanous                 // Create IPv4 with provided data
1140537174c4SEd Tanous                 if (!gateway)
11411abe55efSEd Tanous                 {
1142a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11434a0cb85cSEd Tanous                                               pathString + "/Gateway");
11444a0cb85cSEd Tanous                     continue;
11454a0cb85cSEd Tanous                 }
11464a0cb85cSEd Tanous 
1147537174c4SEd Tanous                 if (!address)
11481abe55efSEd Tanous                 {
1149a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11504a0cb85cSEd Tanous                                               pathString + "/Address");
11514a0cb85cSEd Tanous                     continue;
11524a0cb85cSEd Tanous                 }
11534a0cb85cSEd Tanous 
1154537174c4SEd Tanous                 if (!subnetMask)
11551abe55efSEd Tanous                 {
1156a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11574a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
11584a0cb85cSEd Tanous                     continue;
1159588c3f0dSKowalski, Kamil                 }
1160588c3f0dSKowalski, Kamil 
1161b01bf299SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1162b01bf299SEd Tanous                            asyncResp);
116395897b20SRatan Gupta 
116495897b20SRatan Gupta                 nlohmann::json &ipv4AddressJson =
116595897b20SRatan Gupta                     asyncResp->res.jsonValue["IPv4Addresses"][entryIdx];
116695897b20SRatan Gupta                 ipv4AddressJson["Address"] = *address;
116795897b20SRatan Gupta                 ipv4AddressJson["SubnetMask"] = *subnetMask;
116895897b20SRatan Gupta                 ipv4AddressJson["Gateway"] = *gateway;
11694a0cb85cSEd Tanous             }
11704a0cb85cSEd Tanous             entryIdx++;
11714a0cb85cSEd Tanous         }
11724a0cb85cSEd Tanous     }
11734a0cb85cSEd Tanous 
1174f85837bfSRAJESWARAN THILLAIGOVINDAN     void handleStaticNameServersPatch(
1175f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::string &ifaceId,
1176f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::vector<std::string> &updatedStaticNameServers,
1177f85837bfSRAJESWARAN THILLAIGOVINDAN         const std::shared_ptr<AsyncResp> &asyncResp)
1178f85837bfSRAJESWARAN THILLAIGOVINDAN     {
1179f85837bfSRAJESWARAN THILLAIGOVINDAN         crow::connections::systemBus->async_method_call(
1180f85837bfSRAJESWARAN THILLAIGOVINDAN             [asyncResp,
1181f85837bfSRAJESWARAN THILLAIGOVINDAN              updatedStaticNameServers](const boost::system::error_code ec) {
1182f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (ec)
1183f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1184f85837bfSRAJESWARAN THILLAIGOVINDAN                     messages::internalError(asyncResp->res);
1185f85837bfSRAJESWARAN THILLAIGOVINDAN                     return;
1186f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1187f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["NameServers"] =
1188f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1189f85837bfSRAJESWARAN THILLAIGOVINDAN                 asyncResp->res.jsonValue["StaticNameServers"] =
1190f85837bfSRAJESWARAN THILLAIGOVINDAN                     updatedStaticNameServers;
1191f85837bfSRAJESWARAN THILLAIGOVINDAN             },
1192f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network",
1193f85837bfSRAJESWARAN THILLAIGOVINDAN             "/xyz/openbmc_project/network/" + ifaceId,
1194f85837bfSRAJESWARAN THILLAIGOVINDAN             "org.freedesktop.DBus.Properties", "Set",
1195f85837bfSRAJESWARAN THILLAIGOVINDAN             "xyz.openbmc_project.Network.EthernetInterface", "Nameservers",
1196f85837bfSRAJESWARAN THILLAIGOVINDAN             std::variant<std::vector<std::string>>{updatedStaticNameServers});
1197f85837bfSRAJESWARAN THILLAIGOVINDAN     }
1198f85837bfSRAJESWARAN THILLAIGOVINDAN 
11990f74e643SEd Tanous     void parseInterfaceData(
12000f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
12010f74e643SEd Tanous         const EthernetInterfaceData &ethData,
12024a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
12034a0cb85cSEd Tanous     {
12044a0cb85cSEd Tanous         json_response["Id"] = iface_id;
12054a0cb85cSEd Tanous         json_response["@odata.id"] =
12064a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1207029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1208029573d4SEd Tanous         if (ethData.speed == 0)
1209029573d4SEd Tanous         {
1210029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1211029573d4SEd Tanous             json_response["Status"] = {
1212029573d4SEd Tanous                 {"Health", "OK"},
1213029573d4SEd Tanous                 {"State", "Disabled"},
1214029573d4SEd Tanous             };
1215029573d4SEd Tanous         }
1216029573d4SEd Tanous         else
1217029573d4SEd Tanous         {
1218029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1219029573d4SEd Tanous             json_response["Status"] = {
1220029573d4SEd Tanous                 {"Health", "OK"},
1221029573d4SEd Tanous                 {"State", "Enabled"},
1222029573d4SEd Tanous             };
1223029573d4SEd Tanous         }
12244a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
12254a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
1226fda13ad2SSunitha Harish         json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled;
12272a133282Smanojkiraneda 
12284a0cb85cSEd Tanous         if (!ethData.hostname.empty())
12294a0cb85cSEd Tanous         {
12304a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
12314a0cb85cSEd Tanous         }
12324a0cb85cSEd Tanous 
1233fda13ad2SSunitha Harish         json_response["VLANs"] = {
1234fda13ad2SSunitha Harish             {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
1235fda13ad2SSunitha Harish                               iface_id + "/VLANs"}};
1236fda13ad2SSunitha Harish 
1237029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
1238f85837bfSRAJESWARAN THILLAIGOVINDAN         json_response["StaticNameServers"] = ethData.nameservers;
12394a0cb85cSEd Tanous 
12404a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
12414a0cb85cSEd Tanous         {
12424a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
12434a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
12444a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
12454a0cb85cSEd Tanous             {
1246fa5053a6SGunnar Mills 
1247fa5053a6SGunnar Mills                 std::string gatewayStr = ipv4_config.gateway;
1248fa5053a6SGunnar Mills                 if (gatewayStr.empty())
1249fa5053a6SGunnar Mills                 {
1250fa5053a6SGunnar Mills                     gatewayStr = "0.0.0.0";
1251fa5053a6SGunnar Mills                 }
1252fa5053a6SGunnar Mills 
12534a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
12544a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1255029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1256fa5053a6SGunnar Mills                                       {"Gateway", gatewayStr}});
12574a0cb85cSEd Tanous             }
12584a0cb85cSEd Tanous         }
1259*9a6fc6feSRavi Teja         json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway;
1260588c3f0dSKowalski, Kamil     }
1261588c3f0dSKowalski, Kamil 
12629391bb9cSRapkiewicz, Pawel     /**
12639391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
12649391bb9cSRapkiewicz, Pawel      */
126555c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
12661abe55efSEd Tanous                const std::vector<std::string> &params) override
12671abe55efSEd Tanous     {
12684a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12691abe55efSEd Tanous         if (params.size() != 1)
12701abe55efSEd Tanous         {
1271f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
12729391bb9cSRapkiewicz, Pawel             return;
12739391bb9cSRapkiewicz, Pawel         }
12749391bb9cSRapkiewicz, Pawel 
12754a0cb85cSEd Tanous         getEthernetIfaceData(
12764a0cb85cSEd Tanous             params[0],
12774a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
12784a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
12794a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
12804a0cb85cSEd Tanous                 if (!success)
12811abe55efSEd Tanous                 {
12821abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
12831abe55efSEd Tanous                     // object, and other errors
1284f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1285f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
12864a0cb85cSEd Tanous                     return;
12879391bb9cSRapkiewicz, Pawel                 }
12880f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
1289fda13ad2SSunitha Harish                     "#EthernetInterface.v1_4_1.EthernetInterface";
12900f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
12910f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
12920f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
12930f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
12940f74e643SEd Tanous                     "Management Network Interface";
12950f74e643SEd Tanous 
12960f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
12970f74e643SEd Tanous                                    ipv4Data);
12989391bb9cSRapkiewicz, Pawel             });
12992a133282Smanojkiraneda         getDHCPConfigData(asyncResp);
13009391bb9cSRapkiewicz, Pawel     }
13019391bb9cSRapkiewicz, Pawel 
130255c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
13031abe55efSEd Tanous                  const std::vector<std::string> &params) override
13041abe55efSEd Tanous     {
13054a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13061abe55efSEd Tanous         if (params.size() != 1)
13071abe55efSEd Tanous         {
1308f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1309588c3f0dSKowalski, Kamil             return;
1310588c3f0dSKowalski, Kamil         }
1311588c3f0dSKowalski, Kamil 
13124a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1313588c3f0dSKowalski, Kamil 
1314bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1315d577665bSRatan Gupta         std::optional<std::string> macAddress;
1316*9a6fc6feSRavi Teja         std::optional<std::string> ipv6DefaultGateway;
1317f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1318f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
1319f85837bfSRAJESWARAN THILLAIGOVINDAN         std::optional<std::vector<std::string>> staticNameServers;
13200627a2c7SEd Tanous 
1321fda13ad2SSunitha Harish         if (!json_util::readJson(
1322fda13ad2SSunitha Harish                 req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses,
1323f85837bfSRAJESWARAN THILLAIGOVINDAN                 "IPv6Addresses", ipv6Addresses, "MACAddress", macAddress,
1324*9a6fc6feSRavi Teja                 "StaticNameServers", staticNameServers, "IPv6DefaultGateway",
1325*9a6fc6feSRavi Teja                 ipv6DefaultGateway))
13261abe55efSEd Tanous         {
1327588c3f0dSKowalski, Kamil             return;
1328588c3f0dSKowalski, Kamil         }
1329f15aad37SRatan Gupta 
13304a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1331588c3f0dSKowalski, Kamil         // preparation
13324a0cb85cSEd Tanous         getEthernetIfaceData(
13334a0cb85cSEd Tanous             iface_id,
1334fda13ad2SSunitha Harish             [this, asyncResp, iface_id, hostname = std::move(hostname),
1335fda13ad2SSunitha Harish              macAddress = std::move(macAddress),
13360627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
1337f85837bfSRAJESWARAN THILLAIGOVINDAN              ipv6Addresses = std::move(ipv6Addresses),
1338*9a6fc6feSRavi Teja              ipv6DefaultGateway = std::move(ipv6DefaultGateway),
1339f85837bfSRAJESWARAN THILLAIGOVINDAN              staticNameServers = std::move(staticNameServers)](
13404a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13414a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13421abe55efSEd Tanous                 if (!success)
13431abe55efSEd Tanous                 {
1344588c3f0dSKowalski, Kamil                     // ... otherwise return error
13451abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13461abe55efSEd Tanous                     // object, and other errors
1347fda13ad2SSunitha Harish                     messages::resourceNotFound(asyncResp->res,
1348fda13ad2SSunitha Harish                                                "Ethernet Interface", iface_id);
1349588c3f0dSKowalski, Kamil                     return;
1350588c3f0dSKowalski, Kamil                 }
1351588c3f0dSKowalski, Kamil 
13520f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
13530f74e643SEd Tanous                                    ipv4Data);
1354588c3f0dSKowalski, Kamil 
13550627a2c7SEd Tanous                 if (hostname)
13561abe55efSEd Tanous                 {
13570627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
13581abe55efSEd Tanous                 }
13590627a2c7SEd Tanous 
1360d577665bSRatan Gupta                 if (macAddress)
1361d577665bSRatan Gupta                 {
1362d577665bSRatan Gupta                     handleMACAddressPatch(iface_id, *macAddress, asyncResp);
1363d577665bSRatan Gupta                 }
1364d577665bSRatan Gupta 
13650627a2c7SEd Tanous                 if (ipv4Addresses)
13661abe55efSEd Tanous                 {
1367537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1368537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1369537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1370537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1371537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1372537174c4SEd Tanous                     // on that, but could be done more efficiently
1373f476acbfSRatan Gupta                     nlohmann::json ipv4 = std::move(*ipv4Addresses);
1374537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
13751abe55efSEd Tanous                 }
13760627a2c7SEd Tanous 
13770627a2c7SEd Tanous                 if (ipv6Addresses)
13781abe55efSEd Tanous                 {
1379179db1d7SKowalski, Kamil                     // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1380a08b46ccSJason M. Bills                     messages::propertyNotWritable(asyncResp->res,
13810627a2c7SEd Tanous                                                   "IPv6Addresses");
1382588c3f0dSKowalski, Kamil                 }
1383f85837bfSRAJESWARAN THILLAIGOVINDAN 
1384f85837bfSRAJESWARAN THILLAIGOVINDAN                 if (staticNameServers)
1385f85837bfSRAJESWARAN THILLAIGOVINDAN                 {
1386f85837bfSRAJESWARAN THILLAIGOVINDAN                     handleStaticNameServersPatch(iface_id, *staticNameServers,
1387f85837bfSRAJESWARAN THILLAIGOVINDAN                                                  asyncResp);
1388f85837bfSRAJESWARAN THILLAIGOVINDAN                 }
1389*9a6fc6feSRavi Teja 
1390*9a6fc6feSRavi Teja                 if (ipv6DefaultGateway)
1391*9a6fc6feSRavi Teja                 {
1392*9a6fc6feSRavi Teja                     messages::propertyNotWritable(asyncResp->res,
1393*9a6fc6feSRavi Teja                                                   "IPv6DefaultGateway");
1394*9a6fc6feSRavi Teja                 }
1395588c3f0dSKowalski, Kamil             });
1396588c3f0dSKowalski, Kamil     }
13979391bb9cSRapkiewicz, Pawel };
13989391bb9cSRapkiewicz, Pawel 
1399e439f0f8SKowalski, Kamil /**
14004a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
14014a0cb85cSEd Tanous  * Schema
1402e439f0f8SKowalski, Kamil  */
14031abe55efSEd Tanous class VlanNetworkInterface : public Node
14041abe55efSEd Tanous {
1405e439f0f8SKowalski, Kamil   public:
1406e439f0f8SKowalski, Kamil     /*
1407e439f0f8SKowalski, Kamil      * Default Constructor
1408e439f0f8SKowalski, Kamil      */
1409e439f0f8SKowalski, Kamil     template <typename CrowApp>
14101abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
14114a0cb85cSEd Tanous         Node(app,
14120f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
14131abe55efSEd Tanous              std::string(), std::string())
14141abe55efSEd Tanous     {
1415e439f0f8SKowalski, Kamil         entityPrivileges = {
1416e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1417e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1418e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1419e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1420e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1421e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1422e439f0f8SKowalski, Kamil     }
1423e439f0f8SKowalski, Kamil 
1424e439f0f8SKowalski, Kamil   private:
14250f74e643SEd Tanous     void parseInterfaceData(
14260f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
14270f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
14284a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
14291abe55efSEd Tanous     {
1430e439f0f8SKowalski, Kamil         // Fill out obvious data...
14314a0cb85cSEd Tanous         json_response["Id"] = iface_id;
14324a0cb85cSEd Tanous         json_response["@odata.id"] =
14334a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
14344a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1435e439f0f8SKowalski, Kamil 
14364a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
1437fda13ad2SSunitha Harish         if (!ethData.vlan_id.empty())
14384a0cb85cSEd Tanous         {
1439fda13ad2SSunitha Harish             json_response["VLANId"] = ethData.vlan_id.back();
14404a0cb85cSEd Tanous         }
1441e439f0f8SKowalski, Kamil     }
1442e439f0f8SKowalski, Kamil 
1443fda13ad2SSunitha Harish     bool verifyNames(const std::string &parent, const std::string &iface)
14441abe55efSEd Tanous     {
14451abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
14461abe55efSEd Tanous         {
1447927a505aSKowalski, Kamil             return false;
14481abe55efSEd Tanous         }
14491abe55efSEd Tanous         else
14501abe55efSEd Tanous         {
1451927a505aSKowalski, Kamil             return true;
1452927a505aSKowalski, Kamil         }
1453927a505aSKowalski, Kamil     }
1454927a505aSKowalski, Kamil 
1455e439f0f8SKowalski, Kamil     /**
1456e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1457e439f0f8SKowalski, Kamil      */
145855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
14591abe55efSEd Tanous                const std::vector<std::string> &params) override
14601abe55efSEd Tanous     {
14614a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14624a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1463e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1464e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1465e439f0f8SKowalski, Kamil         // impossible.
14661abe55efSEd Tanous         if (params.size() != 2)
14671abe55efSEd Tanous         {
1468f12894f8SJason M. Bills             messages::internalError(res);
1469e439f0f8SKowalski, Kamil             res.end();
1470e439f0f8SKowalski, Kamil             return;
1471e439f0f8SKowalski, Kamil         }
1472e439f0f8SKowalski, Kamil 
14734a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
14744a0cb85cSEd Tanous         const std::string &iface_id = params[1];
14750f74e643SEd Tanous         res.jsonValue["@odata.type"] =
14760f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
14770f74e643SEd Tanous         res.jsonValue["@odata.context"] =
14780f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
14790f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1480e439f0f8SKowalski, Kamil 
1481fda13ad2SSunitha Harish         if (!verifyNames(parent_iface_id, iface_id))
14821abe55efSEd Tanous         {
1483a434f2bdSEd Tanous             return;
1484a434f2bdSEd Tanous         }
1485a434f2bdSEd Tanous 
1486e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1487e439f0f8SKowalski, Kamil         // preparation
14884a0cb85cSEd Tanous         getEthernetIfaceData(
1489fda13ad2SSunitha Harish             params[1],
1490fda13ad2SSunitha Harish             [this, asyncResp, parent_iface_id{std::string(params[0])},
1491fda13ad2SSunitha Harish              iface_id{std::string(params[1])}](
14924a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14934a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1494fda13ad2SSunitha Harish                 if (success && ethData.vlan_id.size() != 0)
14951abe55efSEd Tanous                 {
14960f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
14970f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
14980f74e643SEd Tanous                                        ipv4Data);
14991abe55efSEd Tanous                 }
15001abe55efSEd Tanous                 else
15011abe55efSEd Tanous                 {
1502e439f0f8SKowalski, Kamil                     // ... otherwise return error
15031abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15041abe55efSEd Tanous                     // object, and other errors
1505f12894f8SJason M. Bills                     messages::resourceNotFound(
1506f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1507e439f0f8SKowalski, Kamil                 }
1508e439f0f8SKowalski, Kamil             });
1509e439f0f8SKowalski, Kamil     }
1510e439f0f8SKowalski, Kamil 
151155c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
15121abe55efSEd Tanous                  const std::vector<std::string> &params) override
15131abe55efSEd Tanous     {
15144a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15151abe55efSEd Tanous         if (params.size() != 2)
15161abe55efSEd Tanous         {
1517f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1518e439f0f8SKowalski, Kamil             return;
1519e439f0f8SKowalski, Kamil         }
1520e439f0f8SKowalski, Kamil 
1521d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
152255c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1523927a505aSKowalski, Kamil 
1524fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
15251abe55efSEd Tanous         {
1526fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1527fda13ad2SSunitha Harish                                        ifaceId);
1528927a505aSKowalski, Kamil             return;
1529927a505aSKowalski, Kamil         }
1530927a505aSKowalski, Kamil 
15310627a2c7SEd Tanous         bool vlanEnable = false;
15320627a2c7SEd Tanous         uint64_t vlanId = 0;
15330627a2c7SEd Tanous 
15340627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
15350627a2c7SEd Tanous                                  vlanId))
15361abe55efSEd Tanous         {
1537927a505aSKowalski, Kamil             return;
1538927a505aSKowalski, Kamil         }
1539927a505aSKowalski, Kamil 
1540927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1541927a505aSKowalski, Kamil         // preparation
154208244d02SSunitha Harish         getEthernetIfaceData(params[1], [this, asyncResp,
154308244d02SSunitha Harish                                          parentIfaceId{std::string(params[0])},
154408244d02SSunitha Harish                                          ifaceId{std::string(params[1])},
154508244d02SSunitha Harish                                          &vlanEnable, &vlanId](
154608244d02SSunitha Harish                                             const bool &success,
154708244d02SSunitha Harish                                             const EthernetInterfaceData
154808244d02SSunitha Harish                                                 &ethData,
154908244d02SSunitha Harish                                             const boost::container::flat_set<
155008244d02SSunitha Harish                                                 IPv4AddressData> &ipv4Data) {
155108244d02SSunitha Harish             if (success && !ethData.vlan_id.empty())
155208244d02SSunitha Harish             {
155308244d02SSunitha Harish                 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
155408244d02SSunitha Harish                                    ifaceId, ethData, ipv4Data);
155508244d02SSunitha Harish                 auto callback =
155608244d02SSunitha Harish                     [asyncResp](const boost::system::error_code ec) {
155708244d02SSunitha Harish                         if (ec)
155808244d02SSunitha Harish                         {
155908244d02SSunitha Harish                             messages::internalError(asyncResp->res);
156008244d02SSunitha Harish                         }
156108244d02SSunitha Harish                     };
156208244d02SSunitha Harish 
156308244d02SSunitha Harish                 if (vlanEnable == true)
156408244d02SSunitha Harish                 {
156508244d02SSunitha Harish                     crow::connections::systemBus->async_method_call(
156608244d02SSunitha Harish                         std::move(callback), "xyz.openbmc_project.Network",
156708244d02SSunitha Harish                         "/xyz/openbmc_project/network/" + ifaceId,
156808244d02SSunitha Harish                         "org.freedesktop.DBus.Properties", "Set",
156908244d02SSunitha Harish                         "xyz.openbmc_project.Network.VLAN", "Id",
157008244d02SSunitha Harish                         std::variant<uint32_t>(vlanId));
157108244d02SSunitha Harish                 }
157208244d02SSunitha Harish                 else
157308244d02SSunitha Harish                 {
157408244d02SSunitha Harish                     BMCWEB_LOG_DEBUG
157508244d02SSunitha Harish                         << "vlanEnable is false. Deleting the vlan interface";
157608244d02SSunitha Harish                     crow::connections::systemBus->async_method_call(
157708244d02SSunitha Harish                         std::move(callback), "xyz.openbmc_project.Network",
157808244d02SSunitha Harish                         std::string("/xyz/openbmc_project/network/") + ifaceId,
157908244d02SSunitha Harish                         "xyz.openbmc_project.Object.Delete", "Delete");
158008244d02SSunitha Harish                 }
158108244d02SSunitha Harish             }
158208244d02SSunitha Harish             else
15831abe55efSEd Tanous             {
15841abe55efSEd Tanous                 // TODO(Pawel)consider distinguish between non existing
15851abe55efSEd Tanous                 // object, and other errors
158608244d02SSunitha Harish                 messages::resourceNotFound(asyncResp->res,
158708244d02SSunitha Harish                                            "VLAN Network Interface", ifaceId);
1588927a505aSKowalski, Kamil                 return;
1589927a505aSKowalski, Kamil             }
1590927a505aSKowalski, Kamil         });
1591e439f0f8SKowalski, Kamil     }
1592e439f0f8SKowalski, Kamil 
159355c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
15941abe55efSEd Tanous                   const std::vector<std::string> &params) override
15951abe55efSEd Tanous     {
15964a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15971abe55efSEd Tanous         if (params.size() != 2)
15981abe55efSEd Tanous         {
1599f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1600e439f0f8SKowalski, Kamil             return;
1601e439f0f8SKowalski, Kamil         }
1602e439f0f8SKowalski, Kamil 
1603d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
160455c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1605927a505aSKowalski, Kamil 
1606fda13ad2SSunitha Harish         if (!verifyNames(parentIfaceId, ifaceId))
16071abe55efSEd Tanous         {
1608fda13ad2SSunitha Harish             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1609fda13ad2SSunitha Harish                                        ifaceId);
1610927a505aSKowalski, Kamil             return;
1611927a505aSKowalski, Kamil         }
1612927a505aSKowalski, Kamil 
1613927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1614927a505aSKowalski, Kamil         // preparation
1615f12894f8SJason M. Bills         getEthernetIfaceData(
1616fda13ad2SSunitha Harish             params[1],
1617fda13ad2SSunitha Harish             [this, asyncResp, parentIfaceId{std::string(params[0])},
1618fda13ad2SSunitha Harish              ifaceId{std::string(params[1])}](
1619f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1620f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
1621fda13ad2SSunitha Harish                 if (success && !ethData.vlan_id.empty())
16221abe55efSEd Tanous                 {
16230f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
16240f74e643SEd Tanous                                        ifaceId, ethData, ipv4Data);
1625927a505aSKowalski, Kamil 
1626f12894f8SJason M. Bills                     auto callback =
1627f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
16281abe55efSEd Tanous                             if (ec)
16291abe55efSEd Tanous                             {
1630f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1631927a505aSKowalski, Kamil                             }
16324a0cb85cSEd Tanous                         };
16334a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
16344a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
16354a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
16364a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
16371abe55efSEd Tanous                 }
16381abe55efSEd Tanous                 else
16391abe55efSEd Tanous                 {
1640927a505aSKowalski, Kamil                     // ... otherwise return error
1641f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1642f12894f8SJason M. Bills                     // object, and other errors
1643f12894f8SJason M. Bills                     messages::resourceNotFound(
1644f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1645927a505aSKowalski, Kamil                 }
1646927a505aSKowalski, Kamil             });
1647e439f0f8SKowalski, Kamil     }
1648e439f0f8SKowalski, Kamil };
1649e439f0f8SKowalski, Kamil 
1650e439f0f8SKowalski, Kamil /**
1651e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1652e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1653e439f0f8SKowalski, Kamil  */
16541abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
16551abe55efSEd Tanous {
1656e439f0f8SKowalski, Kamil   public:
1657e439f0f8SKowalski, Kamil     template <typename CrowApp>
16581abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
16594a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
16604a0cb85cSEd Tanous              std::string())
16611abe55efSEd Tanous     {
1662e439f0f8SKowalski, Kamil         entityPrivileges = {
1663e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1664e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1665e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1666e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1667e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1668e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1669e439f0f8SKowalski, Kamil     }
1670e439f0f8SKowalski, Kamil 
1671e439f0f8SKowalski, Kamil   private:
1672e439f0f8SKowalski, Kamil     /**
1673e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1674e439f0f8SKowalski, Kamil      */
167555c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
16761abe55efSEd Tanous                const std::vector<std::string> &params) override
16771abe55efSEd Tanous     {
16784a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16791abe55efSEd Tanous         if (params.size() != 1)
16801abe55efSEd Tanous         {
1681e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1682f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1683e439f0f8SKowalski, Kamil             return;
1684e439f0f8SKowalski, Kamil         }
1685e439f0f8SKowalski, Kamil 
16864a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1687e439f0f8SKowalski, Kamil 
16884a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
16891abe55efSEd Tanous         // preparation
1690f12894f8SJason M. Bills         getEthernetIfaceList(
169143b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
16921abe55efSEd Tanous                 const bool &success,
16931abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
16944a0cb85cSEd Tanous                 if (!success)
16951abe55efSEd Tanous                 {
1696f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
16974a0cb85cSEd Tanous                     return;
16981abe55efSEd Tanous                 }
16990f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
17000f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
17010f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
17020f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
17030f74e643SEd Tanous                     "/redfish/v1/$metadata"
17040f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
17050f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
17060f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
17070f74e643SEd Tanous                     "VLAN Network Interface Collection";
17084a0cb85cSEd Tanous 
17094a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
17104a0cb85cSEd Tanous 
17114a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
17121abe55efSEd Tanous                 {
17134a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
17144a0cb85cSEd Tanous                     {
17154a0cb85cSEd Tanous                         iface_array.push_back(
17164a0cb85cSEd Tanous                             {{"@odata.id",
17174a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
17184a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1719e439f0f8SKowalski, Kamil                     }
1720e439f0f8SKowalski, Kamil                 }
1721e439f0f8SKowalski, Kamil 
17224a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
17234a0cb85cSEd Tanous                     iface_array.size();
17244a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
17254a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
17264a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
17274a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1728e439f0f8SKowalski, Kamil             });
1729e439f0f8SKowalski, Kamil     }
1730e439f0f8SKowalski, Kamil 
173155c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
17321abe55efSEd Tanous                 const std::vector<std::string> &params) override
17331abe55efSEd Tanous     {
17344a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17351abe55efSEd Tanous         if (params.size() != 1)
17361abe55efSEd Tanous         {
1737f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1738e439f0f8SKowalski, Kamil             return;
1739e439f0f8SKowalski, Kamil         }
1740fda13ad2SSunitha Harish         bool vlanEnable = false;
17410627a2c7SEd Tanous         uint32_t vlanId = 0;
1742fda13ad2SSunitha Harish         if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable",
1743fda13ad2SSunitha Harish                                  vlanEnable))
17441abe55efSEd Tanous         {
17454a0cb85cSEd Tanous             return;
1746e439f0f8SKowalski, Kamil         }
1747fda13ad2SSunitha Harish         // Need both vlanId and vlanEnable to service this request
1748fda13ad2SSunitha Harish         if (!vlanId)
1749fda13ad2SSunitha Harish         {
1750fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANId");
1751fda13ad2SSunitha Harish         }
1752fda13ad2SSunitha Harish         if (!vlanEnable)
1753fda13ad2SSunitha Harish         {
1754fda13ad2SSunitha Harish             messages::propertyMissing(asyncResp->res, "VLANEnable");
1755fda13ad2SSunitha Harish         }
1756fda13ad2SSunitha Harish         if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
1757fda13ad2SSunitha Harish         {
1758fda13ad2SSunitha Harish             return;
1759fda13ad2SSunitha Harish         }
1760fda13ad2SSunitha Harish 
17614a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
17624a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
17631abe55efSEd Tanous             if (ec)
17641abe55efSEd Tanous             {
17654a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
17664a0cb85cSEd Tanous                 // phosphor-network responses
1767f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
17684a0cb85cSEd Tanous                 return;
17691abe55efSEd Tanous             }
1770f12894f8SJason M. Bills             messages::created(asyncResp->res);
1771e439f0f8SKowalski, Kamil         };
17724a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
17734a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
17744a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
17754a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
17760627a2c7SEd Tanous             rootInterfaceName, vlanId);
17774a0cb85cSEd Tanous     }
17784a0cb85cSEd Tanous };
17799391bb9cSRapkiewicz, Pawel } // namespace redfish
1780