xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision abf2add6a35aaf42ba60c4ae955a4d8925b13b19)
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>
25*abf2add6SEd 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<
35*abf2add6SEd 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<
43*abf2add6SEd Tanous             std::string,
44*abf2add6SEd Tanous             std::variant<std::string, bool, uint8_t, int16_t, uint16_t, int32_t,
45*abf2add6SEd Tanous                          uint32_t, int64_t, uint64_t, double>>>>>>;
464a0cb85cSEd Tanous 
474a0cb85cSEd Tanous enum class LinkType
484a0cb85cSEd Tanous {
494a0cb85cSEd Tanous     Local,
504a0cb85cSEd Tanous     Global
514a0cb85cSEd Tanous };
529391bb9cSRapkiewicz, Pawel 
539391bb9cSRapkiewicz, Pawel /**
549391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
559391bb9cSRapkiewicz, Pawel  */
561abe55efSEd Tanous struct IPv4AddressData
571abe55efSEd Tanous {
58179db1d7SKowalski, Kamil     std::string id;
594a0cb85cSEd Tanous     std::string address;
604a0cb85cSEd Tanous     std::string domain;
614a0cb85cSEd Tanous     std::string gateway;
629391bb9cSRapkiewicz, Pawel     std::string netmask;
639391bb9cSRapkiewicz, Pawel     std::string origin;
644a0cb85cSEd Tanous     LinkType linktype;
654a0cb85cSEd Tanous 
661abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
671abe55efSEd Tanous     {
684a0cb85cSEd Tanous         return id < obj.id;
691abe55efSEd Tanous     }
709391bb9cSRapkiewicz, Pawel };
719391bb9cSRapkiewicz, Pawel 
729391bb9cSRapkiewicz, Pawel /**
739391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
749391bb9cSRapkiewicz, Pawel  * available from DBus
759391bb9cSRapkiewicz, Pawel  */
761abe55efSEd Tanous struct EthernetInterfaceData
771abe55efSEd Tanous {
784a0cb85cSEd Tanous     uint32_t speed;
794a0cb85cSEd Tanous     bool auto_neg;
804a0cb85cSEd Tanous     std::string hostname;
814a0cb85cSEd Tanous     std::string default_gateway;
824a0cb85cSEd Tanous     std::string mac_address;
83a24526dcSEd Tanous     std::optional<uint32_t> vlan_id;
849391bb9cSRapkiewicz, Pawel };
859391bb9cSRapkiewicz, Pawel 
869391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
879391bb9cSRapkiewicz, Pawel // into full dot notation
881abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
891abe55efSEd Tanous {
909391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
919391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
929391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
939391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
949391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
959391bb9cSRapkiewicz, Pawel     return netmask;
969391bb9cSRapkiewicz, Pawel }
979391bb9cSRapkiewicz, Pawel 
984a0cb85cSEd Tanous inline std::string
994a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1004a0cb85cSEd Tanous                                         bool isIPv4)
1011abe55efSEd Tanous {
1024a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1031abe55efSEd Tanous     {
1044a0cb85cSEd Tanous         return "Static";
1059391bb9cSRapkiewicz, Pawel     }
1064a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1071abe55efSEd Tanous     {
1084a0cb85cSEd Tanous         if (isIPv4)
1091abe55efSEd Tanous         {
1104a0cb85cSEd Tanous             return "IPv4LinkLocal";
1111abe55efSEd Tanous         }
1121abe55efSEd Tanous         else
1131abe55efSEd Tanous         {
1144a0cb85cSEd Tanous             return "LinkLocal";
1159391bb9cSRapkiewicz, Pawel         }
1169391bb9cSRapkiewicz, Pawel     }
1174a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1181abe55efSEd Tanous     {
1194a0cb85cSEd Tanous         if (isIPv4)
1204a0cb85cSEd Tanous         {
1214a0cb85cSEd Tanous             return "DHCP";
1224a0cb85cSEd Tanous         }
1234a0cb85cSEd Tanous         else
1244a0cb85cSEd Tanous         {
1254a0cb85cSEd Tanous             return "DHCPv6";
1264a0cb85cSEd Tanous         }
1274a0cb85cSEd Tanous     }
1284a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1294a0cb85cSEd Tanous     {
1304a0cb85cSEd Tanous         return "SLAAC";
1314a0cb85cSEd Tanous     }
1324a0cb85cSEd Tanous     return "";
1334a0cb85cSEd Tanous }
1344a0cb85cSEd Tanous 
1354a0cb85cSEd Tanous inline std::string
1364a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1374a0cb85cSEd Tanous {
1384a0cb85cSEd Tanous     if (inputOrigin == "Static")
1394a0cb85cSEd Tanous     {
1404a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1414a0cb85cSEd Tanous     }
1424a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1434a0cb85cSEd Tanous     {
1444a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1454a0cb85cSEd Tanous     }
1464a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1474a0cb85cSEd Tanous     {
1484a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1494a0cb85cSEd Tanous     }
1504a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1514a0cb85cSEd Tanous     {
1524a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1534a0cb85cSEd Tanous     }
1544a0cb85cSEd Tanous     return "";
1554a0cb85cSEd Tanous }
1564a0cb85cSEd Tanous 
1574a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
1584a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1594a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1604a0cb85cSEd Tanous {
1614a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1624a0cb85cSEd Tanous     {
1634a0cb85cSEd Tanous         if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
1644a0cb85cSEd Tanous         {
1654a0cb85cSEd Tanous             for (const auto &ifacePair : objpath.second)
1664a0cb85cSEd Tanous             {
1674a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1684a0cb85cSEd Tanous                 {
1694a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1704a0cb85cSEd Tanous                     {
1714a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1724a0cb85cSEd Tanous                         {
1734a0cb85cSEd Tanous                             const std::string *mac =
174*abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1754a0cb85cSEd Tanous                             if (mac != nullptr)
1764a0cb85cSEd Tanous                             {
1774a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1784a0cb85cSEd Tanous                             }
1794a0cb85cSEd Tanous                         }
1804a0cb85cSEd Tanous                     }
1814a0cb85cSEd Tanous                 }
1824a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1834a0cb85cSEd Tanous                 {
1844a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1854a0cb85cSEd Tanous                     {
1864a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1874a0cb85cSEd Tanous                         {
1881b6b96c5SEd Tanous                             const uint32_t *id =
189*abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1904a0cb85cSEd Tanous                             if (id != nullptr)
1914a0cb85cSEd Tanous                             {
1924a0cb85cSEd Tanous                                 ethData.vlan_id = *id;
1934a0cb85cSEd Tanous                             }
1944a0cb85cSEd Tanous                         }
1954a0cb85cSEd Tanous                     }
1964a0cb85cSEd Tanous                 }
1974a0cb85cSEd Tanous                 else if (ifacePair.first ==
1984a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
1994a0cb85cSEd Tanous                 {
2004a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2014a0cb85cSEd Tanous                     {
2024a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2034a0cb85cSEd Tanous                         {
2044a0cb85cSEd Tanous                             const bool *auto_neg =
205*abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2064a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2074a0cb85cSEd Tanous                             {
2084a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2094a0cb85cSEd Tanous                             }
2104a0cb85cSEd Tanous                         }
2114a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2124a0cb85cSEd Tanous                         {
2134a0cb85cSEd Tanous                             const uint32_t *speed =
214*abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2154a0cb85cSEd Tanous                             if (speed != nullptr)
2164a0cb85cSEd Tanous                             {
2174a0cb85cSEd Tanous                                 ethData.speed = *speed;
2184a0cb85cSEd Tanous                             }
2194a0cb85cSEd Tanous                         }
2204a0cb85cSEd Tanous                     }
2214a0cb85cSEd Tanous                 }
2224a0cb85cSEd Tanous                 else if (ifacePair.first ==
2234a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.SystemConfiguration")
2244a0cb85cSEd Tanous                 {
2254a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2264a0cb85cSEd Tanous                     {
2274a0cb85cSEd Tanous                         if (propertyPair.first == "HostName")
2284a0cb85cSEd Tanous                         {
2294a0cb85cSEd Tanous                             const std::string *hostname =
230*abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
2314a0cb85cSEd Tanous                             if (hostname != nullptr)
2324a0cb85cSEd Tanous                             {
2334a0cb85cSEd Tanous                                 ethData.hostname = *hostname;
2344a0cb85cSEd Tanous                             }
2354a0cb85cSEd Tanous                         }
2364a0cb85cSEd Tanous                         else if (propertyPair.first == "DefaultGateway")
2374a0cb85cSEd Tanous                         {
2384a0cb85cSEd Tanous                             const std::string *defaultGateway =
239*abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
2404a0cb85cSEd Tanous                             if (defaultGateway != nullptr)
2414a0cb85cSEd Tanous                             {
2424a0cb85cSEd Tanous                                 ethData.default_gateway = *defaultGateway;
2434a0cb85cSEd Tanous                             }
2444a0cb85cSEd Tanous                         }
2454a0cb85cSEd Tanous                     }
2464a0cb85cSEd Tanous                 }
2474a0cb85cSEd Tanous             }
2484a0cb85cSEd Tanous         }
2494a0cb85cSEd Tanous     }
2504a0cb85cSEd Tanous }
2514a0cb85cSEd Tanous 
2524a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2534a0cb85cSEd Tanous inline void
2544a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2554a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2564a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2574a0cb85cSEd Tanous {
2584a0cb85cSEd Tanous     const std::string ipv4PathStart =
2594a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
2604a0cb85cSEd Tanous 
2614a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
2624a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
2634a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
2644a0cb85cSEd Tanous     {
2654a0cb85cSEd Tanous         // Check if proper pattern for object path appears
2664a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
2674a0cb85cSEd Tanous         {
2684a0cb85cSEd Tanous             for (auto &interface : objpath.second)
2694a0cb85cSEd Tanous             {
2704a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
2714a0cb85cSEd Tanous                 {
2724a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
2734a0cb85cSEd Tanous                     // appropriate
2744a0cb85cSEd Tanous                     std::pair<
2754a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
2764a0cb85cSEd Tanous                         bool>
2774a0cb85cSEd Tanous                         it = ipv4_config.insert(
2784a0cb85cSEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
2794a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
2804a0cb85cSEd Tanous                     for (auto &property : interface.second)
2814a0cb85cSEd Tanous                     {
2824a0cb85cSEd Tanous                         if (property.first == "Address")
2834a0cb85cSEd Tanous                         {
2844a0cb85cSEd Tanous                             const std::string *address =
285*abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
2864a0cb85cSEd Tanous                             if (address != nullptr)
2874a0cb85cSEd Tanous                             {
2884a0cb85cSEd Tanous                                 ipv4_address.address = *address;
2894a0cb85cSEd Tanous                             }
2904a0cb85cSEd Tanous                         }
2914a0cb85cSEd Tanous                         else if (property.first == "Gateway")
2924a0cb85cSEd Tanous                         {
2934a0cb85cSEd Tanous                             const std::string *gateway =
294*abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
2954a0cb85cSEd Tanous                             if (gateway != nullptr)
2964a0cb85cSEd Tanous                             {
2974a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
2984a0cb85cSEd Tanous                             }
2994a0cb85cSEd Tanous                         }
3004a0cb85cSEd Tanous                         else if (property.first == "Origin")
3014a0cb85cSEd Tanous                         {
3024a0cb85cSEd Tanous                             const std::string *origin =
303*abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3044a0cb85cSEd Tanous                             if (origin != nullptr)
3054a0cb85cSEd Tanous                             {
3064a0cb85cSEd Tanous                                 ipv4_address.origin =
3074a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3084a0cb85cSEd Tanous                                                                         true);
3094a0cb85cSEd Tanous                             }
3104a0cb85cSEd Tanous                         }
3114a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3124a0cb85cSEd Tanous                         {
3134a0cb85cSEd Tanous                             const uint8_t *mask =
314*abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
3154a0cb85cSEd Tanous                             if (mask != nullptr)
3164a0cb85cSEd Tanous                             {
3174a0cb85cSEd Tanous                                 // convert it to the string
3184a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3194a0cb85cSEd Tanous                             }
3204a0cb85cSEd Tanous                         }
3214a0cb85cSEd Tanous                         else
3224a0cb85cSEd Tanous                         {
3234a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3244a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3254a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3264a0cb85cSEd Tanous                         }
3274a0cb85cSEd Tanous                     }
3284a0cb85cSEd Tanous                     // Check if given address is local, or global
3294a0cb85cSEd Tanous                     ipv4_address.linktype =
3304a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3314a0cb85cSEd Tanous                             ? LinkType::Global
3324a0cb85cSEd Tanous                             : LinkType::Local;
3334a0cb85cSEd Tanous                 }
3344a0cb85cSEd Tanous             }
3354a0cb85cSEd Tanous         }
3364a0cb85cSEd Tanous     }
3374a0cb85cSEd Tanous }
338588c3f0dSKowalski, Kamil 
339588c3f0dSKowalski, Kamil /**
340588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
341588c3f0dSKowalski, Kamil  *
342588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
343588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
344588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
345588c3f0dSKowalski, Kamil  *
346588c3f0dSKowalski, Kamil  * @return None.
347588c3f0dSKowalski, Kamil  */
348588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3494a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3501abe55efSEd Tanous                   CallbackFunc &&callback)
3511abe55efSEd Tanous {
35255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
353588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
354588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
355588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
356588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
357*abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
3584a0cb85cSEd Tanous }
359588c3f0dSKowalski, Kamil 
360588c3f0dSKowalski, Kamil /**
361179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
362179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
363179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
364179db1d7SKowalski, Kamil  *
365179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
366179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
367179db1d7SKowalski, Kamil  *
368179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
369179db1d7SKowalski, Kamil  */
3704a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
3711abe55efSEd Tanous                                        uint8_t *bits = nullptr)
3721abe55efSEd Tanous {
373179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
374179db1d7SKowalski, Kamil 
375179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
376179db1d7SKowalski, Kamil 
3774a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
3781abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
3791abe55efSEd Tanous     {
380179db1d7SKowalski, Kamil         return false;
381179db1d7SKowalski, Kamil     }
382179db1d7SKowalski, Kamil 
3831abe55efSEd Tanous     if (bits != nullptr)
3841abe55efSEd Tanous     {
385179db1d7SKowalski, Kamil         *bits = 0;
386179db1d7SKowalski, Kamil     }
387179db1d7SKowalski, Kamil 
388179db1d7SKowalski, Kamil     char *endPtr;
389179db1d7SKowalski, Kamil     long previousValue = 255;
390179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
3911abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
3921abe55efSEd Tanous     {
3931abe55efSEd Tanous         if (byte.empty())
3941abe55efSEd Tanous         {
3951db9ca37SKowalski, Kamil             return false;
3961db9ca37SKowalski, Kamil         }
3971db9ca37SKowalski, Kamil 
398179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
3991db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
400179db1d7SKowalski, Kamil 
4014a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4024a0cb85cSEd Tanous         // is not 100% number
4031abe55efSEd Tanous         if (*endPtr != '\0')
4041abe55efSEd Tanous         {
405179db1d7SKowalski, Kamil             return false;
406179db1d7SKowalski, Kamil         }
407179db1d7SKowalski, Kamil 
408179db1d7SKowalski, Kamil         // Value should be contained in byte
4091abe55efSEd Tanous         if (value < 0 || value > 255)
4101abe55efSEd Tanous         {
411179db1d7SKowalski, Kamil             return false;
412179db1d7SKowalski, Kamil         }
413179db1d7SKowalski, Kamil 
4141abe55efSEd Tanous         if (bits != nullptr)
4151abe55efSEd Tanous         {
416179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4171abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4181abe55efSEd Tanous             {
419179db1d7SKowalski, Kamil                 return false;
420179db1d7SKowalski, Kamil             }
421179db1d7SKowalski, Kamil 
422179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
423179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
424179db1d7SKowalski, Kamil 
425179db1d7SKowalski, Kamil             // Count bits
4261abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4271abe55efSEd Tanous             {
4281abe55efSEd Tanous                 if (value & (1 << bitIdx))
4291abe55efSEd Tanous                 {
4301abe55efSEd Tanous                     if (firstZeroInByteHit)
4311abe55efSEd Tanous                     {
432179db1d7SKowalski, Kamil                         // Continuity not preserved
433179db1d7SKowalski, Kamil                         return false;
4341abe55efSEd Tanous                     }
4351abe55efSEd Tanous                     else
4361abe55efSEd Tanous                     {
437179db1d7SKowalski, Kamil                         (*bits)++;
438179db1d7SKowalski, Kamil                     }
4391abe55efSEd Tanous                 }
4401abe55efSEd Tanous                 else
4411abe55efSEd Tanous                 {
442179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
443179db1d7SKowalski, Kamil                 }
444179db1d7SKowalski, Kamil             }
445179db1d7SKowalski, Kamil         }
446179db1d7SKowalski, Kamil 
447179db1d7SKowalski, Kamil         previousValue = value;
448179db1d7SKowalski, Kamil     }
449179db1d7SKowalski, Kamil 
450179db1d7SKowalski, Kamil     return true;
451179db1d7SKowalski, Kamil }
452179db1d7SKowalski, Kamil 
453179db1d7SKowalski, Kamil /**
454179db1d7SKowalski, Kamil  * @brief Changes IPv4 address type property (Address, Gateway)
455179db1d7SKowalski, Kamil  *
456179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be modified
4574a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
458179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of modified IP
459179db1d7SKowalski, Kamil  * @param[in] name        Name of field in JSON representation
460179db1d7SKowalski, Kamil  * @param[in] newValue    New value that should be written
461179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
462179db1d7SKowalski, Kamil  *
463179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
464179db1d7SKowalski, Kamil  * otherwise
465179db1d7SKowalski, Kamil  */
4664a0cb85cSEd Tanous inline void changeIPv4AddressProperty(
4674a0cb85cSEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
4684a0cb85cSEd Tanous     const std::string &name, const std::string &newValue,
4694a0cb85cSEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
4701abe55efSEd Tanous {
4714a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
4724a0cb85cSEd Tanous                      newValue{std::move(newValue)}](
4731abe55efSEd Tanous                         const boost::system::error_code ec) {
4741abe55efSEd Tanous         if (ec)
4751abe55efSEd Tanous         {
476a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
4771abe55efSEd Tanous         }
4781abe55efSEd Tanous         else
4791abe55efSEd Tanous         {
4804a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
481179db1d7SKowalski, Kamil         }
482179db1d7SKowalski, Kamil     };
483179db1d7SKowalski, Kamil 
48455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
485179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
486179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
487179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
488179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", name,
489*abf2add6SEd Tanous         std::variant<std::string>(newValue));
4904a0cb85cSEd Tanous }
491179db1d7SKowalski, Kamil 
492179db1d7SKowalski, Kamil /**
493179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
494179db1d7SKowalski, Kamil  *
495179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
4964a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
4971abe55efSEd Tanous  * modified
498179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
499179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
500179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
501179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
502179db1d7SKowalski, Kamil  *
503179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
504179db1d7SKowalski, Kamil  * otherwise
505179db1d7SKowalski, Kamil  */
5064a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5071abe55efSEd Tanous                              const std::string &ipHash,
5081abe55efSEd Tanous                              const std::string &newValue,
509179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5104a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5111abe55efSEd Tanous {
5124a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5131abe55efSEd Tanous                         const boost::system::error_code ec) {
5141abe55efSEd Tanous         if (ec)
5151abe55efSEd Tanous         {
516a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5171abe55efSEd Tanous         }
5181abe55efSEd Tanous         else
5191abe55efSEd Tanous         {
5204a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
521179db1d7SKowalski, Kamil                 newValue;
522179db1d7SKowalski, Kamil         }
523179db1d7SKowalski, Kamil     };
524179db1d7SKowalski, Kamil 
52555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
526179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
527179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
528179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
529179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
530*abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
5314a0cb85cSEd Tanous }
532179db1d7SKowalski, Kamil 
533179db1d7SKowalski, Kamil /**
534179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
535179db1d7SKowalski, Kamil  *
536179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5374a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5381abe55efSEd Tanous  * modified
539179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
540179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
541179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
542179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
543179db1d7SKowalski, Kamil  *
544179db1d7SKowalski, Kamil  * @return None
545179db1d7SKowalski, Kamil  */
5464a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5474a0cb85cSEd Tanous                                          const std::string &ipHash,
5484a0cb85cSEd Tanous                                          const std::string &newValueStr,
5494a0cb85cSEd Tanous                                          uint8_t &newValue,
5504a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5511abe55efSEd Tanous {
5524a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5531abe55efSEd Tanous                         const boost::system::error_code ec) {
5541abe55efSEd Tanous         if (ec)
5551abe55efSEd Tanous         {
556a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5571abe55efSEd Tanous         }
5581abe55efSEd Tanous         else
5591abe55efSEd Tanous         {
56055c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
561179db1d7SKowalski, Kamil                 newValueStr;
562179db1d7SKowalski, Kamil         }
563179db1d7SKowalski, Kamil     };
564179db1d7SKowalski, Kamil 
56555c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
566179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
567179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
568179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
569179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
570*abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
5714a0cb85cSEd Tanous }
572588c3f0dSKowalski, Kamil 
573588c3f0dSKowalski, Kamil /**
574179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
575179db1d7SKowalski, Kamil  *
576179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
5774a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
578179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
579179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
580179db1d7SKowalski, Kamil  *
581179db1d7SKowalski, Kamil  * @return None
582179db1d7SKowalski, Kamil  */
5834a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
584179db1d7SKowalski, Kamil                        unsigned int ipIdx,
5854a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
5861abe55efSEd Tanous {
58755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
5884a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
5891abe55efSEd Tanous             if (ec)
5901abe55efSEd Tanous             {
591a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
5921abe55efSEd Tanous             }
5931abe55efSEd Tanous             else
5941abe55efSEd Tanous             {
59555c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
596179db1d7SKowalski, Kamil             }
597179db1d7SKowalski, Kamil         },
598179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
599179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
600179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
601179db1d7SKowalski, Kamil }
602179db1d7SKowalski, Kamil 
603179db1d7SKowalski, Kamil /**
604179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
605179db1d7SKowalski, Kamil  *
606179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6074a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
608179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
609179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
610179db1d7SKowalski, Kamil  *
611179db1d7SKowalski, Kamil  * @return None
612179db1d7SKowalski, Kamil  */
6134a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
614179db1d7SKowalski, Kamil                        uint8_t subnetMask, const std::string &gateway,
615179db1d7SKowalski, Kamil                        const std::string &address,
6164a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6171abe55efSEd Tanous {
6184a0cb85cSEd Tanous     auto createIpHandler = [ipIdx,
6194a0cb85cSEd Tanous                             asyncResp](const boost::system::error_code ec) {
6201abe55efSEd Tanous         if (ec)
6211abe55efSEd Tanous         {
622a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
623179db1d7SKowalski, Kamil         }
624179db1d7SKowalski, Kamil     };
625179db1d7SKowalski, Kamil 
62655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
627179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
628179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
629179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
630179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
631179db1d7SKowalski, Kamil         gateway);
632179db1d7SKowalski, Kamil }
633179db1d7SKowalski, Kamil 
634179db1d7SKowalski, Kamil /**
635179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
636179db1d7SKowalski, Kamil  * Object
637179db1d7SKowalski, Kamil  * from EntityManager Network Manager
6384a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
639179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
640179db1d7SKowalski, Kamil  * into JSON
641179db1d7SKowalski, Kamil  */
642179db1d7SKowalski, Kamil template <typename CallbackFunc>
6434a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
6441abe55efSEd Tanous                           CallbackFunc &&callback)
6451abe55efSEd Tanous {
64655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6474a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
6481abe55efSEd Tanous             const boost::system::error_code error_code,
6494a0cb85cSEd Tanous             const GetManagedObjects &resp) {
65055c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
6514a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
652179db1d7SKowalski, Kamil 
6531abe55efSEd Tanous             if (error_code)
6541abe55efSEd Tanous             {
65555c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
656179db1d7SKowalski, Kamil                 return;
657179db1d7SKowalski, Kamil             }
658179db1d7SKowalski, Kamil 
6594a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
6604a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
661179db1d7SKowalski, Kamil 
662179db1d7SKowalski, Kamil             // Fix global GW
6631abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
6641abe55efSEd Tanous             {
6654a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
6664a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
6671abe55efSEd Tanous                 {
6684a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
669179db1d7SKowalski, Kamil                 }
670179db1d7SKowalski, Kamil             }
671179db1d7SKowalski, Kamil 
6724a0cb85cSEd Tanous             // Finally make a callback with usefull data
67355c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
674179db1d7SKowalski, Kamil         },
675179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
676179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
677179db1d7SKowalski, Kamil };
678179db1d7SKowalski, Kamil 
679179db1d7SKowalski, Kamil /**
6809391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
6819391bb9cSRapkiewicz, Pawel  * Manager
6821abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
6831abe55efSEd Tanous  * into JSON.
6849391bb9cSRapkiewicz, Pawel  */
6859391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
6861abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
6871abe55efSEd Tanous {
68855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6894a0cb85cSEd Tanous         [callback{std::move(callback)}](
6909391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
6914a0cb85cSEd Tanous             GetManagedObjects &resp) {
6921abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
6931abe55efSEd Tanous             // ethernet interfaces
6944a0cb85cSEd Tanous             std::vector<std::string> iface_list;
6954a0cb85cSEd Tanous             iface_list.reserve(resp.size());
6961abe55efSEd Tanous             if (error_code)
6971abe55efSEd Tanous             {
6984a0cb85cSEd Tanous                 callback(false, iface_list);
6999391bb9cSRapkiewicz, Pawel                 return;
7009391bb9cSRapkiewicz, Pawel             }
7019391bb9cSRapkiewicz, Pawel 
7029391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7034a0cb85cSEd Tanous             for (const auto &objpath : resp)
7041abe55efSEd Tanous             {
7059391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7064a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7071abe55efSEd Tanous                 {
7081abe55efSEd Tanous                     // If interface is
7094a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
7104a0cb85cSEd Tanous                     // what we're looking for.
7119391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7121abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7131abe55efSEd Tanous                     {
7144a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
7154a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
7164a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
7174a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7181abe55efSEd Tanous                         {
7199391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
7204a0cb85cSEd Tanous                             iface_list.emplace_back(
7214a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
7229391bb9cSRapkiewicz, Pawel                         }
7239391bb9cSRapkiewicz, Pawel                     }
7249391bb9cSRapkiewicz, Pawel                 }
7259391bb9cSRapkiewicz, Pawel             }
726a434f2bdSEd Tanous             // Finally make a callback with useful data
7274a0cb85cSEd Tanous             callback(true, iface_list);
7289391bb9cSRapkiewicz, Pawel         },
729aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
730aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7319391bb9cSRapkiewicz, Pawel };
7329391bb9cSRapkiewicz, Pawel 
7339391bb9cSRapkiewicz, Pawel /**
7349391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
7359391bb9cSRapkiewicz, Pawel  */
7361abe55efSEd Tanous class EthernetCollection : public Node
7371abe55efSEd Tanous {
7389391bb9cSRapkiewicz, Pawel   public:
7394a0cb85cSEd Tanous     template <typename CrowApp>
7401abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
7414a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
7421abe55efSEd Tanous     {
743588c3f0dSKowalski, Kamil         entityPrivileges = {
744588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
745e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
746e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
747e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
748e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
749e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
7509391bb9cSRapkiewicz, Pawel     }
7519391bb9cSRapkiewicz, Pawel 
7529391bb9cSRapkiewicz, Pawel   private:
7539391bb9cSRapkiewicz, Pawel     /**
7549391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
7559391bb9cSRapkiewicz, Pawel      */
75655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
7571abe55efSEd Tanous                const std::vector<std::string> &params) override
7581abe55efSEd Tanous     {
7590f74e643SEd Tanous         res.jsonValue["@odata.type"] =
7600f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
7610f74e643SEd Tanous         res.jsonValue["@odata.context"] =
7620f74e643SEd Tanous             "/redfish/v1/"
7630f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
7640f74e643SEd Tanous         res.jsonValue["@odata.id"] =
7650f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
7660f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
7670f74e643SEd Tanous         res.jsonValue["Description"] =
7680f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
7690f74e643SEd Tanous 
7704a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
7711abe55efSEd Tanous         // preparation
772f12894f8SJason M. Bills         getEthernetIfaceList(
773f12894f8SJason M. Bills             [&res](const bool &success,
7741abe55efSEd Tanous                    const std::vector<std::string> &iface_list) {
7754a0cb85cSEd Tanous                 if (!success)
7761abe55efSEd Tanous                 {
777f12894f8SJason M. Bills                     messages::internalError(res);
7784a0cb85cSEd Tanous                     res.end();
7794a0cb85cSEd Tanous                     return;
7804a0cb85cSEd Tanous                 }
7814a0cb85cSEd Tanous 
7824a0cb85cSEd Tanous                 nlohmann::json &iface_array = res.jsonValue["Members"];
7834a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
7844a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
7851abe55efSEd Tanous                 {
7864a0cb85cSEd Tanous                     iface_array.push_back(
7874a0cb85cSEd Tanous                         {{"@odata.id",
7884a0cb85cSEd Tanous                           "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
7894a0cb85cSEd Tanous                               iface_item}});
7909391bb9cSRapkiewicz, Pawel                 }
7914a0cb85cSEd Tanous 
7924a0cb85cSEd Tanous                 res.jsonValue["Members@odata.count"] = iface_array.size();
7934a0cb85cSEd Tanous                 res.jsonValue["@odata.id"] =
7944a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
7959391bb9cSRapkiewicz, Pawel                 res.end();
7969391bb9cSRapkiewicz, Pawel             });
7979391bb9cSRapkiewicz, Pawel     }
7989391bb9cSRapkiewicz, Pawel };
7999391bb9cSRapkiewicz, Pawel 
8009391bb9cSRapkiewicz, Pawel /**
8019391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8029391bb9cSRapkiewicz, Pawel  */
8031abe55efSEd Tanous class EthernetInterface : public Node
8041abe55efSEd Tanous {
8059391bb9cSRapkiewicz, Pawel   public:
8069391bb9cSRapkiewicz, Pawel     /*
8079391bb9cSRapkiewicz, Pawel      * Default Constructor
8089391bb9cSRapkiewicz, Pawel      */
8094a0cb85cSEd Tanous     template <typename CrowApp>
8101abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
8114a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8121abe55efSEd Tanous              std::string())
8131abe55efSEd Tanous     {
814588c3f0dSKowalski, Kamil         entityPrivileges = {
815588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
816e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
817e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
818e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
819e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
820e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8219391bb9cSRapkiewicz, Pawel     }
8229391bb9cSRapkiewicz, Pawel 
823e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
8240627a2c7SEd Tanous     static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable,
8250627a2c7SEd Tanous                                 uint64_t vlanId,
8264a0cb85cSEd Tanous                                 const EthernetInterfaceData &ethData,
8274a0cb85cSEd Tanous                                 const std::shared_ptr<AsyncResp> asyncResp)
8281abe55efSEd Tanous     {
8294a0cb85cSEd Tanous         if (!ethData.vlan_id)
8301abe55efSEd Tanous         {
831e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
832e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
833a08b46ccSJason M. Bills             messages::propertyNotWritable(asyncResp->res, "VLANEnable");
834588c3f0dSKowalski, Kamil 
835588c3f0dSKowalski, Kamil             return;
836588c3f0dSKowalski, Kamil         }
837588c3f0dSKowalski, Kamil 
838588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
8390627a2c7SEd Tanous         if (vlanEnable == true)
8401abe55efSEd Tanous         {
841588c3f0dSKowalski, Kamil             // Change VLAN Id
8420627a2c7SEd Tanous             asyncResp->res.jsonValue["VLANId"] = vlanId;
8434a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
8441abe55efSEd Tanous                 if (ec)
8451abe55efSEd Tanous                 {
846f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8471abe55efSEd Tanous                 }
8481abe55efSEd Tanous                 else
8491abe55efSEd Tanous                 {
8504a0cb85cSEd Tanous                     asyncResp->res.jsonValue["VLANEnable"] = true;
851e439f0f8SKowalski, Kamil                 }
8524a0cb85cSEd Tanous             };
8534a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
8544a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
8554a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
8564a0cb85cSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
8574a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.VLAN", "Id",
858*abf2add6SEd Tanous                 std::variant<uint32_t>(vlanId));
8591abe55efSEd Tanous         }
8604a0cb85cSEd Tanous         else
8611abe55efSEd Tanous         {
8624a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
8631abe55efSEd Tanous                 if (ec)
8641abe55efSEd Tanous                 {
865f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8664a0cb85cSEd Tanous                     return;
8671abe55efSEd Tanous                 }
8684a0cb85cSEd Tanous                 asyncResp->res.jsonValue["VLANEnable"] = false;
8694a0cb85cSEd Tanous             };
8704a0cb85cSEd Tanous 
8714a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
8724a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
8734a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
8744a0cb85cSEd Tanous                 "xyz.openbmc_project.Object.Delete", "Delete");
875588c3f0dSKowalski, Kamil         }
876588c3f0dSKowalski, Kamil     }
877588c3f0dSKowalski, Kamil 
878e439f0f8SKowalski, Kamil   private:
879bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
8804a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
8811abe55efSEd Tanous     {
882bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
883bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
884bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
8854a0cb85cSEd Tanous                 if (ec)
8864a0cb85cSEd Tanous                 {
887a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
8881abe55efSEd Tanous                 }
889bc0bd6e0SEd Tanous             },
890bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
891bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
892bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
893bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
894*abf2add6SEd Tanous             std::variant<std::string>(hostname));
895588c3f0dSKowalski, Kamil     }
896588c3f0dSKowalski, Kamil 
8974a0cb85cSEd Tanous     void handleIPv4Patch(
8984a0cb85cSEd Tanous         const std::string &ifaceId, const nlohmann::json &input,
8994a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
9004a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
9011abe55efSEd Tanous     {
9021abe55efSEd Tanous         if (!input.is_array())
9031abe55efSEd Tanous         {
904f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, input.dump(),
905a08b46ccSJason M. Bills                                              "IPv4Addresses");
906179db1d7SKowalski, Kamil             return;
907179db1d7SKowalski, Kamil         }
908179db1d7SKowalski, Kamil 
909179db1d7SKowalski, Kamil         // According to Redfish PATCH definition, size must be at least equal
9104a0cb85cSEd Tanous         if (input.size() < ipv4Data.size())
9111abe55efSEd Tanous         {
912a08b46ccSJason M. Bills             messages::propertyValueFormatError(asyncResp->res, input.dump(),
913a08b46ccSJason M. Bills                                                "IPv4Addresses");
914179db1d7SKowalski, Kamil             return;
915179db1d7SKowalski, Kamil         }
916179db1d7SKowalski, Kamil 
9174a0cb85cSEd Tanous         int entryIdx = 0;
9184a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
9194a0cb85cSEd Tanous             ipv4Data.begin();
9204a0cb85cSEd Tanous         for (const nlohmann::json &thisJson : input)
9211abe55efSEd Tanous         {
9224a0cb85cSEd Tanous             std::string pathString =
923a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
924179db1d7SKowalski, Kamil             // Check that entry is not of some unexpected type
9254a0cb85cSEd Tanous             if (!thisJson.is_object() && !thisJson.is_null())
9261abe55efSEd Tanous             {
927a08b46ccSJason M. Bills                 messages::propertyValueTypeError(asyncResp->res,
928a08b46ccSJason M. Bills                                                  thisJson.dump(),
929a08b46ccSJason M. Bills                                                  pathString + "/IPv4Address");
930179db1d7SKowalski, Kamil 
931179db1d7SKowalski, Kamil                 continue;
932179db1d7SKowalski, Kamil             }
933179db1d7SKowalski, Kamil 
9344a0cb85cSEd Tanous             nlohmann::json::const_iterator addressFieldIt =
9354a0cb85cSEd Tanous                 thisJson.find("Address");
9364a0cb85cSEd Tanous             const std::string *addressField = nullptr;
9374a0cb85cSEd Tanous             if (addressFieldIt != thisJson.end())
9381abe55efSEd Tanous             {
9394a0cb85cSEd Tanous                 addressField = addressFieldIt->get_ptr<const std::string *>();
9404a0cb85cSEd Tanous                 if (addressField == nullptr)
9411abe55efSEd Tanous                 {
942a08b46ccSJason M. Bills                     messages::propertyValueFormatError(asyncResp->res,
943a08b46ccSJason M. Bills                                                        addressFieldIt->dump(),
9444a0cb85cSEd Tanous                                                        pathString + "/Address");
945179db1d7SKowalski, Kamil                     continue;
946179db1d7SKowalski, Kamil                 }
9471abe55efSEd Tanous                 else
9481abe55efSEd Tanous                 {
9494a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*addressField))
9504a0cb85cSEd Tanous                     {
951f12894f8SJason M. Bills                         messages::propertyValueFormatError(
952a08b46ccSJason M. Bills                             asyncResp->res, *addressField,
9534a0cb85cSEd Tanous                             pathString + "/Address");
9544a0cb85cSEd Tanous                         continue;
9554a0cb85cSEd Tanous                     }
9564a0cb85cSEd Tanous                 }
9574a0cb85cSEd Tanous             }
9584a0cb85cSEd Tanous 
959a24526dcSEd Tanous             std::optional<uint8_t> prefixLength;
9604a0cb85cSEd Tanous             const std::string *subnetField = nullptr;
9614a0cb85cSEd Tanous             nlohmann::json::const_iterator subnetFieldIt =
9624a0cb85cSEd Tanous                 thisJson.find("SubnetMask");
9634a0cb85cSEd Tanous             if (subnetFieldIt != thisJson.end())
9644a0cb85cSEd Tanous             {
9654a0cb85cSEd Tanous                 subnetField = subnetFieldIt->get_ptr<const std::string *>();
9664a0cb85cSEd Tanous                 if (subnetField == nullptr)
9674a0cb85cSEd Tanous                 {
968f12894f8SJason M. Bills                     messages::propertyValueFormatError(
969a08b46ccSJason M. Bills                         asyncResp->res, *subnetField,
9704a0cb85cSEd Tanous                         pathString + "/SubnetMask");
9714a0cb85cSEd Tanous                     continue;
9724a0cb85cSEd Tanous                 }
9734a0cb85cSEd Tanous                 else
9744a0cb85cSEd Tanous                 {
9754a0cb85cSEd Tanous                     prefixLength = 0;
9764a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*subnetField,
9774a0cb85cSEd Tanous                                                     &*prefixLength))
9784a0cb85cSEd Tanous                     {
979f12894f8SJason M. Bills                         messages::propertyValueFormatError(
980a08b46ccSJason M. Bills                             asyncResp->res, *subnetField,
9814a0cb85cSEd Tanous                             pathString + "/SubnetMask");
9824a0cb85cSEd Tanous                         continue;
9834a0cb85cSEd Tanous                     }
9844a0cb85cSEd Tanous                 }
9854a0cb85cSEd Tanous             }
9864a0cb85cSEd Tanous 
9874a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
9884a0cb85cSEd Tanous             const std::string *addressOriginField = nullptr;
9894a0cb85cSEd Tanous             nlohmann::json::const_iterator addressOriginFieldIt =
9904a0cb85cSEd Tanous                 thisJson.find("AddressOrigin");
9914a0cb85cSEd Tanous             if (addressOriginFieldIt != thisJson.end())
9924a0cb85cSEd Tanous             {
9934a0cb85cSEd Tanous                 const std::string *addressOriginField =
9944a0cb85cSEd Tanous                     addressOriginFieldIt->get_ptr<const std::string *>();
9954a0cb85cSEd Tanous                 if (addressOriginField == nullptr)
9964a0cb85cSEd Tanous                 {
997f12894f8SJason M. Bills                     messages::propertyValueFormatError(
998a08b46ccSJason M. Bills                         asyncResp->res, *addressOriginField,
9994a0cb85cSEd Tanous                         pathString + "/AddressOrigin");
10004a0cb85cSEd Tanous                     continue;
10014a0cb85cSEd Tanous                 }
10024a0cb85cSEd Tanous                 else
10034a0cb85cSEd Tanous                 {
10044a0cb85cSEd Tanous                     // Get Address origin in proper format
10054a0cb85cSEd Tanous                     addressOriginInDBusFormat =
10064a0cb85cSEd Tanous                         translateAddressOriginRedfishToDbus(
10074a0cb85cSEd Tanous                             *addressOriginField);
10084a0cb85cSEd Tanous                     if (addressOriginInDBusFormat.empty())
10094a0cb85cSEd Tanous                     {
10104a0cb85cSEd Tanous                         messages::propertyValueNotInList(
1011f12894f8SJason M. Bills                             asyncResp->res, *addressOriginField,
1012a08b46ccSJason M. Bills                             pathString + "/AddressOrigin");
10134a0cb85cSEd Tanous                         continue;
10144a0cb85cSEd Tanous                     }
10154a0cb85cSEd Tanous                 }
10164a0cb85cSEd Tanous             }
10174a0cb85cSEd Tanous 
10184a0cb85cSEd Tanous             nlohmann::json::const_iterator gatewayFieldIt =
10194a0cb85cSEd Tanous                 thisJson.find("Gateway");
10204a0cb85cSEd Tanous             const std::string *gatewayField = nullptr;
10214a0cb85cSEd Tanous             if (gatewayFieldIt != thisJson.end())
10224a0cb85cSEd Tanous             {
10234a0cb85cSEd Tanous                 const std::string *gatewayField =
10244a0cb85cSEd Tanous                     gatewayFieldIt->get_ptr<const std::string *>();
10254a0cb85cSEd Tanous                 if (gatewayField == nullptr ||
10264a0cb85cSEd Tanous                     !ipv4VerifyIpAndGetBitcount(*gatewayField))
10274a0cb85cSEd Tanous                 {
1028a08b46ccSJason M. Bills                     messages::propertyValueFormatError(
1029a08b46ccSJason M. Bills                         asyncResp->res, *gatewayField, pathString + "/Gateway");
10304a0cb85cSEd Tanous                     continue;
10314a0cb85cSEd Tanous                 }
10324a0cb85cSEd Tanous             }
10334a0cb85cSEd Tanous 
10344a0cb85cSEd Tanous             // if a vlan already exists, modify the existing
10354a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
10364a0cb85cSEd Tanous             {
10371abe55efSEd Tanous                 // Existing object that should be modified/deleted/remain
10381abe55efSEd Tanous                 // unchanged
10394a0cb85cSEd Tanous                 if (thisJson.is_null())
10401abe55efSEd Tanous                 {
10414a0cb85cSEd Tanous                     auto callback = [entryIdx{std::to_string(entryIdx)},
10424a0cb85cSEd Tanous                                      asyncResp](
10434a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
10444a0cb85cSEd Tanous                         if (ec)
10454a0cb85cSEd Tanous                         {
1046a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
10474a0cb85cSEd Tanous                             return;
10481abe55efSEd Tanous                         }
10494a0cb85cSEd Tanous                         asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
10504a0cb85cSEd Tanous                             nullptr;
10514a0cb85cSEd Tanous                     };
10524a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
10534a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
10544a0cb85cSEd Tanous                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
10554a0cb85cSEd Tanous                             thisData->id,
10564a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
1057179db1d7SKowalski, Kamil                 }
10584a0cb85cSEd Tanous                 else if (thisJson.is_object())
10594a0cb85cSEd Tanous                 {
1060179db1d7SKowalski, Kamil                     // Apply changes
10614a0cb85cSEd Tanous                     if (addressField != nullptr)
10621abe55efSEd Tanous                     {
10634a0cb85cSEd Tanous                         auto callback =
10644a0cb85cSEd Tanous                             [asyncResp, entryIdx,
10654a0cb85cSEd Tanous                              addressField{std::string(*addressField)}](
10664a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
10674a0cb85cSEd Tanous                                 if (ec)
10681abe55efSEd Tanous                                 {
1069a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
10704a0cb85cSEd Tanous                                     return;
10714a0cb85cSEd Tanous                                 }
10724a0cb85cSEd Tanous                                 asyncResp->res
10734a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
10744a0cb85cSEd Tanous                                         entryIdx)]["Address"] = addressField;
10754a0cb85cSEd Tanous                             };
10764a0cb85cSEd Tanous 
10774a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
10784a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
10794a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
10804a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
10814a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
10824a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Address",
1083*abf2add6SEd Tanous                             std::variant<std::string>(*addressField));
1084179db1d7SKowalski, Kamil                     }
1085179db1d7SKowalski, Kamil 
10864a0cb85cSEd Tanous                     if (prefixLength && subnetField != nullptr)
10871abe55efSEd Tanous                     {
10884a0cb85cSEd Tanous                         changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
10894a0cb85cSEd Tanous                                                      thisData->id, *subnetField,
10904a0cb85cSEd Tanous                                                      *prefixLength, asyncResp);
1091179db1d7SKowalski, Kamil                     }
1092179db1d7SKowalski, Kamil 
10934a0cb85cSEd Tanous                     if (!addressOriginInDBusFormat.empty() &&
10944a0cb85cSEd Tanous                         addressOriginField != nullptr)
10951abe55efSEd Tanous                     {
10964a0cb85cSEd Tanous                         changeIPv4Origin(ifaceId, entryIdx, thisData->id,
10974a0cb85cSEd Tanous                                          *addressOriginField,
10984a0cb85cSEd Tanous                                          addressOriginInDBusFormat, asyncResp);
1099179db1d7SKowalski, Kamil                     }
1100179db1d7SKowalski, Kamil 
11014a0cb85cSEd Tanous                     if (gatewayField != nullptr)
11021abe55efSEd Tanous                     {
11034a0cb85cSEd Tanous                         auto callback =
11044a0cb85cSEd Tanous                             [asyncResp, entryIdx,
11054a0cb85cSEd Tanous                              gatewayField{std::string(*gatewayField)}](
11064a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
11074a0cb85cSEd Tanous                                 if (ec)
11081abe55efSEd Tanous                                 {
1109a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
11104a0cb85cSEd Tanous                                     return;
11114a0cb85cSEd Tanous                                 }
11124a0cb85cSEd Tanous                                 asyncResp->res
11134a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
11144a0cb85cSEd Tanous                                         entryIdx)]["Gateway"] =
11154a0cb85cSEd Tanous                                     std::move(gatewayField);
11164a0cb85cSEd Tanous                             };
11174a0cb85cSEd Tanous 
11184a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
11194a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
11204a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
11214a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
11224a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
11234a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Gateway",
1124*abf2add6SEd Tanous                             std::variant<std::string>(*gatewayField));
11254a0cb85cSEd Tanous                     }
11264a0cb85cSEd Tanous                 }
11274a0cb85cSEd Tanous                 thisData++;
11281abe55efSEd Tanous             }
11291abe55efSEd Tanous             else
11301abe55efSEd Tanous             {
11314a0cb85cSEd Tanous                 // Create IPv4 with provided data
11324a0cb85cSEd Tanous                 if (gatewayField == nullptr)
11331abe55efSEd Tanous                 {
1134a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11354a0cb85cSEd Tanous                                               pathString + "/Gateway");
11364a0cb85cSEd Tanous                     continue;
11374a0cb85cSEd Tanous                 }
11384a0cb85cSEd Tanous 
11394a0cb85cSEd Tanous                 if (addressField == nullptr)
11401abe55efSEd Tanous                 {
1141a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11424a0cb85cSEd Tanous                                               pathString + "/Address");
11434a0cb85cSEd Tanous                     continue;
11444a0cb85cSEd Tanous                 }
11454a0cb85cSEd Tanous 
11464a0cb85cSEd Tanous                 if (!prefixLength)
11471abe55efSEd Tanous                 {
1148a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
11494a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
11504a0cb85cSEd Tanous                     continue;
1151588c3f0dSKowalski, Kamil                 }
1152588c3f0dSKowalski, Kamil 
11534a0cb85cSEd Tanous                 createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField,
11544a0cb85cSEd Tanous                            *addressField, asyncResp);
11554a0cb85cSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
11564a0cb85cSEd Tanous             }
11574a0cb85cSEd Tanous             entryIdx++;
11584a0cb85cSEd Tanous         }
11594a0cb85cSEd Tanous     }
11604a0cb85cSEd Tanous 
11610f74e643SEd Tanous     void parseInterfaceData(
11620f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
11630f74e643SEd Tanous         const EthernetInterfaceData &ethData,
11644a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
11654a0cb85cSEd Tanous     {
11664a0cb85cSEd Tanous         json_response["Id"] = iface_id;
11674a0cb85cSEd Tanous         json_response["@odata.id"] =
11684a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
11694a0cb85cSEd Tanous 
11704a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
11714a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
11724a0cb85cSEd Tanous         if (!ethData.hostname.empty())
11734a0cb85cSEd Tanous         {
11744a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
11754a0cb85cSEd Tanous         }
11764a0cb85cSEd Tanous 
11774a0cb85cSEd Tanous         nlohmann::json &vlanObj = json_response["VLAN"];
11784a0cb85cSEd Tanous         if (ethData.vlan_id)
11794a0cb85cSEd Tanous         {
11804a0cb85cSEd Tanous             vlanObj["VLANEnable"] = true;
11814a0cb85cSEd Tanous             vlanObj["VLANId"] = *ethData.vlan_id;
11824a0cb85cSEd Tanous         }
11834a0cb85cSEd Tanous         else
11844a0cb85cSEd Tanous         {
11854a0cb85cSEd Tanous             vlanObj["VLANEnable"] = false;
11864a0cb85cSEd Tanous             vlanObj["VLANId"] = 0;
11874a0cb85cSEd Tanous         }
11884a0cb85cSEd Tanous 
11894a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
11904a0cb85cSEd Tanous         {
11914a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
11924a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
11934a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
11944a0cb85cSEd Tanous             {
11954a0cb85cSEd Tanous                 if (!ipv4_config.address.empty())
11964a0cb85cSEd Tanous                 {
11974a0cb85cSEd Tanous                     ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
11984a0cb85cSEd Tanous                                           {"SubnetMask", ipv4_config.netmask},
11994a0cb85cSEd Tanous                                           {"Address", ipv4_config.address}});
12004a0cb85cSEd Tanous 
12014a0cb85cSEd Tanous                     if (!ipv4_config.gateway.empty())
12024a0cb85cSEd Tanous                     {
12034a0cb85cSEd Tanous                         ipv4_array.back()["Gateway"] = ipv4_config.gateway;
12044a0cb85cSEd Tanous                     }
12054a0cb85cSEd Tanous                 }
12064a0cb85cSEd Tanous             }
12074a0cb85cSEd Tanous         }
1208588c3f0dSKowalski, Kamil     }
1209588c3f0dSKowalski, Kamil 
12109391bb9cSRapkiewicz, Pawel     /**
12119391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
12129391bb9cSRapkiewicz, Pawel      */
121355c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
12141abe55efSEd Tanous                const std::vector<std::string> &params) override
12151abe55efSEd Tanous     {
12164a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12171abe55efSEd Tanous         if (params.size() != 1)
12181abe55efSEd Tanous         {
1219f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
12209391bb9cSRapkiewicz, Pawel             return;
12219391bb9cSRapkiewicz, Pawel         }
12229391bb9cSRapkiewicz, Pawel 
12234a0cb85cSEd Tanous         getEthernetIfaceData(
12244a0cb85cSEd Tanous             params[0],
12254a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
12264a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
12274a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
12284a0cb85cSEd Tanous                 if (!success)
12291abe55efSEd Tanous                 {
12301abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
12311abe55efSEd Tanous                     // object, and other errors
1232f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1233f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
12344a0cb85cSEd Tanous                     return;
12359391bb9cSRapkiewicz, Pawel                 }
12360f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
12370f74e643SEd Tanous                     "#EthernetInterface.v1_2_0.EthernetInterface";
12380f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
12390f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
12400f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
12410f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
12420f74e643SEd Tanous                     "Management Network Interface";
12430f74e643SEd Tanous 
12440f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
12450f74e643SEd Tanous                                    ipv4Data);
12469391bb9cSRapkiewicz, Pawel             });
12479391bb9cSRapkiewicz, Pawel     }
12489391bb9cSRapkiewicz, Pawel 
124955c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
12501abe55efSEd Tanous                  const std::vector<std::string> &params) override
12511abe55efSEd Tanous     {
12524a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12531abe55efSEd Tanous         if (params.size() != 1)
12541abe55efSEd Tanous         {
1255f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1256588c3f0dSKowalski, Kamil             return;
1257588c3f0dSKowalski, Kamil         }
1258588c3f0dSKowalski, Kamil 
12594a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1260588c3f0dSKowalski, Kamil 
12610627a2c7SEd Tanous         std::optional<nlohmann::json> vlan;
1262bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
12630627a2c7SEd Tanous         std::optional<nlohmann::json> ipv4Addresses;
12640627a2c7SEd Tanous         std::optional<nlohmann::json> ipv6Addresses;
12650627a2c7SEd Tanous 
12660627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
12670627a2c7SEd Tanous                                  "IPv4Addresses", ipv4Addresses,
12680627a2c7SEd Tanous                                  "IPv6Addresses", ipv6Addresses))
12691abe55efSEd Tanous         {
1270588c3f0dSKowalski, Kamil             return;
1271588c3f0dSKowalski, Kamil         }
12720627a2c7SEd Tanous         std::optional<uint64_t> vlanId = 0;
12730627a2c7SEd Tanous         std::optional<bool> vlanEnable = false;
12740627a2c7SEd Tanous         if (vlan)
12750627a2c7SEd Tanous         {
12760627a2c7SEd Tanous             if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable,
12770627a2c7SEd Tanous                                      "VLANId", vlanId))
12780627a2c7SEd Tanous             {
12790627a2c7SEd Tanous                 return;
12800627a2c7SEd Tanous             }
12810627a2c7SEd Tanous             // Need both vlanId and vlanEnable to service this request
12820627a2c7SEd Tanous             if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
12830627a2c7SEd Tanous             {
12840627a2c7SEd Tanous                 if (vlanId)
12850627a2c7SEd Tanous                 {
12860627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANEnable");
12870627a2c7SEd Tanous                 }
12880627a2c7SEd Tanous                 else
12890627a2c7SEd Tanous                 {
12900627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANId");
12910627a2c7SEd Tanous                 }
12920627a2c7SEd Tanous 
12930627a2c7SEd Tanous                 return;
12940627a2c7SEd Tanous             }
12950627a2c7SEd Tanous         }
1296588c3f0dSKowalski, Kamil 
12974a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1298588c3f0dSKowalski, Kamil         // preparation
12994a0cb85cSEd Tanous         getEthernetIfaceData(
13004a0cb85cSEd Tanous             iface_id,
13010627a2c7SEd Tanous             [this, asyncResp, iface_id, vlanId, vlanEnable,
13020627a2c7SEd Tanous              hostname = std::move(hostname),
13030627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
13040627a2c7SEd Tanous              ipv6Addresses = std::move(ipv6Addresses)](
13054a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13064a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13071abe55efSEd Tanous                 if (!success)
13081abe55efSEd Tanous                 {
1309588c3f0dSKowalski, Kamil                     // ... otherwise return error
13101abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13111abe55efSEd Tanous                     // object, and other errors
1312f12894f8SJason M. Bills                     messages::resourceNotFound(
1313f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1314588c3f0dSKowalski, Kamil                     return;
1315588c3f0dSKowalski, Kamil                 }
1316588c3f0dSKowalski, Kamil 
13170f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
13180f74e643SEd Tanous                                    ipv4Data);
1319588c3f0dSKowalski, Kamil 
13200627a2c7SEd Tanous                 if (vlanId && vlanEnable)
13211abe55efSEd Tanous                 {
13220627a2c7SEd Tanous                     handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData,
13234a0cb85cSEd Tanous                                     asyncResp);
13241abe55efSEd Tanous                 }
13250627a2c7SEd Tanous 
13260627a2c7SEd Tanous                 if (hostname)
13271abe55efSEd Tanous                 {
13280627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
13291abe55efSEd Tanous                 }
13300627a2c7SEd Tanous 
13310627a2c7SEd Tanous                 if (ipv4Addresses)
13321abe55efSEd Tanous                 {
13330627a2c7SEd Tanous                     handleIPv4Patch(iface_id, *ipv4Addresses, ipv4Data,
1334179db1d7SKowalski, Kamil                                     asyncResp);
13351abe55efSEd Tanous                 }
13360627a2c7SEd Tanous 
13370627a2c7SEd Tanous                 if (ipv6Addresses)
13381abe55efSEd Tanous                 {
1339179db1d7SKowalski, Kamil                     // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1340a08b46ccSJason M. Bills                     messages::propertyNotWritable(asyncResp->res,
13410627a2c7SEd Tanous                                                   "IPv6Addresses");
1342588c3f0dSKowalski, Kamil                 }
1343588c3f0dSKowalski, Kamil             });
1344588c3f0dSKowalski, Kamil     }
13459391bb9cSRapkiewicz, Pawel };
13469391bb9cSRapkiewicz, Pawel 
1347e439f0f8SKowalski, Kamil /**
13484a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
13494a0cb85cSEd Tanous  * Schema
1350e439f0f8SKowalski, Kamil  */
13511abe55efSEd Tanous class VlanNetworkInterface : public Node
13521abe55efSEd Tanous {
1353e439f0f8SKowalski, Kamil   public:
1354e439f0f8SKowalski, Kamil     /*
1355e439f0f8SKowalski, Kamil      * Default Constructor
1356e439f0f8SKowalski, Kamil      */
1357e439f0f8SKowalski, Kamil     template <typename CrowApp>
13581abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
13594a0cb85cSEd Tanous         Node(app,
13600f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
13611abe55efSEd Tanous              std::string(), std::string())
13621abe55efSEd Tanous     {
1363e439f0f8SKowalski, Kamil         entityPrivileges = {
1364e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1365e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1366e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1367e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1368e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1369e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1370e439f0f8SKowalski, Kamil     }
1371e439f0f8SKowalski, Kamil 
1372e439f0f8SKowalski, Kamil   private:
13730f74e643SEd Tanous     void parseInterfaceData(
13740f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
13750f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
13764a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
13771abe55efSEd Tanous     {
1378e439f0f8SKowalski, Kamil         // Fill out obvious data...
13794a0cb85cSEd Tanous         json_response["Id"] = iface_id;
13804a0cb85cSEd Tanous         json_response["@odata.id"] =
13814a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
13824a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1383e439f0f8SKowalski, Kamil 
13844a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
13854a0cb85cSEd Tanous         if (ethData.vlan_id)
13864a0cb85cSEd Tanous         {
13874a0cb85cSEd Tanous             json_response["VLANId"] = *ethData.vlan_id;
13884a0cb85cSEd Tanous         }
1389e439f0f8SKowalski, Kamil     }
1390e439f0f8SKowalski, Kamil 
139155c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
13921abe55efSEd Tanous                      const std::string &iface)
13931abe55efSEd Tanous     {
1394f12894f8SJason M. Bills         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13951abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
13961abe55efSEd Tanous         {
1397f12894f8SJason M. Bills             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1398f12894f8SJason M. Bills                                        iface);
1399927a505aSKowalski, Kamil             return false;
14001abe55efSEd Tanous         }
14011abe55efSEd Tanous         else
14021abe55efSEd Tanous         {
1403927a505aSKowalski, Kamil             return true;
1404927a505aSKowalski, Kamil         }
1405927a505aSKowalski, Kamil     }
1406927a505aSKowalski, Kamil 
1407e439f0f8SKowalski, Kamil     /**
1408e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1409e439f0f8SKowalski, Kamil      */
141055c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
14111abe55efSEd Tanous                const std::vector<std::string> &params) override
14121abe55efSEd Tanous     {
14134a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14144a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1415e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1416e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1417e439f0f8SKowalski, Kamil         // impossible.
14181abe55efSEd Tanous         if (params.size() != 2)
14191abe55efSEd Tanous         {
1420f12894f8SJason M. Bills             messages::internalError(res);
1421e439f0f8SKowalski, Kamil             res.end();
1422e439f0f8SKowalski, Kamil             return;
1423e439f0f8SKowalski, Kamil         }
1424e439f0f8SKowalski, Kamil 
14254a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
14264a0cb85cSEd Tanous         const std::string &iface_id = params[1];
14270f74e643SEd Tanous         res.jsonValue["@odata.type"] =
14280f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
14290f74e643SEd Tanous         res.jsonValue["@odata.context"] =
14300f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
14310f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1432e439f0f8SKowalski, Kamil 
14334a0cb85cSEd Tanous         if (!verifyNames(res, parent_iface_id, iface_id))
14341abe55efSEd Tanous         {
1435a434f2bdSEd Tanous             return;
1436a434f2bdSEd Tanous         }
1437a434f2bdSEd Tanous 
1438e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1439e439f0f8SKowalski, Kamil         // preparation
14404a0cb85cSEd Tanous         getEthernetIfaceData(
14414a0cb85cSEd Tanous             iface_id,
14424a0cb85cSEd Tanous             [this, asyncResp, parent_iface_id, iface_id](
14434a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14444a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14454a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
14461abe55efSEd Tanous                 {
14470f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
14480f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
14490f74e643SEd Tanous                                        ipv4Data);
14501abe55efSEd Tanous                 }
14511abe55efSEd Tanous                 else
14521abe55efSEd Tanous                 {
1453e439f0f8SKowalski, Kamil                     // ... otherwise return error
14541abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14551abe55efSEd Tanous                     // object, and other errors
1456f12894f8SJason M. Bills                     messages::resourceNotFound(
1457f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1458e439f0f8SKowalski, Kamil                 }
1459e439f0f8SKowalski, Kamil             });
1460e439f0f8SKowalski, Kamil     }
1461e439f0f8SKowalski, Kamil 
146255c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
14631abe55efSEd Tanous                  const std::vector<std::string> &params) override
14641abe55efSEd Tanous     {
14654a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14661abe55efSEd Tanous         if (params.size() != 2)
14671abe55efSEd Tanous         {
1468f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1469e439f0f8SKowalski, Kamil             return;
1470e439f0f8SKowalski, Kamil         }
1471e439f0f8SKowalski, Kamil 
1472d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
147355c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1474927a505aSKowalski, Kamil 
14751abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
14761abe55efSEd Tanous         {
1477927a505aSKowalski, Kamil             return;
1478927a505aSKowalski, Kamil         }
1479927a505aSKowalski, Kamil 
14800627a2c7SEd Tanous         bool vlanEnable = false;
14810627a2c7SEd Tanous         uint64_t vlanId = 0;
14820627a2c7SEd Tanous 
14830627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
14840627a2c7SEd Tanous                                  vlanId))
14851abe55efSEd Tanous         {
1486927a505aSKowalski, Kamil             return;
1487927a505aSKowalski, Kamil         }
1488927a505aSKowalski, Kamil 
1489927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1490927a505aSKowalski, Kamil         // preparation
14914a0cb85cSEd Tanous         getEthernetIfaceData(
14921abe55efSEd Tanous             ifaceId,
14930627a2c7SEd Tanous             [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId](
14944a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14954a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14961abe55efSEd Tanous                 if (!success)
14971abe55efSEd Tanous                 {
14981abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14991abe55efSEd Tanous                     // object, and other errors
1500f12894f8SJason M. Bills                     messages::resourceNotFound(
1501f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1502927a505aSKowalski, Kamil 
1503927a505aSKowalski, Kamil                     return;
1504927a505aSKowalski, Kamil                 }
1505927a505aSKowalski, Kamil 
15060f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
15070f74e643SEd Tanous                                    ifaceId, ethData, ipv4Data);
1508927a505aSKowalski, Kamil 
15090627a2c7SEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable,
15100627a2c7SEd Tanous                                                    ethData, asyncResp);
1511927a505aSKowalski, Kamil             });
1512e439f0f8SKowalski, Kamil     }
1513e439f0f8SKowalski, Kamil 
151455c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
15151abe55efSEd Tanous                   const std::vector<std::string> &params) override
15161abe55efSEd Tanous     {
15174a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15181abe55efSEd Tanous         if (params.size() != 2)
15191abe55efSEd Tanous         {
1520f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1521e439f0f8SKowalski, Kamil             return;
1522e439f0f8SKowalski, Kamil         }
1523e439f0f8SKowalski, Kamil 
1524d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
152555c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1526927a505aSKowalski, Kamil 
15274a0cb85cSEd Tanous         if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
15281abe55efSEd Tanous         {
1529927a505aSKowalski, Kamil             return;
1530927a505aSKowalski, Kamil         }
1531927a505aSKowalski, Kamil 
1532927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1533927a505aSKowalski, Kamil         // preparation
1534f12894f8SJason M. Bills         getEthernetIfaceData(
1535f12894f8SJason M. Bills             ifaceId,
1536f12894f8SJason M. Bills             [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
15374a0cb85cSEd Tanous              ifaceId{std::string(ifaceId)}](
1538f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1539f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15404a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
15411abe55efSEd Tanous                 {
15420f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
15430f74e643SEd Tanous                                        ifaceId, ethData, ipv4Data);
1544927a505aSKowalski, Kamil 
1545f12894f8SJason M. Bills                     auto callback =
1546f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
15471abe55efSEd Tanous                             if (ec)
15481abe55efSEd Tanous                             {
1549f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1550927a505aSKowalski, Kamil                             }
15514a0cb85cSEd Tanous                         };
15524a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
15534a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
15544a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
15554a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
15561abe55efSEd Tanous                 }
15571abe55efSEd Tanous                 else
15581abe55efSEd Tanous                 {
1559927a505aSKowalski, Kamil                     // ... otherwise return error
1560f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1561f12894f8SJason M. Bills                     // object, and other errors
1562f12894f8SJason M. Bills                     messages::resourceNotFound(
1563f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1564927a505aSKowalski, Kamil                 }
1565927a505aSKowalski, Kamil             });
1566e439f0f8SKowalski, Kamil     }
1567e439f0f8SKowalski, Kamil };
1568e439f0f8SKowalski, Kamil 
1569e439f0f8SKowalski, Kamil /**
1570e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1571e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1572e439f0f8SKowalski, Kamil  */
15731abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
15741abe55efSEd Tanous {
1575e439f0f8SKowalski, Kamil   public:
1576e439f0f8SKowalski, Kamil     template <typename CrowApp>
15771abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
15784a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
15794a0cb85cSEd Tanous              std::string())
15801abe55efSEd Tanous     {
1581e439f0f8SKowalski, Kamil         entityPrivileges = {
1582e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1583e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1584e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1585e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1586e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1587e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1588e439f0f8SKowalski, Kamil     }
1589e439f0f8SKowalski, Kamil 
1590e439f0f8SKowalski, Kamil   private:
1591e439f0f8SKowalski, Kamil     /**
1592e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1593e439f0f8SKowalski, Kamil      */
159455c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15951abe55efSEd Tanous                const std::vector<std::string> &params) override
15961abe55efSEd Tanous     {
15974a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15981abe55efSEd Tanous         if (params.size() != 1)
15991abe55efSEd Tanous         {
1600e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1601f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1602e439f0f8SKowalski, Kamil             return;
1603e439f0f8SKowalski, Kamil         }
1604e439f0f8SKowalski, Kamil 
16054a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1606e439f0f8SKowalski, Kamil 
16074a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
16081abe55efSEd Tanous         // preparation
1609f12894f8SJason M. Bills         getEthernetIfaceList(
1610f12894f8SJason M. Bills             [this, asyncResp,
1611f12894f8SJason M. Bills              rootInterfaceName{std::string(rootInterfaceName)}](
16121abe55efSEd Tanous                 const bool &success,
16131abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
16144a0cb85cSEd Tanous                 if (!success)
16151abe55efSEd Tanous                 {
1616f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
16174a0cb85cSEd Tanous                     return;
16181abe55efSEd Tanous                 }
16190f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
16200f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
16210f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
16220f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
16230f74e643SEd Tanous                     "/redfish/v1/$metadata"
16240f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
16250f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
16260f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
16270f74e643SEd Tanous                     "VLAN Network Interface Collection";
16284a0cb85cSEd Tanous 
16294a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
16304a0cb85cSEd Tanous 
16314a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
16321abe55efSEd Tanous                 {
16334a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
16344a0cb85cSEd Tanous                     {
16354a0cb85cSEd Tanous                         iface_array.push_back(
16364a0cb85cSEd Tanous                             {{"@odata.id",
16374a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
16384a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1639e439f0f8SKowalski, Kamil                     }
1640e439f0f8SKowalski, Kamil                 }
1641e439f0f8SKowalski, Kamil 
16424a0cb85cSEd Tanous                 if (iface_array.empty())
16431abe55efSEd Tanous                 {
1644f12894f8SJason M. Bills                     messages::resourceNotFound(
1645f12894f8SJason M. Bills                         asyncResp->res, "EthernetInterface", rootInterfaceName);
16464a0cb85cSEd Tanous                     return;
1647e439f0f8SKowalski, Kamil                 }
16484a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
16494a0cb85cSEd Tanous                     iface_array.size();
16504a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
16514a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
16524a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
16534a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1654e439f0f8SKowalski, Kamil             });
1655e439f0f8SKowalski, Kamil     }
1656e439f0f8SKowalski, Kamil 
165755c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
16581abe55efSEd Tanous                 const std::vector<std::string> &params) override
16591abe55efSEd Tanous     {
16604a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16611abe55efSEd Tanous         if (params.size() != 1)
16621abe55efSEd Tanous         {
1663f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1664e439f0f8SKowalski, Kamil             return;
1665e439f0f8SKowalski, Kamil         }
1666e439f0f8SKowalski, Kamil 
16670627a2c7SEd Tanous         uint32_t vlanId = 0;
16680627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANId", vlanId))
16691abe55efSEd Tanous         {
16704a0cb85cSEd Tanous             return;
1671e439f0f8SKowalski, Kamil         }
16724a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
16734a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
16741abe55efSEd Tanous             if (ec)
16751abe55efSEd Tanous             {
16764a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
16774a0cb85cSEd Tanous                 // phosphor-network responses
1678f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
16794a0cb85cSEd Tanous                 return;
16801abe55efSEd Tanous             }
1681f12894f8SJason M. Bills             messages::created(asyncResp->res);
1682e439f0f8SKowalski, Kamil         };
16834a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
16844a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
16854a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
16864a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
16870627a2c7SEd Tanous             rootInterfaceName, vlanId);
16884a0cb85cSEd Tanous     }
16894a0cb85cSEd Tanous };
16909391bb9cSRapkiewicz, Pawel } // namespace redfish
1691