xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision f476acbf885119861a1fecad47399a8eeeff0086)
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;
844a0cb85cSEd Tanous     std::string mac_address;
85a24526dcSEd Tanous     std::optional<uint32_t> vlan_id;
86029573d4SEd Tanous     std::vector<std::string> nameservers;
879391bb9cSRapkiewicz, Pawel };
889391bb9cSRapkiewicz, Pawel 
899391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
909391bb9cSRapkiewicz, Pawel // into full dot notation
911abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
921abe55efSEd Tanous {
939391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
949391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
959391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
969391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
979391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
989391bb9cSRapkiewicz, Pawel     return netmask;
999391bb9cSRapkiewicz, Pawel }
1009391bb9cSRapkiewicz, Pawel 
1014a0cb85cSEd Tanous inline std::string
1024a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1034a0cb85cSEd Tanous                                         bool isIPv4)
1041abe55efSEd Tanous {
1054a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1061abe55efSEd Tanous     {
1074a0cb85cSEd Tanous         return "Static";
1089391bb9cSRapkiewicz, Pawel     }
1094a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1101abe55efSEd Tanous     {
1114a0cb85cSEd Tanous         if (isIPv4)
1121abe55efSEd Tanous         {
1134a0cb85cSEd Tanous             return "IPv4LinkLocal";
1141abe55efSEd Tanous         }
1151abe55efSEd Tanous         else
1161abe55efSEd Tanous         {
1174a0cb85cSEd Tanous             return "LinkLocal";
1189391bb9cSRapkiewicz, Pawel         }
1199391bb9cSRapkiewicz, Pawel     }
1204a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1211abe55efSEd Tanous     {
1224a0cb85cSEd Tanous         if (isIPv4)
1234a0cb85cSEd Tanous         {
1244a0cb85cSEd Tanous             return "DHCP";
1254a0cb85cSEd Tanous         }
1264a0cb85cSEd Tanous         else
1274a0cb85cSEd Tanous         {
1284a0cb85cSEd Tanous             return "DHCPv6";
1294a0cb85cSEd Tanous         }
1304a0cb85cSEd Tanous     }
1314a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1324a0cb85cSEd Tanous     {
1334a0cb85cSEd Tanous         return "SLAAC";
1344a0cb85cSEd Tanous     }
1354a0cb85cSEd Tanous     return "";
1364a0cb85cSEd Tanous }
1374a0cb85cSEd Tanous 
1384a0cb85cSEd Tanous inline std::string
1394a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1404a0cb85cSEd Tanous {
1414a0cb85cSEd Tanous     if (inputOrigin == "Static")
1424a0cb85cSEd Tanous     {
1434a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1444a0cb85cSEd Tanous     }
1454a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1464a0cb85cSEd Tanous     {
1474a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1484a0cb85cSEd Tanous     }
1494a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1504a0cb85cSEd Tanous     {
1514a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1524a0cb85cSEd Tanous     }
1534a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1544a0cb85cSEd Tanous     {
1554a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1564a0cb85cSEd Tanous     }
1574a0cb85cSEd Tanous     return "";
1584a0cb85cSEd Tanous }
1594a0cb85cSEd Tanous 
1604a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
1614a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1624a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1634a0cb85cSEd Tanous {
1644a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1654a0cb85cSEd Tanous     {
1664a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1674a0cb85cSEd Tanous         {
168029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
169029573d4SEd Tanous             {
1704a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1714a0cb85cSEd Tanous                 {
1724a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1734a0cb85cSEd Tanous                     {
1744a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1754a0cb85cSEd Tanous                         {
1764a0cb85cSEd Tanous                             const std::string *mac =
177abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1784a0cb85cSEd Tanous                             if (mac != nullptr)
1794a0cb85cSEd Tanous                             {
1804a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1814a0cb85cSEd Tanous                             }
1824a0cb85cSEd Tanous                         }
1834a0cb85cSEd Tanous                     }
1844a0cb85cSEd Tanous                 }
1854a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1864a0cb85cSEd Tanous                 {
1874a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1884a0cb85cSEd Tanous                     {
1894a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1904a0cb85cSEd Tanous                         {
1911b6b96c5SEd Tanous                             const uint32_t *id =
192abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1934a0cb85cSEd Tanous                             if (id != nullptr)
1944a0cb85cSEd Tanous                             {
1954a0cb85cSEd Tanous                                 ethData.vlan_id = *id;
1964a0cb85cSEd Tanous                             }
1974a0cb85cSEd Tanous                         }
1984a0cb85cSEd Tanous                     }
1994a0cb85cSEd Tanous                 }
2004a0cb85cSEd Tanous                 else if (ifacePair.first ==
2014a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2024a0cb85cSEd Tanous                 {
2034a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2044a0cb85cSEd Tanous                     {
2054a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2064a0cb85cSEd Tanous                         {
2074a0cb85cSEd Tanous                             const bool *auto_neg =
208abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2094a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2104a0cb85cSEd Tanous                             {
2114a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2124a0cb85cSEd Tanous                             }
2134a0cb85cSEd Tanous                         }
2144a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2154a0cb85cSEd Tanous                         {
2164a0cb85cSEd Tanous                             const uint32_t *speed =
217abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2184a0cb85cSEd Tanous                             if (speed != nullptr)
2194a0cb85cSEd Tanous                             {
2204a0cb85cSEd Tanous                                 ethData.speed = *speed;
2214a0cb85cSEd Tanous                             }
2224a0cb85cSEd Tanous                         }
223029573d4SEd Tanous                         else if (propertyPair.first == "NameServers")
224029573d4SEd Tanous                         {
225029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
226029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
227029573d4SEd Tanous                                     std::vector<std::string>>(
228029573d4SEd Tanous                                     &propertyPair.second);
229029573d4SEd Tanous                             if (nameservers != nullptr)
230029573d4SEd Tanous                             {
231029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2324a0cb85cSEd Tanous                             }
2334a0cb85cSEd Tanous                         }
2342a133282Smanojkiraneda                         else if (propertyPair.first == "DHCPEnabled")
2352a133282Smanojkiraneda                         {
2362a133282Smanojkiraneda                             const bool *DHCPEnabled =
2372a133282Smanojkiraneda                                 std::get_if<bool>(&propertyPair.second);
2382a133282Smanojkiraneda                             if (DHCPEnabled != nullptr)
2392a133282Smanojkiraneda                             {
2402a133282Smanojkiraneda                                 ethData.DHCPEnabled = *DHCPEnabled;
2412a133282Smanojkiraneda                             }
2422a133282Smanojkiraneda                         }
243029573d4SEd Tanous                     }
244029573d4SEd Tanous                 }
245029573d4SEd Tanous             }
246029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
247029573d4SEd Tanous             // to check eth number
248029573d4SEd Tanous             if (ifacePair.first ==
2494a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2504a0cb85cSEd Tanous             {
2514a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2524a0cb85cSEd Tanous                 {
2534a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2544a0cb85cSEd Tanous                     {
2554a0cb85cSEd Tanous                         const std::string *hostname =
256029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
257029573d4SEd Tanous                                 &propertyPair.second);
2584a0cb85cSEd Tanous                         if (hostname != nullptr)
2594a0cb85cSEd Tanous                         {
2604a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2614a0cb85cSEd Tanous                         }
2624a0cb85cSEd Tanous                     }
2634a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2644a0cb85cSEd Tanous                     {
2654a0cb85cSEd Tanous                         const std::string *defaultGateway =
266029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
267029573d4SEd Tanous                                 &propertyPair.second);
2684a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2694a0cb85cSEd Tanous                         {
2704a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2714a0cb85cSEd Tanous                         }
2724a0cb85cSEd Tanous                     }
2734a0cb85cSEd Tanous                 }
2744a0cb85cSEd Tanous             }
2754a0cb85cSEd Tanous         }
2764a0cb85cSEd Tanous     }
2774a0cb85cSEd Tanous }
2784a0cb85cSEd Tanous 
2794a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2804a0cb85cSEd Tanous inline void
2814a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2824a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2834a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2844a0cb85cSEd Tanous {
2854a0cb85cSEd Tanous     const std::string ipv4PathStart =
2864a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
2874a0cb85cSEd Tanous 
2884a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
2894a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
2904a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
2914a0cb85cSEd Tanous     {
2924a0cb85cSEd Tanous         // Check if proper pattern for object path appears
2934a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
2944a0cb85cSEd Tanous         {
2954a0cb85cSEd Tanous             for (auto &interface : objpath.second)
2964a0cb85cSEd Tanous             {
2974a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
2984a0cb85cSEd Tanous                 {
2994a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
3004a0cb85cSEd Tanous                     // appropriate
3014a0cb85cSEd Tanous                     std::pair<
3024a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
3034a0cb85cSEd Tanous                         bool>
3044a0cb85cSEd Tanous                         it = ipv4_config.insert(
3054a0cb85cSEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
3064a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
3074a0cb85cSEd Tanous                     for (auto &property : interface.second)
3084a0cb85cSEd Tanous                     {
3094a0cb85cSEd Tanous                         if (property.first == "Address")
3104a0cb85cSEd Tanous                         {
3114a0cb85cSEd Tanous                             const std::string *address =
312abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3134a0cb85cSEd Tanous                             if (address != nullptr)
3144a0cb85cSEd Tanous                             {
3154a0cb85cSEd Tanous                                 ipv4_address.address = *address;
3164a0cb85cSEd Tanous                             }
3174a0cb85cSEd Tanous                         }
3184a0cb85cSEd Tanous                         else if (property.first == "Gateway")
3194a0cb85cSEd Tanous                         {
3204a0cb85cSEd Tanous                             const std::string *gateway =
321abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3224a0cb85cSEd Tanous                             if (gateway != nullptr)
3234a0cb85cSEd Tanous                             {
3244a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
3254a0cb85cSEd Tanous                             }
3264a0cb85cSEd Tanous                         }
3274a0cb85cSEd Tanous                         else if (property.first == "Origin")
3284a0cb85cSEd Tanous                         {
3294a0cb85cSEd Tanous                             const std::string *origin =
330abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3314a0cb85cSEd Tanous                             if (origin != nullptr)
3324a0cb85cSEd Tanous                             {
3334a0cb85cSEd Tanous                                 ipv4_address.origin =
3344a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3354a0cb85cSEd Tanous                                                                         true);
3364a0cb85cSEd Tanous                             }
3374a0cb85cSEd Tanous                         }
3384a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3394a0cb85cSEd Tanous                         {
3404a0cb85cSEd Tanous                             const uint8_t *mask =
341abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
3424a0cb85cSEd Tanous                             if (mask != nullptr)
3434a0cb85cSEd Tanous                             {
3444a0cb85cSEd Tanous                                 // convert it to the string
3454a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3464a0cb85cSEd Tanous                             }
3474a0cb85cSEd Tanous                         }
3484a0cb85cSEd Tanous                         else
3494a0cb85cSEd Tanous                         {
3504a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3514a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3524a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3534a0cb85cSEd Tanous                         }
3544a0cb85cSEd Tanous                     }
3554a0cb85cSEd Tanous                     // Check if given address is local, or global
3564a0cb85cSEd Tanous                     ipv4_address.linktype =
3574a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3584a0cb85cSEd Tanous                             ? LinkType::Global
3594a0cb85cSEd Tanous                             : LinkType::Local;
3604a0cb85cSEd Tanous                 }
3614a0cb85cSEd Tanous             }
3624a0cb85cSEd Tanous         }
3634a0cb85cSEd Tanous     }
3644a0cb85cSEd Tanous }
365588c3f0dSKowalski, Kamil 
366588c3f0dSKowalski, Kamil /**
367588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
368588c3f0dSKowalski, Kamil  *
369588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
370588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
371588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
372588c3f0dSKowalski, Kamil  *
373588c3f0dSKowalski, Kamil  * @return None.
374588c3f0dSKowalski, Kamil  */
375588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3764a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3771abe55efSEd Tanous                   CallbackFunc &&callback)
3781abe55efSEd Tanous {
37955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
380588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
381588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
382588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
383588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
384abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
3854a0cb85cSEd Tanous }
386588c3f0dSKowalski, Kamil 
387588c3f0dSKowalski, Kamil /**
388179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
389179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
390179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
391179db1d7SKowalski, Kamil  *
392179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
393179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
394179db1d7SKowalski, Kamil  *
395179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
396179db1d7SKowalski, Kamil  */
3974a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
3981abe55efSEd Tanous                                        uint8_t *bits = nullptr)
3991abe55efSEd Tanous {
400179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
401179db1d7SKowalski, Kamil 
402179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
403179db1d7SKowalski, Kamil 
4044a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
4051abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
4061abe55efSEd Tanous     {
407179db1d7SKowalski, Kamil         return false;
408179db1d7SKowalski, Kamil     }
409179db1d7SKowalski, Kamil 
4101abe55efSEd Tanous     if (bits != nullptr)
4111abe55efSEd Tanous     {
412179db1d7SKowalski, Kamil         *bits = 0;
413179db1d7SKowalski, Kamil     }
414179db1d7SKowalski, Kamil 
415179db1d7SKowalski, Kamil     char *endPtr;
416179db1d7SKowalski, Kamil     long previousValue = 255;
417179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
4181abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
4191abe55efSEd Tanous     {
4201abe55efSEd Tanous         if (byte.empty())
4211abe55efSEd Tanous         {
4221db9ca37SKowalski, Kamil             return false;
4231db9ca37SKowalski, Kamil         }
4241db9ca37SKowalski, Kamil 
425179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4261db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
427179db1d7SKowalski, Kamil 
4284a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4294a0cb85cSEd Tanous         // is not 100% number
4301abe55efSEd Tanous         if (*endPtr != '\0')
4311abe55efSEd Tanous         {
432179db1d7SKowalski, Kamil             return false;
433179db1d7SKowalski, Kamil         }
434179db1d7SKowalski, Kamil 
435179db1d7SKowalski, Kamil         // Value should be contained in byte
4361abe55efSEd Tanous         if (value < 0 || value > 255)
4371abe55efSEd Tanous         {
438179db1d7SKowalski, Kamil             return false;
439179db1d7SKowalski, Kamil         }
440179db1d7SKowalski, Kamil 
4411abe55efSEd Tanous         if (bits != nullptr)
4421abe55efSEd Tanous         {
443179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4441abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4451abe55efSEd Tanous             {
446179db1d7SKowalski, Kamil                 return false;
447179db1d7SKowalski, Kamil             }
448179db1d7SKowalski, Kamil 
449179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
450179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
451179db1d7SKowalski, Kamil 
452179db1d7SKowalski, Kamil             // Count bits
4531abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4541abe55efSEd Tanous             {
4551abe55efSEd Tanous                 if (value & (1 << bitIdx))
4561abe55efSEd Tanous                 {
4571abe55efSEd Tanous                     if (firstZeroInByteHit)
4581abe55efSEd Tanous                     {
459179db1d7SKowalski, Kamil                         // Continuity not preserved
460179db1d7SKowalski, Kamil                         return false;
4611abe55efSEd Tanous                     }
4621abe55efSEd Tanous                     else
4631abe55efSEd Tanous                     {
464179db1d7SKowalski, Kamil                         (*bits)++;
465179db1d7SKowalski, Kamil                     }
4661abe55efSEd Tanous                 }
4671abe55efSEd Tanous                 else
4681abe55efSEd Tanous                 {
469179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
470179db1d7SKowalski, Kamil                 }
471179db1d7SKowalski, Kamil             }
472179db1d7SKowalski, Kamil         }
473179db1d7SKowalski, Kamil 
474179db1d7SKowalski, Kamil         previousValue = value;
475179db1d7SKowalski, Kamil     }
476179db1d7SKowalski, Kamil 
477179db1d7SKowalski, Kamil     return true;
478179db1d7SKowalski, Kamil }
479179db1d7SKowalski, Kamil 
480179db1d7SKowalski, Kamil /**
481179db1d7SKowalski, Kamil  * @brief Changes IPv4 address type property (Address, Gateway)
482179db1d7SKowalski, Kamil  *
483179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be modified
4844a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
485179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of modified IP
486179db1d7SKowalski, Kamil  * @param[in] name        Name of field in JSON representation
487179db1d7SKowalski, Kamil  * @param[in] newValue    New value that should be written
488179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
489179db1d7SKowalski, Kamil  *
490179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
491179db1d7SKowalski, Kamil  * otherwise
492179db1d7SKowalski, Kamil  */
4934a0cb85cSEd Tanous inline void changeIPv4AddressProperty(
4944a0cb85cSEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
4954a0cb85cSEd Tanous     const std::string &name, const std::string &newValue,
4964a0cb85cSEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
4971abe55efSEd Tanous {
4984a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
4994a0cb85cSEd Tanous                      newValue{std::move(newValue)}](
5001abe55efSEd Tanous                         const boost::system::error_code ec) {
5011abe55efSEd Tanous         if (ec)
5021abe55efSEd Tanous         {
503a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5041abe55efSEd Tanous         }
5051abe55efSEd Tanous         else
5061abe55efSEd Tanous         {
5074a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
508179db1d7SKowalski, Kamil         }
509179db1d7SKowalski, Kamil     };
510179db1d7SKowalski, Kamil 
51155c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
512179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
513179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
514179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
515179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", name,
516abf2add6SEd Tanous         std::variant<std::string>(newValue));
5174a0cb85cSEd Tanous }
518179db1d7SKowalski, Kamil 
519179db1d7SKowalski, Kamil /**
520179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
521179db1d7SKowalski, Kamil  *
522179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
5234a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5241abe55efSEd Tanous  * modified
525179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
526179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
527179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
528179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
529179db1d7SKowalski, Kamil  *
530179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
531179db1d7SKowalski, Kamil  * otherwise
532179db1d7SKowalski, Kamil  */
5334a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5341abe55efSEd Tanous                              const std::string &ipHash,
5351abe55efSEd Tanous                              const std::string &newValue,
536179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5374a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5381abe55efSEd Tanous {
5394a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5401abe55efSEd Tanous                         const boost::system::error_code ec) {
5411abe55efSEd Tanous         if (ec)
5421abe55efSEd Tanous         {
543a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5441abe55efSEd Tanous         }
5451abe55efSEd Tanous         else
5461abe55efSEd Tanous         {
5474a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
548179db1d7SKowalski, Kamil                 newValue;
549179db1d7SKowalski, Kamil         }
550179db1d7SKowalski, Kamil     };
551179db1d7SKowalski, Kamil 
55255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
553179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
554179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
555179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
556179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
557abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
5584a0cb85cSEd Tanous }
559179db1d7SKowalski, Kamil 
560179db1d7SKowalski, Kamil /**
561179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
562179db1d7SKowalski, Kamil  *
563179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5644a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5651abe55efSEd Tanous  * modified
566179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
567179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
568179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
569179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
570179db1d7SKowalski, Kamil  *
571179db1d7SKowalski, Kamil  * @return None
572179db1d7SKowalski, Kamil  */
5734a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5744a0cb85cSEd Tanous                                          const std::string &ipHash,
5754a0cb85cSEd Tanous                                          const std::string &newValueStr,
5764a0cb85cSEd Tanous                                          uint8_t &newValue,
5774a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5781abe55efSEd Tanous {
5794a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5801abe55efSEd Tanous                         const boost::system::error_code ec) {
5811abe55efSEd Tanous         if (ec)
5821abe55efSEd Tanous         {
583a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5841abe55efSEd Tanous         }
5851abe55efSEd Tanous         else
5861abe55efSEd Tanous         {
58755c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
588179db1d7SKowalski, Kamil                 newValueStr;
589179db1d7SKowalski, Kamil         }
590179db1d7SKowalski, Kamil     };
591179db1d7SKowalski, Kamil 
59255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
593179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
594179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
595179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
596179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
597abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
5984a0cb85cSEd Tanous }
599588c3f0dSKowalski, Kamil 
600588c3f0dSKowalski, Kamil /**
601179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
602179db1d7SKowalski, Kamil  *
603179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6044a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
605179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
606179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
607179db1d7SKowalski, Kamil  *
608179db1d7SKowalski, Kamil  * @return None
609179db1d7SKowalski, Kamil  */
6104a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
611179db1d7SKowalski, Kamil                        unsigned int ipIdx,
6124a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6131abe55efSEd Tanous {
61455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6154a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6161abe55efSEd Tanous             if (ec)
6171abe55efSEd Tanous             {
618a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6191abe55efSEd Tanous             }
6201abe55efSEd Tanous             else
6211abe55efSEd Tanous             {
62255c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
623179db1d7SKowalski, Kamil             }
624179db1d7SKowalski, Kamil         },
625179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
626179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
627179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
628179db1d7SKowalski, Kamil }
629179db1d7SKowalski, Kamil 
630179db1d7SKowalski, Kamil /**
631179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
632179db1d7SKowalski, Kamil  *
633179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6344a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
635179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
636179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
637179db1d7SKowalski, Kamil  *
638179db1d7SKowalski, Kamil  * @return None
639179db1d7SKowalski, Kamil  */
6404a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
641179db1d7SKowalski, Kamil                        uint8_t subnetMask, const std::string &gateway,
642179db1d7SKowalski, Kamil                        const std::string &address,
6434a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6441abe55efSEd Tanous {
64543b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
6461abe55efSEd Tanous         if (ec)
6471abe55efSEd Tanous         {
648a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
649179db1d7SKowalski, Kamil         }
650179db1d7SKowalski, Kamil     };
651179db1d7SKowalski, Kamil 
65255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
653179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
654179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
655179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
656179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
657179db1d7SKowalski, Kamil         gateway);
658179db1d7SKowalski, Kamil }
6592a133282Smanojkiraneda using GetAllPropertiesType =
6602a133282Smanojkiraneda     boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>;
6612a133282Smanojkiraneda 
6622a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp)
6632a133282Smanojkiraneda {
6642a133282Smanojkiraneda     auto getConfig = [asyncResp](const boost::system::error_code error_code,
6652a133282Smanojkiraneda                                  const GetAllPropertiesType &dbus_data) {
6662a133282Smanojkiraneda         if (error_code)
6672a133282Smanojkiraneda         {
6682a133282Smanojkiraneda             BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code;
6692a133282Smanojkiraneda             messages::internalError(asyncResp->res);
6702a133282Smanojkiraneda             return;
6712a133282Smanojkiraneda         }
6722a133282Smanojkiraneda         nlohmann::json &DHCPConfigTypeJson =
6732a133282Smanojkiraneda             asyncResp->res.jsonValue["DHCPv4Configuration"];
6742a133282Smanojkiraneda         for (const auto &property : dbus_data)
6752a133282Smanojkiraneda         {
6762a133282Smanojkiraneda             auto value =
6772a133282Smanojkiraneda                 sdbusplus::message::variant_ns::get_if<bool>(&property.second);
6782a133282Smanojkiraneda 
6792a133282Smanojkiraneda             if (value == nullptr)
6802a133282Smanojkiraneda             {
6812a133282Smanojkiraneda                 continue;
6822a133282Smanojkiraneda             }
6832a133282Smanojkiraneda             if (property.first == "DNSEnabled")
6842a133282Smanojkiraneda             {
6852a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDNSServers"] = *value;
6862a133282Smanojkiraneda             }
6872a133282Smanojkiraneda             else if (property.first == "HostNameEnabled")
6882a133282Smanojkiraneda             {
6892a133282Smanojkiraneda                 DHCPConfigTypeJson["UseDomainName"] = *value;
6902a133282Smanojkiraneda             }
6912a133282Smanojkiraneda             else if (property.first == "NTPEnabled")
6922a133282Smanojkiraneda             {
6932a133282Smanojkiraneda                 DHCPConfigTypeJson["UseNTPServers"] = *value;
6942a133282Smanojkiraneda             }
6952a133282Smanojkiraneda         }
6962a133282Smanojkiraneda     };
6972a133282Smanojkiraneda     crow::connections::systemBus->async_method_call(
6982a133282Smanojkiraneda         std::move(getConfig), "xyz.openbmc_project.Network",
6992a133282Smanojkiraneda         "/xyz/openbmc_project/network/config/dhcp",
7002a133282Smanojkiraneda         "org.freedesktop.DBus.Properties", "GetAll",
7012a133282Smanojkiraneda         "xyz.openbmc_project.Network.DHCPConfiguration");
7022a133282Smanojkiraneda }
703179db1d7SKowalski, Kamil 
704179db1d7SKowalski, Kamil /**
705179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
706179db1d7SKowalski, Kamil  * Object
707179db1d7SKowalski, Kamil  * from EntityManager Network Manager
7084a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
709179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
710179db1d7SKowalski, Kamil  * into JSON
711179db1d7SKowalski, Kamil  */
712179db1d7SKowalski, Kamil template <typename CallbackFunc>
7134a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
7141abe55efSEd Tanous                           CallbackFunc &&callback)
7151abe55efSEd Tanous {
71655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7174a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
7181abe55efSEd Tanous             const boost::system::error_code error_code,
7194a0cb85cSEd Tanous             const GetManagedObjects &resp) {
72055c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
7214a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
722179db1d7SKowalski, Kamil 
7231abe55efSEd Tanous             if (error_code)
7241abe55efSEd Tanous             {
72555c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
726179db1d7SKowalski, Kamil                 return;
727179db1d7SKowalski, Kamil             }
728179db1d7SKowalski, Kamil 
7294a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
7304a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
731179db1d7SKowalski, Kamil 
732179db1d7SKowalski, Kamil             // Fix global GW
7331abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
7341abe55efSEd Tanous             {
7354a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
7364a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
7371abe55efSEd Tanous                 {
7384a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
739179db1d7SKowalski, Kamil                 }
740179db1d7SKowalski, Kamil             }
741179db1d7SKowalski, Kamil 
7424a0cb85cSEd Tanous             // Finally make a callback with usefull data
74355c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
744179db1d7SKowalski, Kamil         },
745179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
746179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
747179db1d7SKowalski, Kamil };
748179db1d7SKowalski, Kamil 
749179db1d7SKowalski, Kamil /**
7509391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
7519391bb9cSRapkiewicz, Pawel  * Manager
7521abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
7531abe55efSEd Tanous  * into JSON.
7549391bb9cSRapkiewicz, Pawel  */
7559391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7561abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7571abe55efSEd Tanous {
75855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7594a0cb85cSEd Tanous         [callback{std::move(callback)}](
7609391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
7614a0cb85cSEd Tanous             GetManagedObjects &resp) {
7621abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7631abe55efSEd Tanous             // ethernet interfaces
7644a0cb85cSEd Tanous             std::vector<std::string> iface_list;
7654a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7661abe55efSEd Tanous             if (error_code)
7671abe55efSEd Tanous             {
7684a0cb85cSEd Tanous                 callback(false, iface_list);
7699391bb9cSRapkiewicz, Pawel                 return;
7709391bb9cSRapkiewicz, Pawel             }
7719391bb9cSRapkiewicz, Pawel 
7729391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7734a0cb85cSEd Tanous             for (const auto &objpath : resp)
7741abe55efSEd Tanous             {
7759391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7764a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7771abe55efSEd Tanous                 {
7781abe55efSEd Tanous                     // If interface is
7794a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
7804a0cb85cSEd Tanous                     // what we're looking for.
7819391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7821abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7831abe55efSEd Tanous                     {
7844a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
7854a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
7864a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
7874a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7881abe55efSEd Tanous                         {
7899391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
7904a0cb85cSEd Tanous                             iface_list.emplace_back(
7914a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
7929391bb9cSRapkiewicz, Pawel                         }
7939391bb9cSRapkiewicz, Pawel                     }
7949391bb9cSRapkiewicz, Pawel                 }
7959391bb9cSRapkiewicz, Pawel             }
796a434f2bdSEd Tanous             // Finally make a callback with useful data
7974a0cb85cSEd Tanous             callback(true, iface_list);
7989391bb9cSRapkiewicz, Pawel         },
799aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
800aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8019391bb9cSRapkiewicz, Pawel };
8029391bb9cSRapkiewicz, Pawel 
8039391bb9cSRapkiewicz, Pawel /**
8049391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
8059391bb9cSRapkiewicz, Pawel  */
8061abe55efSEd Tanous class EthernetCollection : public Node
8071abe55efSEd Tanous {
8089391bb9cSRapkiewicz, Pawel   public:
8094a0cb85cSEd Tanous     template <typename CrowApp>
8101abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
8114a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
8121abe55efSEd Tanous     {
813588c3f0dSKowalski, Kamil         entityPrivileges = {
814588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
815e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
816e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
817e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
818e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
819e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8209391bb9cSRapkiewicz, Pawel     }
8219391bb9cSRapkiewicz, Pawel 
8229391bb9cSRapkiewicz, Pawel   private:
8239391bb9cSRapkiewicz, Pawel     /**
8249391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8259391bb9cSRapkiewicz, Pawel      */
82655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
8271abe55efSEd Tanous                const std::vector<std::string> &params) override
8281abe55efSEd Tanous     {
8290f74e643SEd Tanous         res.jsonValue["@odata.type"] =
8300f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
8310f74e643SEd Tanous         res.jsonValue["@odata.context"] =
8320f74e643SEd Tanous             "/redfish/v1/"
8330f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
8340f74e643SEd Tanous         res.jsonValue["@odata.id"] =
8350f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
8360f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
8370f74e643SEd Tanous         res.jsonValue["Description"] =
8380f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
8390f74e643SEd Tanous 
8404a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
8411abe55efSEd Tanous         // preparation
842f12894f8SJason M. Bills         getEthernetIfaceList(
843f12894f8SJason M. Bills             [&res](const bool &success,
8441abe55efSEd Tanous                    const std::vector<std::string> &iface_list) {
8454a0cb85cSEd Tanous                 if (!success)
8461abe55efSEd Tanous                 {
847f12894f8SJason M. Bills                     messages::internalError(res);
8484a0cb85cSEd Tanous                     res.end();
8494a0cb85cSEd Tanous                     return;
8504a0cb85cSEd Tanous                 }
8514a0cb85cSEd Tanous 
8524a0cb85cSEd Tanous                 nlohmann::json &iface_array = res.jsonValue["Members"];
8534a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
8544a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
8551abe55efSEd Tanous                 {
8564a0cb85cSEd Tanous                     iface_array.push_back(
8574a0cb85cSEd Tanous                         {{"@odata.id",
8584a0cb85cSEd Tanous                           "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
8594a0cb85cSEd Tanous                               iface_item}});
8609391bb9cSRapkiewicz, Pawel                 }
8614a0cb85cSEd Tanous 
8624a0cb85cSEd Tanous                 res.jsonValue["Members@odata.count"] = iface_array.size();
8634a0cb85cSEd Tanous                 res.jsonValue["@odata.id"] =
8644a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
8659391bb9cSRapkiewicz, Pawel                 res.end();
8669391bb9cSRapkiewicz, Pawel             });
8679391bb9cSRapkiewicz, Pawel     }
8689391bb9cSRapkiewicz, Pawel };
8699391bb9cSRapkiewicz, Pawel 
8709391bb9cSRapkiewicz, Pawel /**
8719391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8729391bb9cSRapkiewicz, Pawel  */
8731abe55efSEd Tanous class EthernetInterface : public Node
8741abe55efSEd Tanous {
8759391bb9cSRapkiewicz, Pawel   public:
8769391bb9cSRapkiewicz, Pawel     /*
8779391bb9cSRapkiewicz, Pawel      * Default Constructor
8789391bb9cSRapkiewicz, Pawel      */
8794a0cb85cSEd Tanous     template <typename CrowApp>
8801abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
8814a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8821abe55efSEd Tanous              std::string())
8831abe55efSEd Tanous     {
884588c3f0dSKowalski, Kamil         entityPrivileges = {
885588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
886e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
887e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
888e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
889e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
890e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8919391bb9cSRapkiewicz, Pawel     }
8929391bb9cSRapkiewicz, Pawel 
893e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
8940627a2c7SEd Tanous     static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable,
8950627a2c7SEd Tanous                                 uint64_t vlanId,
8964a0cb85cSEd Tanous                                 const EthernetInterfaceData &ethData,
8974a0cb85cSEd Tanous                                 const std::shared_ptr<AsyncResp> asyncResp)
8981abe55efSEd Tanous     {
8994a0cb85cSEd Tanous         if (!ethData.vlan_id)
9001abe55efSEd Tanous         {
901e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
902e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
903a08b46ccSJason M. Bills             messages::propertyNotWritable(asyncResp->res, "VLANEnable");
904588c3f0dSKowalski, Kamil 
905588c3f0dSKowalski, Kamil             return;
906588c3f0dSKowalski, Kamil         }
907588c3f0dSKowalski, Kamil 
908588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
9090627a2c7SEd Tanous         if (vlanEnable == true)
9101abe55efSEd Tanous         {
911588c3f0dSKowalski, Kamil             // Change VLAN Id
9120627a2c7SEd Tanous             asyncResp->res.jsonValue["VLANId"] = vlanId;
9134a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9141abe55efSEd Tanous                 if (ec)
9151abe55efSEd Tanous                 {
916f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
9171abe55efSEd Tanous                 }
9181abe55efSEd Tanous                 else
9191abe55efSEd Tanous                 {
9204a0cb85cSEd Tanous                     asyncResp->res.jsonValue["VLANEnable"] = true;
921e439f0f8SKowalski, Kamil                 }
9224a0cb85cSEd Tanous             };
9234a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
9244a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
9254a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
9264a0cb85cSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
9274a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.VLAN", "Id",
928abf2add6SEd Tanous                 std::variant<uint32_t>(vlanId));
9291abe55efSEd Tanous         }
9304a0cb85cSEd Tanous         else
9311abe55efSEd Tanous         {
9324a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9331abe55efSEd Tanous                 if (ec)
9341abe55efSEd Tanous                 {
935f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
9364a0cb85cSEd Tanous                     return;
9371abe55efSEd Tanous                 }
9384a0cb85cSEd Tanous                 asyncResp->res.jsonValue["VLANEnable"] = false;
9394a0cb85cSEd Tanous             };
9404a0cb85cSEd Tanous 
9414a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
9424a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
9434a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
9444a0cb85cSEd Tanous                 "xyz.openbmc_project.Object.Delete", "Delete");
945588c3f0dSKowalski, Kamil         }
946588c3f0dSKowalski, Kamil     }
947588c3f0dSKowalski, Kamil 
948e439f0f8SKowalski, Kamil   private:
949bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
9504a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
9511abe55efSEd Tanous     {
952bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
953bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
954bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
9554a0cb85cSEd Tanous                 if (ec)
9564a0cb85cSEd Tanous                 {
957a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
9581abe55efSEd Tanous                 }
959bc0bd6e0SEd Tanous             },
960bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
961bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
962bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
963bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
964abf2add6SEd Tanous             std::variant<std::string>(hostname));
965588c3f0dSKowalski, Kamil     }
966588c3f0dSKowalski, Kamil 
9674a0cb85cSEd Tanous     void handleIPv4Patch(
968*f476acbfSRatan Gupta         const std::string &ifaceId, nlohmann::json &input,
9694a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
9704a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
9711abe55efSEd Tanous     {
972*f476acbfSRatan Gupta         if (!input.is_array())
973*f476acbfSRatan Gupta         {
974*f476acbfSRatan Gupta             messages::propertyValueTypeError(asyncResp->res, input.dump(),
975*f476acbfSRatan Gupta                                              "IPv4Addresses");
976*f476acbfSRatan Gupta             return;
977*f476acbfSRatan Gupta         }
978*f476acbfSRatan Gupta 
9794a0cb85cSEd Tanous         int entryIdx = 0;
9804a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
9814a0cb85cSEd Tanous             ipv4Data.begin();
982537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
9831abe55efSEd Tanous         {
9844a0cb85cSEd Tanous             std::string pathString =
985a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
986179db1d7SKowalski, Kamil 
987*f476acbfSRatan Gupta             if (thisJson.is_null())
988*f476acbfSRatan Gupta             {
989*f476acbfSRatan Gupta                 if (thisData != ipv4Data.end())
990*f476acbfSRatan Gupta                 {
991*f476acbfSRatan Gupta                     deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp);
992*f476acbfSRatan Gupta                     thisData++;
993*f476acbfSRatan Gupta                 }
994*f476acbfSRatan Gupta                 else
995*f476acbfSRatan Gupta                 {
996*f476acbfSRatan Gupta                     messages::propertyValueFormatError(
997*f476acbfSRatan Gupta                         asyncResp->res, input.dump(), pathString);
998*f476acbfSRatan Gupta                     return;
999*f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
1000*f476acbfSRatan Gupta                     // list and if unable to update one of the
1001*f476acbfSRatan Gupta                     // list value then should we proceed further or
1002*f476acbfSRatan Gupta                     // break there, would ask in the redfish forum
1003*f476acbfSRatan Gupta                     // till then we stop processing the next list item.
1004*f476acbfSRatan Gupta                 }
1005*f476acbfSRatan Gupta                 entryIdx++;
1006*f476acbfSRatan Gupta                 continue; // not an error as per the redfish spec.
1007*f476acbfSRatan Gupta             }
1008*f476acbfSRatan Gupta 
10099474b378SRatan Gupta             if (thisJson.empty())
10109474b378SRatan Gupta             {
10119474b378SRatan Gupta                 if (thisData != ipv4Data.end())
10129474b378SRatan Gupta                 {
10139474b378SRatan Gupta                     thisData++;
10149474b378SRatan Gupta                 }
10159474b378SRatan Gupta                 else
10169474b378SRatan Gupta                 {
10179474b378SRatan Gupta                     messages::propertyMissing(asyncResp->res,
10189474b378SRatan Gupta                                               pathString + "/Address");
10199474b378SRatan Gupta                     return;
1020*f476acbfSRatan Gupta                     // TODO(ratagupt) Not sure about the property where value is
10219474b378SRatan Gupta                     // list and if unable to update one of the
10229474b378SRatan Gupta                     // list value then should we proceed further or
10239474b378SRatan Gupta                     // break there, would ask in the redfish forum
10249474b378SRatan Gupta                     // till then we stop processing the next list item.
10259474b378SRatan Gupta                 }
10269474b378SRatan Gupta                 entryIdx++;
10279474b378SRatan Gupta                 continue; // not an error as per the redfish spec.
10289474b378SRatan Gupta             }
10299474b378SRatan Gupta 
1030537174c4SEd Tanous             std::optional<std::string> address;
1031537174c4SEd Tanous             std::optional<std::string> addressOrigin;
1032537174c4SEd Tanous             std::optional<std::string> subnetMask;
1033537174c4SEd Tanous             std::optional<std::string> gateway;
1034537174c4SEd Tanous 
1035537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
1036537174c4SEd Tanous                                      address, "AddressOrigin", addressOrigin,
1037537174c4SEd Tanous                                      "SubnetMask", subnetMask, "Gateway",
1038537174c4SEd Tanous                                      gateway))
1039537174c4SEd Tanous             {
1040537174c4SEd Tanous                 return;
1041179db1d7SKowalski, Kamil             }
1042179db1d7SKowalski, Kamil 
1043537174c4SEd Tanous             if (address)
10441abe55efSEd Tanous             {
1045537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
10461abe55efSEd Tanous                 {
1047537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
10484a0cb85cSEd Tanous                                                        pathString + "/Address");
1049537174c4SEd Tanous                     return;
10504a0cb85cSEd Tanous                 }
10514a0cb85cSEd Tanous             }
10524a0cb85cSEd Tanous 
1053537174c4SEd Tanous             uint8_t prefixLength = 0;
1054537174c4SEd Tanous             if (subnetMask)
10554a0cb85cSEd Tanous             {
1056537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
10574a0cb85cSEd Tanous                 {
1058f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1059537174c4SEd Tanous                         asyncResp->res, *subnetMask,
10604a0cb85cSEd Tanous                         pathString + "/SubnetMask");
1061537174c4SEd Tanous                     return;
10624a0cb85cSEd Tanous                 }
10634a0cb85cSEd Tanous             }
10644a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
1065537174c4SEd Tanous             if (addressOrigin)
10664a0cb85cSEd Tanous             {
10674a0cb85cSEd Tanous                 // Get Address origin in proper format
10684a0cb85cSEd Tanous                 addressOriginInDBusFormat =
1069537174c4SEd Tanous                     translateAddressOriginRedfishToDbus(*addressOrigin);
10704a0cb85cSEd Tanous                 if (addressOriginInDBusFormat.empty())
10714a0cb85cSEd Tanous                 {
10724a0cb85cSEd Tanous                     messages::propertyValueNotInList(
1073537174c4SEd Tanous                         asyncResp->res, *addressOrigin,
1074a08b46ccSJason M. Bills                         pathString + "/AddressOrigin");
1075537174c4SEd Tanous                     return;
10764a0cb85cSEd Tanous                 }
10774a0cb85cSEd Tanous             }
10784a0cb85cSEd Tanous 
1079537174c4SEd Tanous             if (gateway)
10804a0cb85cSEd Tanous             {
1081537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
10824a0cb85cSEd Tanous                 {
1083537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
1084537174c4SEd Tanous                                                        pathString + "/Gateway");
1085537174c4SEd Tanous                     return;
10864a0cb85cSEd Tanous                 }
10874a0cb85cSEd Tanous             }
10884a0cb85cSEd Tanous 
1089*f476acbfSRatan Gupta             // if IP address exist then  modify it.
10904a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
10914a0cb85cSEd Tanous             {
1092179db1d7SKowalski, Kamil                 // Apply changes
1093537174c4SEd Tanous                 if (address)
10941abe55efSEd Tanous                 {
1095*f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1096*f476acbfSRatan Gupta                                      address{std::string(*address)}](
10974a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
10984a0cb85cSEd Tanous                         if (ec)
10991abe55efSEd Tanous                         {
1100a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
11014a0cb85cSEd Tanous                             return;
11024a0cb85cSEd Tanous                         }
1103*f476acbfSRatan Gupta                         asyncResp->res
1104*f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Address"] =
1105*f476acbfSRatan Gupta                             std::move(address);
11064a0cb85cSEd Tanous                     };
11074a0cb85cSEd Tanous 
11084a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
11094a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1110*f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1111*f476acbfSRatan Gupta                             thisData->id,
11124a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
11134a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Address",
1114537174c4SEd Tanous                         std::variant<std::string>(*address));
1115179db1d7SKowalski, Kamil                 }
1116179db1d7SKowalski, Kamil 
1117537174c4SEd Tanous                 if (subnetMask)
11181abe55efSEd Tanous                 {
11194a0cb85cSEd Tanous                     changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1120537174c4SEd Tanous                                                  thisData->id, *subnetMask,
1121537174c4SEd Tanous                                                  prefixLength, asyncResp);
1122179db1d7SKowalski, Kamil                 }
1123179db1d7SKowalski, Kamil 
1124537174c4SEd Tanous                 if (addressOrigin)
11251abe55efSEd Tanous                 {
11264a0cb85cSEd Tanous                     changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1127*f476acbfSRatan Gupta                                      *addressOrigin, addressOriginInDBusFormat,
1128*f476acbfSRatan Gupta                                      asyncResp);
1129179db1d7SKowalski, Kamil                 }
1130179db1d7SKowalski, Kamil 
1131537174c4SEd Tanous                 if (gateway)
11321abe55efSEd Tanous                 {
1133*f476acbfSRatan Gupta                     auto callback = [asyncResp, entryIdx,
1134537174c4SEd Tanous                                      gateway{std::string(*gateway)}](
11354a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
11364a0cb85cSEd Tanous                         if (ec)
11371abe55efSEd Tanous                         {
1138a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
11394a0cb85cSEd Tanous                             return;
11404a0cb85cSEd Tanous                         }
1141*f476acbfSRatan Gupta                         asyncResp->res
1142*f476acbfSRatan Gupta                             .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] =
1143537174c4SEd Tanous                             std::move(gateway);
11444a0cb85cSEd Tanous                     };
11454a0cb85cSEd Tanous 
11464a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
11474a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
1148*f476acbfSRatan Gupta                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
1149*f476acbfSRatan Gupta                             thisData->id,
11504a0cb85cSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
11514a0cb85cSEd Tanous                         "xyz.openbmc_project.Network.IP", "Gateway",
1152537174c4SEd Tanous                         std::variant<std::string>(*gateway));
11534a0cb85cSEd Tanous                 }
1154*f476acbfSRatan Gupta 
11554a0cb85cSEd Tanous                 thisData++;
11561abe55efSEd Tanous             }
11571abe55efSEd Tanous             else
11581abe55efSEd Tanous             {
11594a0cb85cSEd Tanous                 // Create IPv4 with provided data
1160537174c4SEd Tanous                 if (!gateway)
11611abe55efSEd Tanous                 {
1162a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11634a0cb85cSEd Tanous                                               pathString + "/Gateway");
11644a0cb85cSEd Tanous                     continue;
11654a0cb85cSEd Tanous                 }
11664a0cb85cSEd Tanous 
1167537174c4SEd Tanous                 if (!address)
11681abe55efSEd Tanous                 {
1169a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11704a0cb85cSEd Tanous                                               pathString + "/Address");
11714a0cb85cSEd Tanous                     continue;
11724a0cb85cSEd Tanous                 }
11734a0cb85cSEd Tanous 
1174537174c4SEd Tanous                 if (!subnetMask)
11751abe55efSEd Tanous                 {
1176a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11774a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
11784a0cb85cSEd Tanous                     continue;
1179588c3f0dSKowalski, Kamil                 }
1180588c3f0dSKowalski, Kamil 
1181537174c4SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1182537174c4SEd Tanous                            asyncResp);
11834a0cb85cSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
11844a0cb85cSEd Tanous             }
11854a0cb85cSEd Tanous             entryIdx++;
11864a0cb85cSEd Tanous         }
11874a0cb85cSEd Tanous     }
11884a0cb85cSEd Tanous 
11890f74e643SEd Tanous     void parseInterfaceData(
11900f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
11910f74e643SEd Tanous         const EthernetInterfaceData &ethData,
11924a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
11934a0cb85cSEd Tanous     {
11944a0cb85cSEd Tanous         json_response["Id"] = iface_id;
11954a0cb85cSEd Tanous         json_response["@odata.id"] =
11964a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1197029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1198029573d4SEd Tanous         if (ethData.speed == 0)
1199029573d4SEd Tanous         {
1200029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1201029573d4SEd Tanous             json_response["Status"] = {
1202029573d4SEd Tanous                 {"Health", "OK"},
1203029573d4SEd Tanous                 {"State", "Disabled"},
1204029573d4SEd Tanous             };
1205029573d4SEd Tanous         }
1206029573d4SEd Tanous         else
1207029573d4SEd Tanous         {
1208029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1209029573d4SEd Tanous             json_response["Status"] = {
1210029573d4SEd Tanous                 {"Health", "OK"},
1211029573d4SEd Tanous                 {"State", "Enabled"},
1212029573d4SEd Tanous             };
1213029573d4SEd Tanous         }
12144a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
12154a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
12162a133282Smanojkiraneda         json_response["DHCPv4Configuration"]["DHCPEnabled"] =
12172a133282Smanojkiraneda             ethData.DHCPEnabled;
12182a133282Smanojkiraneda 
12194a0cb85cSEd Tanous         if (!ethData.hostname.empty())
12204a0cb85cSEd Tanous         {
12214a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
12224a0cb85cSEd Tanous         }
12234a0cb85cSEd Tanous 
12244a0cb85cSEd Tanous         nlohmann::json &vlanObj = json_response["VLAN"];
12254a0cb85cSEd Tanous         if (ethData.vlan_id)
12264a0cb85cSEd Tanous         {
12274a0cb85cSEd Tanous             vlanObj["VLANEnable"] = true;
12284a0cb85cSEd Tanous             vlanObj["VLANId"] = *ethData.vlan_id;
12294a0cb85cSEd Tanous         }
12304a0cb85cSEd Tanous         else
12314a0cb85cSEd Tanous         {
12324a0cb85cSEd Tanous             vlanObj["VLANEnable"] = false;
12334a0cb85cSEd Tanous             vlanObj["VLANId"] = 0;
12344a0cb85cSEd Tanous         }
1235029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
12364a0cb85cSEd Tanous 
12374a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
12384a0cb85cSEd Tanous         {
12394a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
12404a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
12414a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
12424a0cb85cSEd Tanous             {
12434a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
12444a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1245029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1246029573d4SEd Tanous                                       {"Gateway", ipv4_config.gateway}});
12474a0cb85cSEd Tanous             }
12484a0cb85cSEd Tanous         }
1249588c3f0dSKowalski, Kamil     }
1250588c3f0dSKowalski, Kamil 
12519391bb9cSRapkiewicz, Pawel     /**
12529391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
12539391bb9cSRapkiewicz, Pawel      */
125455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
12551abe55efSEd Tanous                const std::vector<std::string> &params) override
12561abe55efSEd Tanous     {
12574a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12581abe55efSEd Tanous         if (params.size() != 1)
12591abe55efSEd Tanous         {
1260f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
12619391bb9cSRapkiewicz, Pawel             return;
12629391bb9cSRapkiewicz, Pawel         }
12639391bb9cSRapkiewicz, Pawel 
12644a0cb85cSEd Tanous         getEthernetIfaceData(
12654a0cb85cSEd Tanous             params[0],
12664a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
12674a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
12684a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
12694a0cb85cSEd Tanous                 if (!success)
12701abe55efSEd Tanous                 {
12711abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
12721abe55efSEd Tanous                     // object, and other errors
1273f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1274f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
12754a0cb85cSEd Tanous                     return;
12769391bb9cSRapkiewicz, Pawel                 }
12770f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
12780f74e643SEd Tanous                     "#EthernetInterface.v1_2_0.EthernetInterface";
12790f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
12800f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
12810f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
12820f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
12830f74e643SEd Tanous                     "Management Network Interface";
12840f74e643SEd Tanous 
12850f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
12860f74e643SEd Tanous                                    ipv4Data);
12879391bb9cSRapkiewicz, Pawel             });
12882a133282Smanojkiraneda         getDHCPConfigData(asyncResp);
12899391bb9cSRapkiewicz, Pawel     }
12909391bb9cSRapkiewicz, Pawel 
129155c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
12921abe55efSEd Tanous                  const std::vector<std::string> &params) override
12931abe55efSEd Tanous     {
12944a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12951abe55efSEd Tanous         if (params.size() != 1)
12961abe55efSEd Tanous         {
1297f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1298588c3f0dSKowalski, Kamil             return;
1299588c3f0dSKowalski, Kamil         }
1300588c3f0dSKowalski, Kamil 
13014a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1302588c3f0dSKowalski, Kamil 
13030627a2c7SEd Tanous         std::optional<nlohmann::json> vlan;
1304bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1305*f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv4Addresses;
1306*f476acbfSRatan Gupta         std::optional<nlohmann::json> ipv6Addresses;
13070627a2c7SEd Tanous 
13080627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
13090627a2c7SEd Tanous                                  "IPv4Addresses", ipv4Addresses,
13100627a2c7SEd Tanous                                  "IPv6Addresses", ipv6Addresses))
13111abe55efSEd Tanous         {
1312588c3f0dSKowalski, Kamil             return;
1313588c3f0dSKowalski, Kamil         }
1314f15aad37SRatan Gupta 
1315f15aad37SRatan Gupta         std::optional<uint64_t> vlanId;
1316f15aad37SRatan Gupta         std::optional<bool> vlanEnable;
1317f15aad37SRatan Gupta 
13180627a2c7SEd Tanous         if (vlan)
13190627a2c7SEd Tanous         {
13200627a2c7SEd Tanous             if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable,
13210627a2c7SEd Tanous                                      "VLANId", vlanId))
13220627a2c7SEd Tanous             {
13230627a2c7SEd Tanous                 return;
13240627a2c7SEd Tanous             }
13250627a2c7SEd Tanous             // Need both vlanId and vlanEnable to service this request
13260627a2c7SEd Tanous             if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
13270627a2c7SEd Tanous             {
13280627a2c7SEd Tanous                 if (vlanId)
13290627a2c7SEd Tanous                 {
13300627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANEnable");
13310627a2c7SEd Tanous                 }
13320627a2c7SEd Tanous                 else
13330627a2c7SEd Tanous                 {
13340627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANId");
13350627a2c7SEd Tanous                 }
13360627a2c7SEd Tanous 
13370627a2c7SEd Tanous                 return;
13380627a2c7SEd Tanous             }
13390627a2c7SEd Tanous         }
1340588c3f0dSKowalski, Kamil 
13414a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1342588c3f0dSKowalski, Kamil         // preparation
13434a0cb85cSEd Tanous         getEthernetIfaceData(
13444a0cb85cSEd Tanous             iface_id,
13450627a2c7SEd Tanous             [this, asyncResp, iface_id, vlanId, vlanEnable,
13460627a2c7SEd Tanous              hostname = std::move(hostname),
13470627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
13480627a2c7SEd Tanous              ipv6Addresses = std::move(ipv6Addresses)](
13494a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13504a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13511abe55efSEd Tanous                 if (!success)
13521abe55efSEd Tanous                 {
1353588c3f0dSKowalski, Kamil                     // ... otherwise return error
13541abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13551abe55efSEd Tanous                     // object, and other errors
1356f12894f8SJason M. Bills                     messages::resourceNotFound(
1357f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1358588c3f0dSKowalski, Kamil                     return;
1359588c3f0dSKowalski, Kamil                 }
1360588c3f0dSKowalski, Kamil 
13610f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
13620f74e643SEd Tanous                                    ipv4Data);
1363588c3f0dSKowalski, Kamil 
13640627a2c7SEd Tanous                 if (vlanId && vlanEnable)
13651abe55efSEd Tanous                 {
13660627a2c7SEd Tanous                     handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData,
13674a0cb85cSEd Tanous                                     asyncResp);
13681abe55efSEd Tanous                 }
13690627a2c7SEd Tanous 
13700627a2c7SEd Tanous                 if (hostname)
13711abe55efSEd Tanous                 {
13720627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
13731abe55efSEd Tanous                 }
13740627a2c7SEd Tanous 
13750627a2c7SEd Tanous                 if (ipv4Addresses)
13761abe55efSEd Tanous                 {
1377537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1378537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1379537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1380537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1381537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1382537174c4SEd Tanous                     // on that, but could be done more efficiently
1383*f476acbfSRatan Gupta                     nlohmann::json ipv4 = std::move(*ipv4Addresses);
1384537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
13851abe55efSEd Tanous                 }
13860627a2c7SEd Tanous 
13870627a2c7SEd Tanous                 if (ipv6Addresses)
13881abe55efSEd Tanous                 {
1389179db1d7SKowalski, Kamil                     // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1390a08b46ccSJason M. Bills                     messages::propertyNotWritable(asyncResp->res,
13910627a2c7SEd Tanous                                                   "IPv6Addresses");
1392588c3f0dSKowalski, Kamil                 }
1393588c3f0dSKowalski, Kamil             });
1394588c3f0dSKowalski, Kamil     }
13959391bb9cSRapkiewicz, Pawel };
13969391bb9cSRapkiewicz, Pawel 
1397e439f0f8SKowalski, Kamil /**
13984a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
13994a0cb85cSEd Tanous  * Schema
1400e439f0f8SKowalski, Kamil  */
14011abe55efSEd Tanous class VlanNetworkInterface : public Node
14021abe55efSEd Tanous {
1403e439f0f8SKowalski, Kamil   public:
1404e439f0f8SKowalski, Kamil     /*
1405e439f0f8SKowalski, Kamil      * Default Constructor
1406e439f0f8SKowalski, Kamil      */
1407e439f0f8SKowalski, Kamil     template <typename CrowApp>
14081abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
14094a0cb85cSEd Tanous         Node(app,
14100f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
14111abe55efSEd Tanous              std::string(), std::string())
14121abe55efSEd Tanous     {
1413e439f0f8SKowalski, Kamil         entityPrivileges = {
1414e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1415e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1416e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1417e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1418e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1419e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1420e439f0f8SKowalski, Kamil     }
1421e439f0f8SKowalski, Kamil 
1422e439f0f8SKowalski, Kamil   private:
14230f74e643SEd Tanous     void parseInterfaceData(
14240f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
14250f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
14264a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
14271abe55efSEd Tanous     {
1428e439f0f8SKowalski, Kamil         // Fill out obvious data...
14294a0cb85cSEd Tanous         json_response["Id"] = iface_id;
14304a0cb85cSEd Tanous         json_response["@odata.id"] =
14314a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
14324a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1433e439f0f8SKowalski, Kamil 
14344a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
14354a0cb85cSEd Tanous         if (ethData.vlan_id)
14364a0cb85cSEd Tanous         {
14374a0cb85cSEd Tanous             json_response["VLANId"] = *ethData.vlan_id;
14384a0cb85cSEd Tanous         }
1439e439f0f8SKowalski, Kamil     }
1440e439f0f8SKowalski, Kamil 
144155c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
14421abe55efSEd Tanous                      const std::string &iface)
14431abe55efSEd Tanous     {
1444f12894f8SJason M. Bills         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14451abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
14461abe55efSEd Tanous         {
1447f12894f8SJason M. Bills             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1448f12894f8SJason M. Bills                                        iface);
1449927a505aSKowalski, Kamil             return false;
14501abe55efSEd Tanous         }
14511abe55efSEd Tanous         else
14521abe55efSEd Tanous         {
1453927a505aSKowalski, Kamil             return true;
1454927a505aSKowalski, Kamil         }
1455927a505aSKowalski, Kamil     }
1456927a505aSKowalski, Kamil 
1457e439f0f8SKowalski, Kamil     /**
1458e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1459e439f0f8SKowalski, Kamil      */
146055c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
14611abe55efSEd Tanous                const std::vector<std::string> &params) override
14621abe55efSEd Tanous     {
14634a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14644a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1465e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1466e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1467e439f0f8SKowalski, Kamil         // impossible.
14681abe55efSEd Tanous         if (params.size() != 2)
14691abe55efSEd Tanous         {
1470f12894f8SJason M. Bills             messages::internalError(res);
1471e439f0f8SKowalski, Kamil             res.end();
1472e439f0f8SKowalski, Kamil             return;
1473e439f0f8SKowalski, Kamil         }
1474e439f0f8SKowalski, Kamil 
14754a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
14764a0cb85cSEd Tanous         const std::string &iface_id = params[1];
14770f74e643SEd Tanous         res.jsonValue["@odata.type"] =
14780f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
14790f74e643SEd Tanous         res.jsonValue["@odata.context"] =
14800f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
14810f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1482e439f0f8SKowalski, Kamil 
14834a0cb85cSEd Tanous         if (!verifyNames(res, parent_iface_id, iface_id))
14841abe55efSEd Tanous         {
1485a434f2bdSEd Tanous             return;
1486a434f2bdSEd Tanous         }
1487a434f2bdSEd Tanous 
1488e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1489e439f0f8SKowalski, Kamil         // preparation
14904a0cb85cSEd Tanous         getEthernetIfaceData(
14914a0cb85cSEd Tanous             iface_id,
14924a0cb85cSEd Tanous             [this, asyncResp, parent_iface_id, iface_id](
14934a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14944a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14954a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
14961abe55efSEd Tanous                 {
14970f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
14980f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
14990f74e643SEd Tanous                                        ipv4Data);
15001abe55efSEd Tanous                 }
15011abe55efSEd Tanous                 else
15021abe55efSEd Tanous                 {
1503e439f0f8SKowalski, Kamil                     // ... otherwise return error
15041abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15051abe55efSEd Tanous                     // object, and other errors
1506f12894f8SJason M. Bills                     messages::resourceNotFound(
1507f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1508e439f0f8SKowalski, Kamil                 }
1509e439f0f8SKowalski, Kamil             });
1510e439f0f8SKowalski, Kamil     }
1511e439f0f8SKowalski, Kamil 
151255c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
15131abe55efSEd Tanous                  const std::vector<std::string> &params) override
15141abe55efSEd Tanous     {
15154a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15161abe55efSEd Tanous         if (params.size() != 2)
15171abe55efSEd Tanous         {
1518f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1519e439f0f8SKowalski, Kamil             return;
1520e439f0f8SKowalski, Kamil         }
1521e439f0f8SKowalski, Kamil 
1522d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
152355c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1524927a505aSKowalski, Kamil 
15251abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
15261abe55efSEd Tanous         {
1527927a505aSKowalski, Kamil             return;
1528927a505aSKowalski, Kamil         }
1529927a505aSKowalski, Kamil 
15300627a2c7SEd Tanous         bool vlanEnable = false;
15310627a2c7SEd Tanous         uint64_t vlanId = 0;
15320627a2c7SEd Tanous 
15330627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
15340627a2c7SEd Tanous                                  vlanId))
15351abe55efSEd Tanous         {
1536927a505aSKowalski, Kamil             return;
1537927a505aSKowalski, Kamil         }
1538927a505aSKowalski, Kamil 
1539927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1540927a505aSKowalski, Kamil         // preparation
15414a0cb85cSEd Tanous         getEthernetIfaceData(
15421abe55efSEd Tanous             ifaceId,
15430627a2c7SEd Tanous             [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId](
15444a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
15454a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15461abe55efSEd Tanous                 if (!success)
15471abe55efSEd Tanous                 {
15481abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15491abe55efSEd Tanous                     // object, and other errors
1550f12894f8SJason M. Bills                     messages::resourceNotFound(
1551f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1552927a505aSKowalski, Kamil 
1553927a505aSKowalski, Kamil                     return;
1554927a505aSKowalski, Kamil                 }
1555927a505aSKowalski, Kamil 
15560f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
15570f74e643SEd Tanous                                    ifaceId, ethData, ipv4Data);
1558927a505aSKowalski, Kamil 
15590627a2c7SEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable,
15600627a2c7SEd Tanous                                                    ethData, asyncResp);
1561927a505aSKowalski, Kamil             });
1562e439f0f8SKowalski, Kamil     }
1563e439f0f8SKowalski, Kamil 
156455c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
15651abe55efSEd Tanous                   const std::vector<std::string> &params) override
15661abe55efSEd Tanous     {
15674a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15681abe55efSEd Tanous         if (params.size() != 2)
15691abe55efSEd Tanous         {
1570f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1571e439f0f8SKowalski, Kamil             return;
1572e439f0f8SKowalski, Kamil         }
1573e439f0f8SKowalski, Kamil 
1574d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
157555c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1576927a505aSKowalski, Kamil 
15774a0cb85cSEd Tanous         if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
15781abe55efSEd Tanous         {
1579927a505aSKowalski, Kamil             return;
1580927a505aSKowalski, Kamil         }
1581927a505aSKowalski, Kamil 
1582927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1583927a505aSKowalski, Kamil         // preparation
1584f12894f8SJason M. Bills         getEthernetIfaceData(
1585f12894f8SJason M. Bills             ifaceId,
1586f12894f8SJason M. Bills             [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
15874a0cb85cSEd Tanous              ifaceId{std::string(ifaceId)}](
1588f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1589f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15904a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
15911abe55efSEd Tanous                 {
15920f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
15930f74e643SEd Tanous                                        ifaceId, ethData, ipv4Data);
1594927a505aSKowalski, Kamil 
1595f12894f8SJason M. Bills                     auto callback =
1596f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
15971abe55efSEd Tanous                             if (ec)
15981abe55efSEd Tanous                             {
1599f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1600927a505aSKowalski, Kamil                             }
16014a0cb85cSEd Tanous                         };
16024a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
16034a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
16044a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
16054a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
16061abe55efSEd Tanous                 }
16071abe55efSEd Tanous                 else
16081abe55efSEd Tanous                 {
1609927a505aSKowalski, Kamil                     // ... otherwise return error
1610f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1611f12894f8SJason M. Bills                     // object, and other errors
1612f12894f8SJason M. Bills                     messages::resourceNotFound(
1613f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1614927a505aSKowalski, Kamil                 }
1615927a505aSKowalski, Kamil             });
1616e439f0f8SKowalski, Kamil     }
1617e439f0f8SKowalski, Kamil };
1618e439f0f8SKowalski, Kamil 
1619e439f0f8SKowalski, Kamil /**
1620e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1621e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1622e439f0f8SKowalski, Kamil  */
16231abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
16241abe55efSEd Tanous {
1625e439f0f8SKowalski, Kamil   public:
1626e439f0f8SKowalski, Kamil     template <typename CrowApp>
16271abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
16284a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
16294a0cb85cSEd Tanous              std::string())
16301abe55efSEd Tanous     {
1631e439f0f8SKowalski, Kamil         entityPrivileges = {
1632e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1633e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1634e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1635e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1636e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1637e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1638e439f0f8SKowalski, Kamil     }
1639e439f0f8SKowalski, Kamil 
1640e439f0f8SKowalski, Kamil   private:
1641e439f0f8SKowalski, Kamil     /**
1642e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1643e439f0f8SKowalski, Kamil      */
164455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
16451abe55efSEd Tanous                const std::vector<std::string> &params) override
16461abe55efSEd Tanous     {
16474a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16481abe55efSEd Tanous         if (params.size() != 1)
16491abe55efSEd Tanous         {
1650e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1651f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1652e439f0f8SKowalski, Kamil             return;
1653e439f0f8SKowalski, Kamil         }
1654e439f0f8SKowalski, Kamil 
16554a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1656e439f0f8SKowalski, Kamil 
16574a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
16581abe55efSEd Tanous         // preparation
1659f12894f8SJason M. Bills         getEthernetIfaceList(
166043b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
16611abe55efSEd Tanous                 const bool &success,
16621abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
16634a0cb85cSEd Tanous                 if (!success)
16641abe55efSEd Tanous                 {
1665f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
16664a0cb85cSEd Tanous                     return;
16671abe55efSEd Tanous                 }
16680f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
16690f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
16700f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
16710f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
16720f74e643SEd Tanous                     "/redfish/v1/$metadata"
16730f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
16740f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
16750f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
16760f74e643SEd Tanous                     "VLAN Network Interface Collection";
16774a0cb85cSEd Tanous 
16784a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
16794a0cb85cSEd Tanous 
16804a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
16811abe55efSEd Tanous                 {
16824a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
16834a0cb85cSEd Tanous                     {
16844a0cb85cSEd Tanous                         iface_array.push_back(
16854a0cb85cSEd Tanous                             {{"@odata.id",
16864a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
16874a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1688e439f0f8SKowalski, Kamil                     }
1689e439f0f8SKowalski, Kamil                 }
1690e439f0f8SKowalski, Kamil 
16914a0cb85cSEd Tanous                 if (iface_array.empty())
16921abe55efSEd Tanous                 {
1693f12894f8SJason M. Bills                     messages::resourceNotFound(
1694f12894f8SJason M. Bills                         asyncResp->res, "EthernetInterface", rootInterfaceName);
16954a0cb85cSEd Tanous                     return;
1696e439f0f8SKowalski, Kamil                 }
16974a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
16984a0cb85cSEd Tanous                     iface_array.size();
16994a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
17004a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
17014a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
17024a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1703e439f0f8SKowalski, Kamil             });
1704e439f0f8SKowalski, Kamil     }
1705e439f0f8SKowalski, Kamil 
170655c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
17071abe55efSEd Tanous                 const std::vector<std::string> &params) override
17081abe55efSEd Tanous     {
17094a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17101abe55efSEd Tanous         if (params.size() != 1)
17111abe55efSEd Tanous         {
1712f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1713e439f0f8SKowalski, Kamil             return;
1714e439f0f8SKowalski, Kamil         }
1715e439f0f8SKowalski, Kamil 
17160627a2c7SEd Tanous         uint32_t vlanId = 0;
17170627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANId", vlanId))
17181abe55efSEd Tanous         {
17194a0cb85cSEd Tanous             return;
1720e439f0f8SKowalski, Kamil         }
17214a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
17224a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
17231abe55efSEd Tanous             if (ec)
17241abe55efSEd Tanous             {
17254a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
17264a0cb85cSEd Tanous                 // phosphor-network responses
1727f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
17284a0cb85cSEd Tanous                 return;
17291abe55efSEd Tanous             }
1730f12894f8SJason M. Bills             messages::created(asyncResp->res);
1731e439f0f8SKowalski, Kamil         };
17324a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
17334a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
17344a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
17354a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
17360627a2c7SEd Tanous             rootInterfaceName, vlanId);
17374a0cb85cSEd Tanous     }
17384a0cb85cSEd Tanous };
17399391bb9cSRapkiewicz, Pawel } // namespace redfish
1740