xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 537174c420d5f784f8db67158b1ad8e8ed74ffff)
19391bb9cSRapkiewicz, Pawel /*
29391bb9cSRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation
39391bb9cSRapkiewicz, Pawel //
49391bb9cSRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License");
59391bb9cSRapkiewicz, Pawel // you may not use this file except in compliance with the License.
69391bb9cSRapkiewicz, Pawel // You may obtain a copy of the License at
79391bb9cSRapkiewicz, Pawel //
89391bb9cSRapkiewicz, Pawel //      http://www.apache.org/licenses/LICENSE-2.0
99391bb9cSRapkiewicz, Pawel //
109391bb9cSRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software
119391bb9cSRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS,
129391bb9cSRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139391bb9cSRapkiewicz, Pawel // See the License for the specific language governing permissions and
149391bb9cSRapkiewicz, Pawel // limitations under the License.
159391bb9cSRapkiewicz, Pawel */
169391bb9cSRapkiewicz, Pawel #pragma once
179391bb9cSRapkiewicz, Pawel 
181abe55efSEd Tanous #include <boost/container/flat_map.hpp>
194a0cb85cSEd Tanous #include <boost/container/flat_set.hpp>
20179db1d7SKowalski, Kamil #include <dbus_singleton.hpp>
21588c3f0dSKowalski, Kamil #include <error_messages.hpp>
22179db1d7SKowalski, Kamil #include <node.hpp>
23a24526dcSEd Tanous #include <optional>
24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp>
25abf2add6SEd Tanous #include <variant>
269391bb9cSRapkiewicz, Pawel 
271abe55efSEd Tanous namespace redfish
281abe55efSEd Tanous {
299391bb9cSRapkiewicz, Pawel 
309391bb9cSRapkiewicz, Pawel /**
319391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
329391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
339391bb9cSRapkiewicz, Pawel  */
34aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
35abf2add6SEd Tanous     std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
36aa2e59c1SEd Tanous                               int32_t, uint32_t, int64_t, uint64_t, double>>;
379391bb9cSRapkiewicz, Pawel 
384a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair<
39aa2e59c1SEd Tanous     sdbusplus::message::object_path,
404a0cb85cSEd Tanous     std::vector<std::pair<
41aa2e59c1SEd Tanous         std::string,
42aa2e59c1SEd Tanous         boost::container::flat_map<
43029573d4SEd Tanous             std::string, sdbusplus::message::variant<
44029573d4SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
45029573d4SEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double,
46029573d4SEd Tanous                              std::vector<std::string>>>>>>>;
474a0cb85cSEd Tanous 
484a0cb85cSEd Tanous enum class LinkType
494a0cb85cSEd Tanous {
504a0cb85cSEd Tanous     Local,
514a0cb85cSEd Tanous     Global
524a0cb85cSEd Tanous };
539391bb9cSRapkiewicz, Pawel 
549391bb9cSRapkiewicz, Pawel /**
559391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
569391bb9cSRapkiewicz, Pawel  */
571abe55efSEd Tanous struct IPv4AddressData
581abe55efSEd Tanous {
59179db1d7SKowalski, Kamil     std::string id;
604a0cb85cSEd Tanous     std::string address;
614a0cb85cSEd Tanous     std::string domain;
624a0cb85cSEd Tanous     std::string gateway;
639391bb9cSRapkiewicz, Pawel     std::string netmask;
649391bb9cSRapkiewicz, Pawel     std::string origin;
654a0cb85cSEd Tanous     LinkType linktype;
664a0cb85cSEd Tanous 
671abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
681abe55efSEd Tanous     {
694a0cb85cSEd Tanous         return id < obj.id;
701abe55efSEd Tanous     }
719391bb9cSRapkiewicz, Pawel };
729391bb9cSRapkiewicz, Pawel 
739391bb9cSRapkiewicz, Pawel /**
749391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
759391bb9cSRapkiewicz, Pawel  * available from DBus
769391bb9cSRapkiewicz, Pawel  */
771abe55efSEd Tanous struct EthernetInterfaceData
781abe55efSEd Tanous {
794a0cb85cSEd Tanous     uint32_t speed;
804a0cb85cSEd Tanous     bool auto_neg;
814a0cb85cSEd Tanous     std::string hostname;
824a0cb85cSEd Tanous     std::string default_gateway;
834a0cb85cSEd Tanous     std::string mac_address;
84a24526dcSEd Tanous     std::optional<uint32_t> vlan_id;
85029573d4SEd Tanous     std::vector<std::string> nameservers;
869391bb9cSRapkiewicz, Pawel };
879391bb9cSRapkiewicz, Pawel 
889391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
899391bb9cSRapkiewicz, Pawel // into full dot notation
901abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
911abe55efSEd Tanous {
929391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
939391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
949391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
959391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
969391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
979391bb9cSRapkiewicz, Pawel     return netmask;
989391bb9cSRapkiewicz, Pawel }
999391bb9cSRapkiewicz, Pawel 
1004a0cb85cSEd Tanous inline std::string
1014a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1024a0cb85cSEd Tanous                                         bool isIPv4)
1031abe55efSEd Tanous {
1044a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1051abe55efSEd Tanous     {
1064a0cb85cSEd Tanous         return "Static";
1079391bb9cSRapkiewicz, Pawel     }
1084a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1091abe55efSEd Tanous     {
1104a0cb85cSEd Tanous         if (isIPv4)
1111abe55efSEd Tanous         {
1124a0cb85cSEd Tanous             return "IPv4LinkLocal";
1131abe55efSEd Tanous         }
1141abe55efSEd Tanous         else
1151abe55efSEd Tanous         {
1164a0cb85cSEd Tanous             return "LinkLocal";
1179391bb9cSRapkiewicz, Pawel         }
1189391bb9cSRapkiewicz, Pawel     }
1194a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1201abe55efSEd Tanous     {
1214a0cb85cSEd Tanous         if (isIPv4)
1224a0cb85cSEd Tanous         {
1234a0cb85cSEd Tanous             return "DHCP";
1244a0cb85cSEd Tanous         }
1254a0cb85cSEd Tanous         else
1264a0cb85cSEd Tanous         {
1274a0cb85cSEd Tanous             return "DHCPv6";
1284a0cb85cSEd Tanous         }
1294a0cb85cSEd Tanous     }
1304a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1314a0cb85cSEd Tanous     {
1324a0cb85cSEd Tanous         return "SLAAC";
1334a0cb85cSEd Tanous     }
1344a0cb85cSEd Tanous     return "";
1354a0cb85cSEd Tanous }
1364a0cb85cSEd Tanous 
1374a0cb85cSEd Tanous inline std::string
1384a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1394a0cb85cSEd Tanous {
1404a0cb85cSEd Tanous     if (inputOrigin == "Static")
1414a0cb85cSEd Tanous     {
1424a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1434a0cb85cSEd Tanous     }
1444a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1454a0cb85cSEd Tanous     {
1464a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1474a0cb85cSEd Tanous     }
1484a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1494a0cb85cSEd Tanous     {
1504a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1514a0cb85cSEd Tanous     }
1524a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1534a0cb85cSEd Tanous     {
1544a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1554a0cb85cSEd Tanous     }
1564a0cb85cSEd Tanous     return "";
1574a0cb85cSEd Tanous }
1584a0cb85cSEd Tanous 
1594a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
1604a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1614a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1624a0cb85cSEd Tanous {
1634a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1644a0cb85cSEd Tanous     {
1654a0cb85cSEd Tanous         for (const auto &ifacePair : objpath.second)
1664a0cb85cSEd Tanous         {
167029573d4SEd Tanous             if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
168029573d4SEd Tanous             {
1694a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1704a0cb85cSEd Tanous                 {
1714a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1724a0cb85cSEd Tanous                     {
1734a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1744a0cb85cSEd Tanous                         {
1754a0cb85cSEd Tanous                             const std::string *mac =
176abf2add6SEd Tanous                                 std::get_if<std::string>(&propertyPair.second);
1774a0cb85cSEd Tanous                             if (mac != nullptr)
1784a0cb85cSEd Tanous                             {
1794a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1804a0cb85cSEd Tanous                             }
1814a0cb85cSEd Tanous                         }
1824a0cb85cSEd Tanous                     }
1834a0cb85cSEd Tanous                 }
1844a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1854a0cb85cSEd Tanous                 {
1864a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1874a0cb85cSEd Tanous                     {
1884a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1894a0cb85cSEd Tanous                         {
1901b6b96c5SEd Tanous                             const uint32_t *id =
191abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
1924a0cb85cSEd Tanous                             if (id != nullptr)
1934a0cb85cSEd Tanous                             {
1944a0cb85cSEd Tanous                                 ethData.vlan_id = *id;
1954a0cb85cSEd Tanous                             }
1964a0cb85cSEd Tanous                         }
1974a0cb85cSEd Tanous                     }
1984a0cb85cSEd Tanous                 }
1994a0cb85cSEd Tanous                 else if (ifacePair.first ==
2004a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2014a0cb85cSEd Tanous                 {
2024a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2034a0cb85cSEd Tanous                     {
2044a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2054a0cb85cSEd Tanous                         {
2064a0cb85cSEd Tanous                             const bool *auto_neg =
207abf2add6SEd Tanous                                 std::get_if<bool>(&propertyPair.second);
2084a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2094a0cb85cSEd Tanous                             {
2104a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2114a0cb85cSEd Tanous                             }
2124a0cb85cSEd Tanous                         }
2134a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2144a0cb85cSEd Tanous                         {
2154a0cb85cSEd Tanous                             const uint32_t *speed =
216abf2add6SEd Tanous                                 std::get_if<uint32_t>(&propertyPair.second);
2174a0cb85cSEd Tanous                             if (speed != nullptr)
2184a0cb85cSEd Tanous                             {
2194a0cb85cSEd Tanous                                 ethData.speed = *speed;
2204a0cb85cSEd Tanous                             }
2214a0cb85cSEd Tanous                         }
222029573d4SEd Tanous                         else if (propertyPair.first == "NameServers")
223029573d4SEd Tanous                         {
224029573d4SEd Tanous                             const std::vector<std::string> *nameservers =
225029573d4SEd Tanous                                 sdbusplus::message::variant_ns::get_if<
226029573d4SEd Tanous                                     std::vector<std::string>>(
227029573d4SEd Tanous                                     &propertyPair.second);
228029573d4SEd Tanous                             if (nameservers != nullptr)
229029573d4SEd Tanous                             {
230029573d4SEd Tanous                                 ethData.nameservers = std::move(*nameservers);
2314a0cb85cSEd Tanous                             }
2324a0cb85cSEd Tanous                         }
233029573d4SEd Tanous                     }
234029573d4SEd Tanous                 }
235029573d4SEd Tanous             }
236029573d4SEd Tanous             // System configuration shows up in the global namespace, so no need
237029573d4SEd Tanous             // to check eth number
238029573d4SEd Tanous             if (ifacePair.first ==
2394a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.SystemConfiguration")
2404a0cb85cSEd Tanous             {
2414a0cb85cSEd Tanous                 for (const auto &propertyPair : ifacePair.second)
2424a0cb85cSEd Tanous                 {
2434a0cb85cSEd Tanous                     if (propertyPair.first == "HostName")
2444a0cb85cSEd Tanous                     {
2454a0cb85cSEd Tanous                         const std::string *hostname =
246029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
247029573d4SEd Tanous                                 &propertyPair.second);
2484a0cb85cSEd Tanous                         if (hostname != nullptr)
2494a0cb85cSEd Tanous                         {
2504a0cb85cSEd Tanous                             ethData.hostname = *hostname;
2514a0cb85cSEd Tanous                         }
2524a0cb85cSEd Tanous                     }
2534a0cb85cSEd Tanous                     else if (propertyPair.first == "DefaultGateway")
2544a0cb85cSEd Tanous                     {
2554a0cb85cSEd Tanous                         const std::string *defaultGateway =
256029573d4SEd Tanous                             sdbusplus::message::variant_ns::get_if<std::string>(
257029573d4SEd Tanous                                 &propertyPair.second);
2584a0cb85cSEd Tanous                         if (defaultGateway != nullptr)
2594a0cb85cSEd Tanous                         {
2604a0cb85cSEd Tanous                             ethData.default_gateway = *defaultGateway;
2614a0cb85cSEd Tanous                         }
2624a0cb85cSEd Tanous                     }
2634a0cb85cSEd Tanous                 }
2644a0cb85cSEd Tanous             }
2654a0cb85cSEd Tanous         }
2664a0cb85cSEd Tanous     }
2674a0cb85cSEd Tanous }
2684a0cb85cSEd Tanous 
2694a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2704a0cb85cSEd Tanous inline void
2714a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2724a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2734a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2744a0cb85cSEd Tanous {
2754a0cb85cSEd Tanous     const std::string ipv4PathStart =
2764a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
2774a0cb85cSEd Tanous 
2784a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
2794a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
2804a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
2814a0cb85cSEd Tanous     {
2824a0cb85cSEd Tanous         // Check if proper pattern for object path appears
2834a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
2844a0cb85cSEd Tanous         {
2854a0cb85cSEd Tanous             for (auto &interface : objpath.second)
2864a0cb85cSEd Tanous             {
2874a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
2884a0cb85cSEd Tanous                 {
2894a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
2904a0cb85cSEd Tanous                     // appropriate
2914a0cb85cSEd Tanous                     std::pair<
2924a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
2934a0cb85cSEd Tanous                         bool>
2944a0cb85cSEd Tanous                         it = ipv4_config.insert(
2954a0cb85cSEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
2964a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
2974a0cb85cSEd Tanous                     for (auto &property : interface.second)
2984a0cb85cSEd Tanous                     {
2994a0cb85cSEd Tanous                         if (property.first == "Address")
3004a0cb85cSEd Tanous                         {
3014a0cb85cSEd Tanous                             const std::string *address =
302abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3034a0cb85cSEd Tanous                             if (address != nullptr)
3044a0cb85cSEd Tanous                             {
3054a0cb85cSEd Tanous                                 ipv4_address.address = *address;
3064a0cb85cSEd Tanous                             }
3074a0cb85cSEd Tanous                         }
3084a0cb85cSEd Tanous                         else if (property.first == "Gateway")
3094a0cb85cSEd Tanous                         {
3104a0cb85cSEd Tanous                             const std::string *gateway =
311abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3124a0cb85cSEd Tanous                             if (gateway != nullptr)
3134a0cb85cSEd Tanous                             {
3144a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
3154a0cb85cSEd Tanous                             }
3164a0cb85cSEd Tanous                         }
3174a0cb85cSEd Tanous                         else if (property.first == "Origin")
3184a0cb85cSEd Tanous                         {
3194a0cb85cSEd Tanous                             const std::string *origin =
320abf2add6SEd Tanous                                 std::get_if<std::string>(&property.second);
3214a0cb85cSEd Tanous                             if (origin != nullptr)
3224a0cb85cSEd Tanous                             {
3234a0cb85cSEd Tanous                                 ipv4_address.origin =
3244a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3254a0cb85cSEd Tanous                                                                         true);
3264a0cb85cSEd Tanous                             }
3274a0cb85cSEd Tanous                         }
3284a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3294a0cb85cSEd Tanous                         {
3304a0cb85cSEd Tanous                             const uint8_t *mask =
331abf2add6SEd Tanous                                 std::get_if<uint8_t>(&property.second);
3324a0cb85cSEd Tanous                             if (mask != nullptr)
3334a0cb85cSEd Tanous                             {
3344a0cb85cSEd Tanous                                 // convert it to the string
3354a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3364a0cb85cSEd Tanous                             }
3374a0cb85cSEd Tanous                         }
3384a0cb85cSEd Tanous                         else
3394a0cb85cSEd Tanous                         {
3404a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3414a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3424a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3434a0cb85cSEd Tanous                         }
3444a0cb85cSEd Tanous                     }
3454a0cb85cSEd Tanous                     // Check if given address is local, or global
3464a0cb85cSEd Tanous                     ipv4_address.linktype =
3474a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3484a0cb85cSEd Tanous                             ? LinkType::Global
3494a0cb85cSEd Tanous                             : LinkType::Local;
3504a0cb85cSEd Tanous                 }
3514a0cb85cSEd Tanous             }
3524a0cb85cSEd Tanous         }
3534a0cb85cSEd Tanous     }
3544a0cb85cSEd Tanous }
355588c3f0dSKowalski, Kamil 
356588c3f0dSKowalski, Kamil /**
357588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
358588c3f0dSKowalski, Kamil  *
359588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
360588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
361588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
362588c3f0dSKowalski, Kamil  *
363588c3f0dSKowalski, Kamil  * @return None.
364588c3f0dSKowalski, Kamil  */
365588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3664a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3671abe55efSEd Tanous                   CallbackFunc &&callback)
3681abe55efSEd Tanous {
36955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
370588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
371588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
372588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
373588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
374abf2add6SEd Tanous         std::variant<uint32_t>(inputVlanId));
3754a0cb85cSEd Tanous }
376588c3f0dSKowalski, Kamil 
377588c3f0dSKowalski, Kamil /**
378179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
379179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
380179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
381179db1d7SKowalski, Kamil  *
382179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
383179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
384179db1d7SKowalski, Kamil  *
385179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
386179db1d7SKowalski, Kamil  */
3874a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
3881abe55efSEd Tanous                                        uint8_t *bits = nullptr)
3891abe55efSEd Tanous {
390179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
391179db1d7SKowalski, Kamil 
392179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
393179db1d7SKowalski, Kamil 
3944a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
3951abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
3961abe55efSEd Tanous     {
397179db1d7SKowalski, Kamil         return false;
398179db1d7SKowalski, Kamil     }
399179db1d7SKowalski, Kamil 
4001abe55efSEd Tanous     if (bits != nullptr)
4011abe55efSEd Tanous     {
402179db1d7SKowalski, Kamil         *bits = 0;
403179db1d7SKowalski, Kamil     }
404179db1d7SKowalski, Kamil 
405179db1d7SKowalski, Kamil     char *endPtr;
406179db1d7SKowalski, Kamil     long previousValue = 255;
407179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
4081abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
4091abe55efSEd Tanous     {
4101abe55efSEd Tanous         if (byte.empty())
4111abe55efSEd Tanous         {
4121db9ca37SKowalski, Kamil             return false;
4131db9ca37SKowalski, Kamil         }
4141db9ca37SKowalski, Kamil 
415179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4161db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
417179db1d7SKowalski, Kamil 
4184a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4194a0cb85cSEd Tanous         // is not 100% number
4201abe55efSEd Tanous         if (*endPtr != '\0')
4211abe55efSEd Tanous         {
422179db1d7SKowalski, Kamil             return false;
423179db1d7SKowalski, Kamil         }
424179db1d7SKowalski, Kamil 
425179db1d7SKowalski, Kamil         // Value should be contained in byte
4261abe55efSEd Tanous         if (value < 0 || value > 255)
4271abe55efSEd Tanous         {
428179db1d7SKowalski, Kamil             return false;
429179db1d7SKowalski, Kamil         }
430179db1d7SKowalski, Kamil 
4311abe55efSEd Tanous         if (bits != nullptr)
4321abe55efSEd Tanous         {
433179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4341abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4351abe55efSEd Tanous             {
436179db1d7SKowalski, Kamil                 return false;
437179db1d7SKowalski, Kamil             }
438179db1d7SKowalski, Kamil 
439179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
440179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
441179db1d7SKowalski, Kamil 
442179db1d7SKowalski, Kamil             // Count bits
4431abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4441abe55efSEd Tanous             {
4451abe55efSEd Tanous                 if (value & (1 << bitIdx))
4461abe55efSEd Tanous                 {
4471abe55efSEd Tanous                     if (firstZeroInByteHit)
4481abe55efSEd Tanous                     {
449179db1d7SKowalski, Kamil                         // Continuity not preserved
450179db1d7SKowalski, Kamil                         return false;
4511abe55efSEd Tanous                     }
4521abe55efSEd Tanous                     else
4531abe55efSEd Tanous                     {
454179db1d7SKowalski, Kamil                         (*bits)++;
455179db1d7SKowalski, Kamil                     }
4561abe55efSEd Tanous                 }
4571abe55efSEd Tanous                 else
4581abe55efSEd Tanous                 {
459179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
460179db1d7SKowalski, Kamil                 }
461179db1d7SKowalski, Kamil             }
462179db1d7SKowalski, Kamil         }
463179db1d7SKowalski, Kamil 
464179db1d7SKowalski, Kamil         previousValue = value;
465179db1d7SKowalski, Kamil     }
466179db1d7SKowalski, Kamil 
467179db1d7SKowalski, Kamil     return true;
468179db1d7SKowalski, Kamil }
469179db1d7SKowalski, Kamil 
470179db1d7SKowalski, Kamil /**
471179db1d7SKowalski, Kamil  * @brief Changes IPv4 address type property (Address, Gateway)
472179db1d7SKowalski, Kamil  *
473179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be modified
4744a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
475179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of modified IP
476179db1d7SKowalski, Kamil  * @param[in] name        Name of field in JSON representation
477179db1d7SKowalski, Kamil  * @param[in] newValue    New value that should be written
478179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
479179db1d7SKowalski, Kamil  *
480179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
481179db1d7SKowalski, Kamil  * otherwise
482179db1d7SKowalski, Kamil  */
4834a0cb85cSEd Tanous inline void changeIPv4AddressProperty(
4844a0cb85cSEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
4854a0cb85cSEd Tanous     const std::string &name, const std::string &newValue,
4864a0cb85cSEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
4871abe55efSEd Tanous {
4884a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
4894a0cb85cSEd Tanous                      newValue{std::move(newValue)}](
4901abe55efSEd Tanous                         const boost::system::error_code ec) {
4911abe55efSEd Tanous         if (ec)
4921abe55efSEd Tanous         {
493a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
4941abe55efSEd Tanous         }
4951abe55efSEd Tanous         else
4961abe55efSEd Tanous         {
4974a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
498179db1d7SKowalski, Kamil         }
499179db1d7SKowalski, Kamil     };
500179db1d7SKowalski, Kamil 
50155c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
502179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
503179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
504179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
505179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", name,
506abf2add6SEd Tanous         std::variant<std::string>(newValue));
5074a0cb85cSEd Tanous }
508179db1d7SKowalski, Kamil 
509179db1d7SKowalski, Kamil /**
510179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
511179db1d7SKowalski, Kamil  *
512179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
5134a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5141abe55efSEd Tanous  * modified
515179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
516179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
517179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
518179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
519179db1d7SKowalski, Kamil  *
520179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
521179db1d7SKowalski, Kamil  * otherwise
522179db1d7SKowalski, Kamil  */
5234a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5241abe55efSEd Tanous                              const std::string &ipHash,
5251abe55efSEd Tanous                              const std::string &newValue,
526179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5274a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5281abe55efSEd Tanous {
5294a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5301abe55efSEd Tanous                         const boost::system::error_code ec) {
5311abe55efSEd Tanous         if (ec)
5321abe55efSEd Tanous         {
533a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5341abe55efSEd Tanous         }
5351abe55efSEd Tanous         else
5361abe55efSEd Tanous         {
5374a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
538179db1d7SKowalski, Kamil                 newValue;
539179db1d7SKowalski, Kamil         }
540179db1d7SKowalski, Kamil     };
541179db1d7SKowalski, Kamil 
54255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
543179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
544179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
545179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
546179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
547abf2add6SEd Tanous         std::variant<std::string>(newValueDbus));
5484a0cb85cSEd Tanous }
549179db1d7SKowalski, Kamil 
550179db1d7SKowalski, Kamil /**
551179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
552179db1d7SKowalski, Kamil  *
553179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5544a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5551abe55efSEd Tanous  * modified
556179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
557179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
558179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
559179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
560179db1d7SKowalski, Kamil  *
561179db1d7SKowalski, Kamil  * @return None
562179db1d7SKowalski, Kamil  */
5634a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5644a0cb85cSEd Tanous                                          const std::string &ipHash,
5654a0cb85cSEd Tanous                                          const std::string &newValueStr,
5664a0cb85cSEd Tanous                                          uint8_t &newValue,
5674a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5681abe55efSEd Tanous {
5694a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5701abe55efSEd Tanous                         const boost::system::error_code ec) {
5711abe55efSEd Tanous         if (ec)
5721abe55efSEd Tanous         {
573a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
5741abe55efSEd Tanous         }
5751abe55efSEd Tanous         else
5761abe55efSEd Tanous         {
57755c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
578179db1d7SKowalski, Kamil                 newValueStr;
579179db1d7SKowalski, Kamil         }
580179db1d7SKowalski, Kamil     };
581179db1d7SKowalski, Kamil 
58255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
583179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
584179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
585179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
586179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
587abf2add6SEd Tanous         std::variant<uint8_t>(newValue));
5884a0cb85cSEd Tanous }
589588c3f0dSKowalski, Kamil 
590588c3f0dSKowalski, Kamil /**
591179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
592179db1d7SKowalski, Kamil  *
593179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
5944a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
595179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
596179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
597179db1d7SKowalski, Kamil  *
598179db1d7SKowalski, Kamil  * @return None
599179db1d7SKowalski, Kamil  */
6004a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
601179db1d7SKowalski, Kamil                        unsigned int ipIdx,
6024a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6031abe55efSEd Tanous {
60455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6054a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6061abe55efSEd Tanous             if (ec)
6071abe55efSEd Tanous             {
608a08b46ccSJason M. Bills                 messages::internalError(asyncResp->res);
6091abe55efSEd Tanous             }
6101abe55efSEd Tanous             else
6111abe55efSEd Tanous             {
61255c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
613179db1d7SKowalski, Kamil             }
614179db1d7SKowalski, Kamil         },
615179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
616179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
617179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
618179db1d7SKowalski, Kamil }
619179db1d7SKowalski, Kamil 
620179db1d7SKowalski, Kamil /**
621179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
622179db1d7SKowalski, Kamil  *
623179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6244a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
625179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
626179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
627179db1d7SKowalski, Kamil  *
628179db1d7SKowalski, Kamil  * @return None
629179db1d7SKowalski, Kamil  */
6304a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
631179db1d7SKowalski, Kamil                        uint8_t subnetMask, const std::string &gateway,
632179db1d7SKowalski, Kamil                        const std::string &address,
6334a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6341abe55efSEd Tanous {
63543b761d0SEd Tanous     auto createIpHandler = [asyncResp](const boost::system::error_code ec) {
6361abe55efSEd Tanous         if (ec)
6371abe55efSEd Tanous         {
638a08b46ccSJason M. Bills             messages::internalError(asyncResp->res);
639179db1d7SKowalski, Kamil         }
640179db1d7SKowalski, Kamil     };
641179db1d7SKowalski, Kamil 
64255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
643179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
644179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
645179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
646179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
647179db1d7SKowalski, Kamil         gateway);
648179db1d7SKowalski, Kamil }
649179db1d7SKowalski, Kamil 
650179db1d7SKowalski, Kamil /**
651179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
652179db1d7SKowalski, Kamil  * Object
653179db1d7SKowalski, Kamil  * from EntityManager Network Manager
6544a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
655179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
656179db1d7SKowalski, Kamil  * into JSON
657179db1d7SKowalski, Kamil  */
658179db1d7SKowalski, Kamil template <typename CallbackFunc>
6594a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
6601abe55efSEd Tanous                           CallbackFunc &&callback)
6611abe55efSEd Tanous {
66255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6634a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
6641abe55efSEd Tanous             const boost::system::error_code error_code,
6654a0cb85cSEd Tanous             const GetManagedObjects &resp) {
66655c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
6674a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
668179db1d7SKowalski, Kamil 
6691abe55efSEd Tanous             if (error_code)
6701abe55efSEd Tanous             {
67155c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
672179db1d7SKowalski, Kamil                 return;
673179db1d7SKowalski, Kamil             }
674179db1d7SKowalski, Kamil 
6754a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
6764a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
677179db1d7SKowalski, Kamil 
678179db1d7SKowalski, Kamil             // Fix global GW
6791abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
6801abe55efSEd Tanous             {
6814a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
6824a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
6831abe55efSEd Tanous                 {
6844a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
685179db1d7SKowalski, Kamil                 }
686179db1d7SKowalski, Kamil             }
687179db1d7SKowalski, Kamil 
6884a0cb85cSEd Tanous             // Finally make a callback with usefull data
68955c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
690179db1d7SKowalski, Kamil         },
691179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
692179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
693179db1d7SKowalski, Kamil };
694179db1d7SKowalski, Kamil 
695179db1d7SKowalski, Kamil /**
6969391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
6979391bb9cSRapkiewicz, Pawel  * Manager
6981abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
6991abe55efSEd Tanous  * into JSON.
7009391bb9cSRapkiewicz, Pawel  */
7019391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7021abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7031abe55efSEd Tanous {
70455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7054a0cb85cSEd Tanous         [callback{std::move(callback)}](
7069391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
7074a0cb85cSEd Tanous             GetManagedObjects &resp) {
7081abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7091abe55efSEd Tanous             // ethernet interfaces
7104a0cb85cSEd Tanous             std::vector<std::string> iface_list;
7114a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7121abe55efSEd Tanous             if (error_code)
7131abe55efSEd Tanous             {
7144a0cb85cSEd Tanous                 callback(false, iface_list);
7159391bb9cSRapkiewicz, Pawel                 return;
7169391bb9cSRapkiewicz, Pawel             }
7179391bb9cSRapkiewicz, Pawel 
7189391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7194a0cb85cSEd Tanous             for (const auto &objpath : resp)
7201abe55efSEd Tanous             {
7219391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7224a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7231abe55efSEd Tanous                 {
7241abe55efSEd Tanous                     // If interface is
7254a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
7264a0cb85cSEd Tanous                     // what we're looking for.
7279391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7281abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7291abe55efSEd Tanous                     {
7304a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
7314a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
7324a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
7334a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7341abe55efSEd Tanous                         {
7359391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
7364a0cb85cSEd Tanous                             iface_list.emplace_back(
7374a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
7389391bb9cSRapkiewicz, Pawel                         }
7399391bb9cSRapkiewicz, Pawel                     }
7409391bb9cSRapkiewicz, Pawel                 }
7419391bb9cSRapkiewicz, Pawel             }
742a434f2bdSEd Tanous             // Finally make a callback with useful data
7434a0cb85cSEd Tanous             callback(true, iface_list);
7449391bb9cSRapkiewicz, Pawel         },
745aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
746aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7479391bb9cSRapkiewicz, Pawel };
7489391bb9cSRapkiewicz, Pawel 
7499391bb9cSRapkiewicz, Pawel /**
7509391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
7519391bb9cSRapkiewicz, Pawel  */
7521abe55efSEd Tanous class EthernetCollection : public Node
7531abe55efSEd Tanous {
7549391bb9cSRapkiewicz, Pawel   public:
7554a0cb85cSEd Tanous     template <typename CrowApp>
7561abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
7574a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
7581abe55efSEd Tanous     {
759588c3f0dSKowalski, Kamil         entityPrivileges = {
760588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
761e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
762e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
763e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
764e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
765e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
7669391bb9cSRapkiewicz, Pawel     }
7679391bb9cSRapkiewicz, Pawel 
7689391bb9cSRapkiewicz, Pawel   private:
7699391bb9cSRapkiewicz, Pawel     /**
7709391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
7719391bb9cSRapkiewicz, Pawel      */
77255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
7731abe55efSEd Tanous                const std::vector<std::string> &params) override
7741abe55efSEd Tanous     {
7750f74e643SEd Tanous         res.jsonValue["@odata.type"] =
7760f74e643SEd Tanous             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
7770f74e643SEd Tanous         res.jsonValue["@odata.context"] =
7780f74e643SEd Tanous             "/redfish/v1/"
7790f74e643SEd Tanous             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
7800f74e643SEd Tanous         res.jsonValue["@odata.id"] =
7810f74e643SEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces";
7820f74e643SEd Tanous         res.jsonValue["Name"] = "Ethernet Network Interface Collection";
7830f74e643SEd Tanous         res.jsonValue["Description"] =
7840f74e643SEd Tanous             "Collection of EthernetInterfaces for this Manager";
7850f74e643SEd Tanous 
7864a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
7871abe55efSEd Tanous         // preparation
788f12894f8SJason M. Bills         getEthernetIfaceList(
789f12894f8SJason M. Bills             [&res](const bool &success,
7901abe55efSEd Tanous                    const std::vector<std::string> &iface_list) {
7914a0cb85cSEd Tanous                 if (!success)
7921abe55efSEd Tanous                 {
793f12894f8SJason M. Bills                     messages::internalError(res);
7944a0cb85cSEd Tanous                     res.end();
7954a0cb85cSEd Tanous                     return;
7964a0cb85cSEd Tanous                 }
7974a0cb85cSEd Tanous 
7984a0cb85cSEd Tanous                 nlohmann::json &iface_array = res.jsonValue["Members"];
7994a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
8004a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
8011abe55efSEd Tanous                 {
8024a0cb85cSEd Tanous                     iface_array.push_back(
8034a0cb85cSEd Tanous                         {{"@odata.id",
8044a0cb85cSEd Tanous                           "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
8054a0cb85cSEd Tanous                               iface_item}});
8069391bb9cSRapkiewicz, Pawel                 }
8074a0cb85cSEd Tanous 
8084a0cb85cSEd Tanous                 res.jsonValue["Members@odata.count"] = iface_array.size();
8094a0cb85cSEd Tanous                 res.jsonValue["@odata.id"] =
8104a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
8119391bb9cSRapkiewicz, Pawel                 res.end();
8129391bb9cSRapkiewicz, Pawel             });
8139391bb9cSRapkiewicz, Pawel     }
8149391bb9cSRapkiewicz, Pawel };
8159391bb9cSRapkiewicz, Pawel 
8169391bb9cSRapkiewicz, Pawel /**
8179391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8189391bb9cSRapkiewicz, Pawel  */
8191abe55efSEd Tanous class EthernetInterface : public Node
8201abe55efSEd Tanous {
8219391bb9cSRapkiewicz, Pawel   public:
8229391bb9cSRapkiewicz, Pawel     /*
8239391bb9cSRapkiewicz, Pawel      * Default Constructor
8249391bb9cSRapkiewicz, Pawel      */
8254a0cb85cSEd Tanous     template <typename CrowApp>
8261abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
8274a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8281abe55efSEd Tanous              std::string())
8291abe55efSEd Tanous     {
830588c3f0dSKowalski, Kamil         entityPrivileges = {
831588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
832e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
833e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
834e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
835e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
836e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8379391bb9cSRapkiewicz, Pawel     }
8389391bb9cSRapkiewicz, Pawel 
839e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
8400627a2c7SEd Tanous     static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable,
8410627a2c7SEd Tanous                                 uint64_t vlanId,
8424a0cb85cSEd Tanous                                 const EthernetInterfaceData &ethData,
8434a0cb85cSEd Tanous                                 const std::shared_ptr<AsyncResp> asyncResp)
8441abe55efSEd Tanous     {
8454a0cb85cSEd Tanous         if (!ethData.vlan_id)
8461abe55efSEd Tanous         {
847e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
848e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
849a08b46ccSJason M. Bills             messages::propertyNotWritable(asyncResp->res, "VLANEnable");
850588c3f0dSKowalski, Kamil 
851588c3f0dSKowalski, Kamil             return;
852588c3f0dSKowalski, Kamil         }
853588c3f0dSKowalski, Kamil 
854588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
8550627a2c7SEd Tanous         if (vlanEnable == true)
8561abe55efSEd Tanous         {
857588c3f0dSKowalski, Kamil             // Change VLAN Id
8580627a2c7SEd Tanous             asyncResp->res.jsonValue["VLANId"] = vlanId;
8594a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
8601abe55efSEd Tanous                 if (ec)
8611abe55efSEd Tanous                 {
862f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8631abe55efSEd Tanous                 }
8641abe55efSEd Tanous                 else
8651abe55efSEd Tanous                 {
8664a0cb85cSEd Tanous                     asyncResp->res.jsonValue["VLANEnable"] = true;
867e439f0f8SKowalski, Kamil                 }
8684a0cb85cSEd Tanous             };
8694a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
8704a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
8714a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
8724a0cb85cSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
8734a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.VLAN", "Id",
874abf2add6SEd Tanous                 std::variant<uint32_t>(vlanId));
8751abe55efSEd Tanous         }
8764a0cb85cSEd Tanous         else
8771abe55efSEd Tanous         {
8784a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
8791abe55efSEd Tanous                 if (ec)
8801abe55efSEd Tanous                 {
881f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
8824a0cb85cSEd Tanous                     return;
8831abe55efSEd Tanous                 }
8844a0cb85cSEd Tanous                 asyncResp->res.jsonValue["VLANEnable"] = false;
8854a0cb85cSEd Tanous             };
8864a0cb85cSEd Tanous 
8874a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
8884a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
8894a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
8904a0cb85cSEd Tanous                 "xyz.openbmc_project.Object.Delete", "Delete");
891588c3f0dSKowalski, Kamil         }
892588c3f0dSKowalski, Kamil     }
893588c3f0dSKowalski, Kamil 
894e439f0f8SKowalski, Kamil   private:
895bc0bd6e0SEd Tanous     void handleHostnamePatch(const std::string &hostname,
8964a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
8971abe55efSEd Tanous     {
898bc0bd6e0SEd Tanous         asyncResp->res.jsonValue["HostName"] = hostname;
899bc0bd6e0SEd Tanous         crow::connections::systemBus->async_method_call(
900bc0bd6e0SEd Tanous             [asyncResp](const boost::system::error_code ec) {
9014a0cb85cSEd Tanous                 if (ec)
9024a0cb85cSEd Tanous                 {
903a08b46ccSJason M. Bills                     messages::internalError(asyncResp->res);
9041abe55efSEd Tanous                 }
905bc0bd6e0SEd Tanous             },
906bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network",
907bc0bd6e0SEd Tanous             "/xyz/openbmc_project/network/config",
908bc0bd6e0SEd Tanous             "org.freedesktop.DBus.Properties", "Set",
909bc0bd6e0SEd Tanous             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
910abf2add6SEd Tanous             std::variant<std::string>(hostname));
911588c3f0dSKowalski, Kamil     }
912588c3f0dSKowalski, Kamil 
9134a0cb85cSEd Tanous     void handleIPv4Patch(
914*537174c4SEd Tanous         const std::string &ifaceId, std::vector<nlohmann::json> &input,
9154a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
9164a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
9171abe55efSEd Tanous     {
9184a0cb85cSEd Tanous         int entryIdx = 0;
9194a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
9204a0cb85cSEd Tanous             ipv4Data.begin();
921*537174c4SEd Tanous         for (nlohmann::json &thisJson : input)
9221abe55efSEd Tanous         {
9234a0cb85cSEd Tanous             std::string pathString =
924a08b46ccSJason M. Bills                 "IPv4Addresses/" + std::to_string(entryIdx);
925179db1d7SKowalski, Kamil 
926*537174c4SEd Tanous             std::optional<std::string> address;
927*537174c4SEd Tanous             std::optional<std::string> addressOrigin;
928*537174c4SEd Tanous             std::optional<std::string> subnetMask;
929*537174c4SEd Tanous             std::optional<std::string> gateway;
930*537174c4SEd Tanous 
931*537174c4SEd Tanous             if (!json_util::readJson(thisJson, asyncResp->res, "Address",
932*537174c4SEd Tanous                                      address, "AddressOrigin", addressOrigin,
933*537174c4SEd Tanous                                      "SubnetMask", subnetMask, "Gateway",
934*537174c4SEd Tanous                                      gateway))
935*537174c4SEd Tanous             {
936*537174c4SEd Tanous                 return;
937179db1d7SKowalski, Kamil             }
938179db1d7SKowalski, Kamil 
939*537174c4SEd Tanous             if (address)
9401abe55efSEd Tanous             {
941*537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*address))
9421abe55efSEd Tanous                 {
943*537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *address,
9444a0cb85cSEd Tanous                                                        pathString + "/Address");
945*537174c4SEd Tanous                     return;
9464a0cb85cSEd Tanous                 }
9474a0cb85cSEd Tanous             }
9484a0cb85cSEd Tanous 
949*537174c4SEd Tanous             uint8_t prefixLength = 0;
950*537174c4SEd Tanous             if (subnetMask)
9514a0cb85cSEd Tanous             {
952*537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength))
9534a0cb85cSEd Tanous                 {
954f12894f8SJason M. Bills                     messages::propertyValueFormatError(
955*537174c4SEd Tanous                         asyncResp->res, *subnetMask,
9564a0cb85cSEd Tanous                         pathString + "/SubnetMask");
957*537174c4SEd Tanous                     return;
9584a0cb85cSEd Tanous                 }
9594a0cb85cSEd Tanous             }
9604a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
961*537174c4SEd Tanous             if (addressOrigin)
9624a0cb85cSEd Tanous             {
9634a0cb85cSEd Tanous                 // Get Address origin in proper format
9644a0cb85cSEd Tanous                 addressOriginInDBusFormat =
965*537174c4SEd Tanous                     translateAddressOriginRedfishToDbus(*addressOrigin);
9664a0cb85cSEd Tanous                 if (addressOriginInDBusFormat.empty())
9674a0cb85cSEd Tanous                 {
9684a0cb85cSEd Tanous                     messages::propertyValueNotInList(
969*537174c4SEd Tanous                         asyncResp->res, *addressOrigin,
970a08b46ccSJason M. Bills                         pathString + "/AddressOrigin");
971*537174c4SEd Tanous                     return;
9724a0cb85cSEd Tanous                 }
9734a0cb85cSEd Tanous             }
9744a0cb85cSEd Tanous 
975*537174c4SEd Tanous             if (gateway)
9764a0cb85cSEd Tanous             {
977*537174c4SEd Tanous                 if (!ipv4VerifyIpAndGetBitcount(*gateway))
9784a0cb85cSEd Tanous                 {
979*537174c4SEd Tanous                     messages::propertyValueFormatError(asyncResp->res, *gateway,
980*537174c4SEd Tanous                                                        pathString + "/Gateway");
981*537174c4SEd Tanous                     return;
9824a0cb85cSEd Tanous                 }
9834a0cb85cSEd Tanous             }
9844a0cb85cSEd Tanous 
9854a0cb85cSEd Tanous             // if a vlan already exists, modify the existing
9864a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
9874a0cb85cSEd Tanous             {
9881abe55efSEd Tanous                 // Existing object that should be modified/deleted/remain
9891abe55efSEd Tanous                 // unchanged
9904a0cb85cSEd Tanous                 if (thisJson.is_null())
9911abe55efSEd Tanous                 {
9924a0cb85cSEd Tanous                     auto callback = [entryIdx{std::to_string(entryIdx)},
9934a0cb85cSEd Tanous                                      asyncResp](
9944a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
9954a0cb85cSEd Tanous                         if (ec)
9964a0cb85cSEd Tanous                         {
997a08b46ccSJason M. Bills                             messages::internalError(asyncResp->res);
9984a0cb85cSEd Tanous                             return;
9991abe55efSEd Tanous                         }
10004a0cb85cSEd Tanous                         asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
10014a0cb85cSEd Tanous                             nullptr;
10024a0cb85cSEd Tanous                     };
10034a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
10044a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
10054a0cb85cSEd Tanous                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
10064a0cb85cSEd Tanous                             thisData->id,
10074a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
1008179db1d7SKowalski, Kamil                 }
10094a0cb85cSEd Tanous                 else if (thisJson.is_object())
10104a0cb85cSEd Tanous                 {
1011179db1d7SKowalski, Kamil                     // Apply changes
1012*537174c4SEd Tanous                     if (address)
10131abe55efSEd Tanous                     {
10144a0cb85cSEd Tanous                         auto callback =
1015*537174c4SEd Tanous                             [asyncResp, entryIdx, address = *address](
10164a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
10174a0cb85cSEd Tanous                                 if (ec)
10181abe55efSEd Tanous                                 {
1019a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
10204a0cb85cSEd Tanous                                     return;
10214a0cb85cSEd Tanous                                 }
10224a0cb85cSEd Tanous                                 asyncResp->res
10234a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
1024*537174c4SEd Tanous                                         entryIdx)]["Address"] = address;
10254a0cb85cSEd Tanous                             };
10264a0cb85cSEd Tanous 
10274a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
10284a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
10294a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
10304a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
10314a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
10324a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Address",
1033*537174c4SEd Tanous                             std::variant<std::string>(*address));
1034179db1d7SKowalski, Kamil                     }
1035179db1d7SKowalski, Kamil 
1036*537174c4SEd Tanous                     if (subnetMask)
10371abe55efSEd Tanous                     {
10384a0cb85cSEd Tanous                         changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
1039*537174c4SEd Tanous                                                      thisData->id, *subnetMask,
1040*537174c4SEd Tanous                                                      prefixLength, asyncResp);
1041179db1d7SKowalski, Kamil                     }
1042179db1d7SKowalski, Kamil 
1043*537174c4SEd Tanous                     if (addressOrigin)
10441abe55efSEd Tanous                     {
10454a0cb85cSEd Tanous                         changeIPv4Origin(ifaceId, entryIdx, thisData->id,
1046*537174c4SEd Tanous                                          *addressOrigin,
10474a0cb85cSEd Tanous                                          addressOriginInDBusFormat, asyncResp);
1048179db1d7SKowalski, Kamil                     }
1049179db1d7SKowalski, Kamil 
1050*537174c4SEd Tanous                     if (gateway)
10511abe55efSEd Tanous                     {
10524a0cb85cSEd Tanous                         auto callback =
10534a0cb85cSEd Tanous                             [asyncResp, entryIdx,
1054*537174c4SEd Tanous                              gateway{std::string(*gateway)}](
10554a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
10564a0cb85cSEd Tanous                                 if (ec)
10571abe55efSEd Tanous                                 {
1058a08b46ccSJason M. Bills                                     messages::internalError(asyncResp->res);
10594a0cb85cSEd Tanous                                     return;
10604a0cb85cSEd Tanous                                 }
10614a0cb85cSEd Tanous                                 asyncResp->res
10624a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
10634a0cb85cSEd Tanous                                         entryIdx)]["Gateway"] =
1064*537174c4SEd Tanous                                     std::move(gateway);
10654a0cb85cSEd Tanous                             };
10664a0cb85cSEd Tanous 
10674a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
10684a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
10694a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
10704a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
10714a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
10724a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Gateway",
1073*537174c4SEd Tanous                             std::variant<std::string>(*gateway));
10744a0cb85cSEd Tanous                     }
10754a0cb85cSEd Tanous                 }
10764a0cb85cSEd Tanous                 thisData++;
10771abe55efSEd Tanous             }
10781abe55efSEd Tanous             else
10791abe55efSEd Tanous             {
10804a0cb85cSEd Tanous                 // Create IPv4 with provided data
1081*537174c4SEd Tanous                 if (!gateway)
10821abe55efSEd Tanous                 {
1083a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
10844a0cb85cSEd Tanous                                               pathString + "/Gateway");
10854a0cb85cSEd Tanous                     continue;
10864a0cb85cSEd Tanous                 }
10874a0cb85cSEd Tanous 
1088*537174c4SEd Tanous                 if (!address)
10891abe55efSEd Tanous                 {
1090a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
10914a0cb85cSEd Tanous                                               pathString + "/Address");
10924a0cb85cSEd Tanous                     continue;
10934a0cb85cSEd Tanous                 }
10944a0cb85cSEd Tanous 
1095*537174c4SEd Tanous                 if (!subnetMask)
10961abe55efSEd Tanous                 {
1097a08b46ccSJason M. Bills                     messages::propertyMissing(asyncResp->res,
10984a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
10994a0cb85cSEd Tanous                     continue;
1100588c3f0dSKowalski, Kamil                 }
1101588c3f0dSKowalski, Kamil 
1102*537174c4SEd Tanous                 createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address,
1103*537174c4SEd Tanous                            asyncResp);
11044a0cb85cSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
11054a0cb85cSEd Tanous             }
11064a0cb85cSEd Tanous             entryIdx++;
11074a0cb85cSEd Tanous         }
11084a0cb85cSEd Tanous     }
11094a0cb85cSEd Tanous 
11100f74e643SEd Tanous     void parseInterfaceData(
11110f74e643SEd Tanous         nlohmann::json &json_response, const std::string &iface_id,
11120f74e643SEd Tanous         const EthernetInterfaceData &ethData,
11134a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
11144a0cb85cSEd Tanous     {
11154a0cb85cSEd Tanous         json_response["Id"] = iface_id;
11164a0cb85cSEd Tanous         json_response["@odata.id"] =
11174a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
1118029573d4SEd Tanous         json_response["InterfaceEnabled"] = true;
1119029573d4SEd Tanous         if (ethData.speed == 0)
1120029573d4SEd Tanous         {
1121029573d4SEd Tanous             json_response["LinkStatus"] = "NoLink";
1122029573d4SEd Tanous             json_response["Status"] = {
1123029573d4SEd Tanous                 {"Health", "OK"},
1124029573d4SEd Tanous                 {"State", "Disabled"},
1125029573d4SEd Tanous             };
1126029573d4SEd Tanous         }
1127029573d4SEd Tanous         else
1128029573d4SEd Tanous         {
1129029573d4SEd Tanous             json_response["LinkStatus"] = "LinkUp";
1130029573d4SEd Tanous             json_response["Status"] = {
1131029573d4SEd Tanous                 {"Health", "OK"},
1132029573d4SEd Tanous                 {"State", "Enabled"},
1133029573d4SEd Tanous             };
1134029573d4SEd Tanous         }
11354a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
11364a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
11374a0cb85cSEd Tanous         if (!ethData.hostname.empty())
11384a0cb85cSEd Tanous         {
11394a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
11404a0cb85cSEd Tanous         }
11414a0cb85cSEd Tanous 
11424a0cb85cSEd Tanous         nlohmann::json &vlanObj = json_response["VLAN"];
11434a0cb85cSEd Tanous         if (ethData.vlan_id)
11444a0cb85cSEd Tanous         {
11454a0cb85cSEd Tanous             vlanObj["VLANEnable"] = true;
11464a0cb85cSEd Tanous             vlanObj["VLANId"] = *ethData.vlan_id;
11474a0cb85cSEd Tanous         }
11484a0cb85cSEd Tanous         else
11494a0cb85cSEd Tanous         {
11504a0cb85cSEd Tanous             vlanObj["VLANEnable"] = false;
11514a0cb85cSEd Tanous             vlanObj["VLANId"] = 0;
11524a0cb85cSEd Tanous         }
1153029573d4SEd Tanous         json_response["NameServers"] = ethData.nameservers;
11544a0cb85cSEd Tanous 
11554a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
11564a0cb85cSEd Tanous         {
11574a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
11584a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
11594a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
11604a0cb85cSEd Tanous             {
11614a0cb85cSEd Tanous                 ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
11624a0cb85cSEd Tanous                                       {"SubnetMask", ipv4_config.netmask},
1163029573d4SEd Tanous                                       {"Address", ipv4_config.address},
1164029573d4SEd Tanous                                       {"Gateway", ipv4_config.gateway}});
11654a0cb85cSEd Tanous             }
11664a0cb85cSEd Tanous         }
1167588c3f0dSKowalski, Kamil     }
1168588c3f0dSKowalski, Kamil 
11699391bb9cSRapkiewicz, Pawel     /**
11709391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
11719391bb9cSRapkiewicz, Pawel      */
117255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
11731abe55efSEd Tanous                const std::vector<std::string> &params) override
11741abe55efSEd Tanous     {
11754a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
11761abe55efSEd Tanous         if (params.size() != 1)
11771abe55efSEd Tanous         {
1178f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
11799391bb9cSRapkiewicz, Pawel             return;
11809391bb9cSRapkiewicz, Pawel         }
11819391bb9cSRapkiewicz, Pawel 
11824a0cb85cSEd Tanous         getEthernetIfaceData(
11834a0cb85cSEd Tanous             params[0],
11844a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
11854a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
11864a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
11874a0cb85cSEd Tanous                 if (!success)
11881abe55efSEd Tanous                 {
11891abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
11901abe55efSEd Tanous                     // object, and other errors
1191f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1192f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
11934a0cb85cSEd Tanous                     return;
11949391bb9cSRapkiewicz, Pawel                 }
11950f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
11960f74e643SEd Tanous                     "#EthernetInterface.v1_2_0.EthernetInterface";
11970f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
11980f74e643SEd Tanous                     "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
11990f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface";
12000f74e643SEd Tanous                 asyncResp->res.jsonValue["Description"] =
12010f74e643SEd Tanous                     "Management Network Interface";
12020f74e643SEd Tanous 
12030f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
12040f74e643SEd Tanous                                    ipv4Data);
12059391bb9cSRapkiewicz, Pawel             });
12069391bb9cSRapkiewicz, Pawel     }
12079391bb9cSRapkiewicz, Pawel 
120855c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
12091abe55efSEd Tanous                  const std::vector<std::string> &params) override
12101abe55efSEd Tanous     {
12114a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
12121abe55efSEd Tanous         if (params.size() != 1)
12131abe55efSEd Tanous         {
1214f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1215588c3f0dSKowalski, Kamil             return;
1216588c3f0dSKowalski, Kamil         }
1217588c3f0dSKowalski, Kamil 
12184a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1219588c3f0dSKowalski, Kamil 
12200627a2c7SEd Tanous         std::optional<nlohmann::json> vlan;
1221bc0bd6e0SEd Tanous         std::optional<std::string> hostname;
1222*537174c4SEd Tanous         std::optional<std::vector<nlohmann::json>> ipv4Addresses;
1223*537174c4SEd Tanous         std::optional<std::vector<nlohmann::json>> ipv6Addresses;
12240627a2c7SEd Tanous 
12250627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname,
12260627a2c7SEd Tanous                                  "IPv4Addresses", ipv4Addresses,
12270627a2c7SEd Tanous                                  "IPv6Addresses", ipv6Addresses))
12281abe55efSEd Tanous         {
1229588c3f0dSKowalski, Kamil             return;
1230588c3f0dSKowalski, Kamil         }
12310627a2c7SEd Tanous         std::optional<uint64_t> vlanId = 0;
12320627a2c7SEd Tanous         std::optional<bool> vlanEnable = false;
12330627a2c7SEd Tanous         if (vlan)
12340627a2c7SEd Tanous         {
12350627a2c7SEd Tanous             if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable,
12360627a2c7SEd Tanous                                      "VLANId", vlanId))
12370627a2c7SEd Tanous             {
12380627a2c7SEd Tanous                 return;
12390627a2c7SEd Tanous             }
12400627a2c7SEd Tanous             // Need both vlanId and vlanEnable to service this request
12410627a2c7SEd Tanous             if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable))
12420627a2c7SEd Tanous             {
12430627a2c7SEd Tanous                 if (vlanId)
12440627a2c7SEd Tanous                 {
12450627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANEnable");
12460627a2c7SEd Tanous                 }
12470627a2c7SEd Tanous                 else
12480627a2c7SEd Tanous                 {
12490627a2c7SEd Tanous                     messages::propertyMissing(asyncResp->res, "VLANId");
12500627a2c7SEd Tanous                 }
12510627a2c7SEd Tanous 
12520627a2c7SEd Tanous                 return;
12530627a2c7SEd Tanous             }
12540627a2c7SEd Tanous         }
1255588c3f0dSKowalski, Kamil 
12564a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1257588c3f0dSKowalski, Kamil         // preparation
12584a0cb85cSEd Tanous         getEthernetIfaceData(
12594a0cb85cSEd Tanous             iface_id,
12600627a2c7SEd Tanous             [this, asyncResp, iface_id, vlanId, vlanEnable,
12610627a2c7SEd Tanous              hostname = std::move(hostname),
12620627a2c7SEd Tanous              ipv4Addresses = std::move(ipv4Addresses),
12630627a2c7SEd Tanous              ipv6Addresses = std::move(ipv6Addresses)](
12644a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
12654a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
12661abe55efSEd Tanous                 if (!success)
12671abe55efSEd Tanous                 {
1268588c3f0dSKowalski, Kamil                     // ... otherwise return error
12691abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
12701abe55efSEd Tanous                     // object, and other errors
1271f12894f8SJason M. Bills                     messages::resourceNotFound(
1272f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1273588c3f0dSKowalski, Kamil                     return;
1274588c3f0dSKowalski, Kamil                 }
1275588c3f0dSKowalski, Kamil 
12760f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData,
12770f74e643SEd Tanous                                    ipv4Data);
1278588c3f0dSKowalski, Kamil 
12790627a2c7SEd Tanous                 if (vlanId && vlanEnable)
12801abe55efSEd Tanous                 {
12810627a2c7SEd Tanous                     handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData,
12824a0cb85cSEd Tanous                                     asyncResp);
12831abe55efSEd Tanous                 }
12840627a2c7SEd Tanous 
12850627a2c7SEd Tanous                 if (hostname)
12861abe55efSEd Tanous                 {
12870627a2c7SEd Tanous                     handleHostnamePatch(*hostname, asyncResp);
12881abe55efSEd Tanous                 }
12890627a2c7SEd Tanous 
12900627a2c7SEd Tanous                 if (ipv4Addresses)
12911abe55efSEd Tanous                 {
1292*537174c4SEd Tanous                     // TODO(ed) for some reason the capture of ipv4Addresses
1293*537174c4SEd Tanous                     // above is returning a const value, not a non-const value.
1294*537174c4SEd Tanous                     // This doesn't really work for us, as we need to be able to
1295*537174c4SEd Tanous                     // efficiently move out the intermedia nlohmann::json
1296*537174c4SEd Tanous                     // objects. This makes a copy of the structure, and operates
1297*537174c4SEd Tanous                     // on that, but could be done more efficiently
1298*537174c4SEd Tanous                     std::vector<nlohmann::json> ipv4 =
1299*537174c4SEd Tanous                         std::move(*ipv4Addresses);
1300*537174c4SEd Tanous                     handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp);
13011abe55efSEd Tanous                 }
13020627a2c7SEd Tanous 
13030627a2c7SEd Tanous                 if (ipv6Addresses)
13041abe55efSEd Tanous                 {
1305179db1d7SKowalski, Kamil                     // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1306a08b46ccSJason M. Bills                     messages::propertyNotWritable(asyncResp->res,
13070627a2c7SEd Tanous                                                   "IPv6Addresses");
1308588c3f0dSKowalski, Kamil                 }
1309588c3f0dSKowalski, Kamil             });
1310588c3f0dSKowalski, Kamil     }
13119391bb9cSRapkiewicz, Pawel };
13129391bb9cSRapkiewicz, Pawel 
1313e439f0f8SKowalski, Kamil /**
13144a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
13154a0cb85cSEd Tanous  * Schema
1316e439f0f8SKowalski, Kamil  */
13171abe55efSEd Tanous class VlanNetworkInterface : public Node
13181abe55efSEd Tanous {
1319e439f0f8SKowalski, Kamil   public:
1320e439f0f8SKowalski, Kamil     /*
1321e439f0f8SKowalski, Kamil      * Default Constructor
1322e439f0f8SKowalski, Kamil      */
1323e439f0f8SKowalski, Kamil     template <typename CrowApp>
13241abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
13254a0cb85cSEd Tanous         Node(app,
13260f74e643SEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>",
13271abe55efSEd Tanous              std::string(), std::string())
13281abe55efSEd Tanous     {
1329e439f0f8SKowalski, Kamil         entityPrivileges = {
1330e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1331e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1332e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1333e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1334e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1335e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1336e439f0f8SKowalski, Kamil     }
1337e439f0f8SKowalski, Kamil 
1338e439f0f8SKowalski, Kamil   private:
13390f74e643SEd Tanous     void parseInterfaceData(
13400f74e643SEd Tanous         nlohmann::json &json_response, const std::string &parent_iface_id,
13410f74e643SEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
13424a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
13431abe55efSEd Tanous     {
1344e439f0f8SKowalski, Kamil         // Fill out obvious data...
13454a0cb85cSEd Tanous         json_response["Id"] = iface_id;
13464a0cb85cSEd Tanous         json_response["@odata.id"] =
13474a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
13484a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1349e439f0f8SKowalski, Kamil 
13504a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
13514a0cb85cSEd Tanous         if (ethData.vlan_id)
13524a0cb85cSEd Tanous         {
13534a0cb85cSEd Tanous             json_response["VLANId"] = *ethData.vlan_id;
13544a0cb85cSEd Tanous         }
1355e439f0f8SKowalski, Kamil     }
1356e439f0f8SKowalski, Kamil 
135755c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
13581abe55efSEd Tanous                      const std::string &iface)
13591abe55efSEd Tanous     {
1360f12894f8SJason M. Bills         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13611abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
13621abe55efSEd Tanous         {
1363f12894f8SJason M. Bills             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1364f12894f8SJason M. Bills                                        iface);
1365927a505aSKowalski, Kamil             return false;
13661abe55efSEd Tanous         }
13671abe55efSEd Tanous         else
13681abe55efSEd Tanous         {
1369927a505aSKowalski, Kamil             return true;
1370927a505aSKowalski, Kamil         }
1371927a505aSKowalski, Kamil     }
1372927a505aSKowalski, Kamil 
1373e439f0f8SKowalski, Kamil     /**
1374e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1375e439f0f8SKowalski, Kamil      */
137655c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
13771abe55efSEd Tanous                const std::vector<std::string> &params) override
13781abe55efSEd Tanous     {
13794a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13804a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1381e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1382e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1383e439f0f8SKowalski, Kamil         // impossible.
13841abe55efSEd Tanous         if (params.size() != 2)
13851abe55efSEd Tanous         {
1386f12894f8SJason M. Bills             messages::internalError(res);
1387e439f0f8SKowalski, Kamil             res.end();
1388e439f0f8SKowalski, Kamil             return;
1389e439f0f8SKowalski, Kamil         }
1390e439f0f8SKowalski, Kamil 
13914a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
13924a0cb85cSEd Tanous         const std::string &iface_id = params[1];
13930f74e643SEd Tanous         res.jsonValue["@odata.type"] =
13940f74e643SEd Tanous             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
13950f74e643SEd Tanous         res.jsonValue["@odata.context"] =
13960f74e643SEd Tanous             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
13970f74e643SEd Tanous         res.jsonValue["Name"] = "VLAN Network Interface";
1398e439f0f8SKowalski, Kamil 
13994a0cb85cSEd Tanous         if (!verifyNames(res, parent_iface_id, iface_id))
14001abe55efSEd Tanous         {
1401a434f2bdSEd Tanous             return;
1402a434f2bdSEd Tanous         }
1403a434f2bdSEd Tanous 
1404e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1405e439f0f8SKowalski, Kamil         // preparation
14064a0cb85cSEd Tanous         getEthernetIfaceData(
14074a0cb85cSEd Tanous             iface_id,
14084a0cb85cSEd Tanous             [this, asyncResp, parent_iface_id, iface_id](
14094a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14104a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14114a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
14121abe55efSEd Tanous                 {
14130f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue,
14140f74e643SEd Tanous                                        parent_iface_id, iface_id, ethData,
14150f74e643SEd Tanous                                        ipv4Data);
14161abe55efSEd Tanous                 }
14171abe55efSEd Tanous                 else
14181abe55efSEd Tanous                 {
1419e439f0f8SKowalski, Kamil                     // ... otherwise return error
14201abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14211abe55efSEd Tanous                     // object, and other errors
1422f12894f8SJason M. Bills                     messages::resourceNotFound(
1423f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1424e439f0f8SKowalski, Kamil                 }
1425e439f0f8SKowalski, Kamil             });
1426e439f0f8SKowalski, Kamil     }
1427e439f0f8SKowalski, Kamil 
142855c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
14291abe55efSEd Tanous                  const std::vector<std::string> &params) override
14301abe55efSEd Tanous     {
14314a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14321abe55efSEd Tanous         if (params.size() != 2)
14331abe55efSEd Tanous         {
1434f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1435e439f0f8SKowalski, Kamil             return;
1436e439f0f8SKowalski, Kamil         }
1437e439f0f8SKowalski, Kamil 
1438d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
143955c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1440927a505aSKowalski, Kamil 
14411abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
14421abe55efSEd Tanous         {
1443927a505aSKowalski, Kamil             return;
1444927a505aSKowalski, Kamil         }
1445927a505aSKowalski, Kamil 
14460627a2c7SEd Tanous         bool vlanEnable = false;
14470627a2c7SEd Tanous         uint64_t vlanId = 0;
14480627a2c7SEd Tanous 
14490627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId",
14500627a2c7SEd Tanous                                  vlanId))
14511abe55efSEd Tanous         {
1452927a505aSKowalski, Kamil             return;
1453927a505aSKowalski, Kamil         }
1454927a505aSKowalski, Kamil 
1455927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1456927a505aSKowalski, Kamil         // preparation
14574a0cb85cSEd Tanous         getEthernetIfaceData(
14581abe55efSEd Tanous             ifaceId,
14590627a2c7SEd Tanous             [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId](
14604a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
14614a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
14621abe55efSEd Tanous                 if (!success)
14631abe55efSEd Tanous                 {
14641abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
14651abe55efSEd Tanous                     // object, and other errors
1466f12894f8SJason M. Bills                     messages::resourceNotFound(
1467f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1468927a505aSKowalski, Kamil 
1469927a505aSKowalski, Kamil                     return;
1470927a505aSKowalski, Kamil                 }
1471927a505aSKowalski, Kamil 
14720f74e643SEd Tanous                 parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
14730f74e643SEd Tanous                                    ifaceId, ethData, ipv4Data);
1474927a505aSKowalski, Kamil 
14750627a2c7SEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable,
14760627a2c7SEd Tanous                                                    ethData, asyncResp);
1477927a505aSKowalski, Kamil             });
1478e439f0f8SKowalski, Kamil     }
1479e439f0f8SKowalski, Kamil 
148055c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
14811abe55efSEd Tanous                   const std::vector<std::string> &params) override
14821abe55efSEd Tanous     {
14834a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14841abe55efSEd Tanous         if (params.size() != 2)
14851abe55efSEd Tanous         {
1486f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1487e439f0f8SKowalski, Kamil             return;
1488e439f0f8SKowalski, Kamil         }
1489e439f0f8SKowalski, Kamil 
1490d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
149155c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1492927a505aSKowalski, Kamil 
14934a0cb85cSEd Tanous         if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
14941abe55efSEd Tanous         {
1495927a505aSKowalski, Kamil             return;
1496927a505aSKowalski, Kamil         }
1497927a505aSKowalski, Kamil 
1498927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1499927a505aSKowalski, Kamil         // preparation
1500f12894f8SJason M. Bills         getEthernetIfaceData(
1501f12894f8SJason M. Bills             ifaceId,
1502f12894f8SJason M. Bills             [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
15034a0cb85cSEd Tanous              ifaceId{std::string(ifaceId)}](
1504f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1505f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15064a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
15071abe55efSEd Tanous                 {
15080f74e643SEd Tanous                     parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId,
15090f74e643SEd Tanous                                        ifaceId, ethData, ipv4Data);
1510927a505aSKowalski, Kamil 
1511f12894f8SJason M. Bills                     auto callback =
1512f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
15131abe55efSEd Tanous                             if (ec)
15141abe55efSEd Tanous                             {
1515f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1516927a505aSKowalski, Kamil                             }
15174a0cb85cSEd Tanous                         };
15184a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
15194a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
15204a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
15214a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
15221abe55efSEd Tanous                 }
15231abe55efSEd Tanous                 else
15241abe55efSEd Tanous                 {
1525927a505aSKowalski, Kamil                     // ... otherwise return error
1526f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1527f12894f8SJason M. Bills                     // object, and other errors
1528f12894f8SJason M. Bills                     messages::resourceNotFound(
1529f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1530927a505aSKowalski, Kamil                 }
1531927a505aSKowalski, Kamil             });
1532e439f0f8SKowalski, Kamil     }
1533e439f0f8SKowalski, Kamil };
1534e439f0f8SKowalski, Kamil 
1535e439f0f8SKowalski, Kamil /**
1536e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1537e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1538e439f0f8SKowalski, Kamil  */
15391abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
15401abe55efSEd Tanous {
1541e439f0f8SKowalski, Kamil   public:
1542e439f0f8SKowalski, Kamil     template <typename CrowApp>
15431abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
15444a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
15454a0cb85cSEd Tanous              std::string())
15461abe55efSEd Tanous     {
1547e439f0f8SKowalski, Kamil         entityPrivileges = {
1548e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1549e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1550e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1551e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1552e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1553e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1554e439f0f8SKowalski, Kamil     }
1555e439f0f8SKowalski, Kamil 
1556e439f0f8SKowalski, Kamil   private:
1557e439f0f8SKowalski, Kamil     /**
1558e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1559e439f0f8SKowalski, Kamil      */
156055c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15611abe55efSEd Tanous                const std::vector<std::string> &params) override
15621abe55efSEd Tanous     {
15634a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15641abe55efSEd Tanous         if (params.size() != 1)
15651abe55efSEd Tanous         {
1566e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1567f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1568e439f0f8SKowalski, Kamil             return;
1569e439f0f8SKowalski, Kamil         }
1570e439f0f8SKowalski, Kamil 
15714a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1572e439f0f8SKowalski, Kamil 
15734a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
15741abe55efSEd Tanous         // preparation
1575f12894f8SJason M. Bills         getEthernetIfaceList(
157643b761d0SEd Tanous             [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}](
15771abe55efSEd Tanous                 const bool &success,
15781abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
15794a0cb85cSEd Tanous                 if (!success)
15801abe55efSEd Tanous                 {
1581f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
15824a0cb85cSEd Tanous                     return;
15831abe55efSEd Tanous                 }
15840f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
15850f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
15860f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
15870f74e643SEd Tanous                 asyncResp->res.jsonValue["@odata.context"] =
15880f74e643SEd Tanous                     "/redfish/v1/$metadata"
15890f74e643SEd Tanous                     "#VLanNetworkInterfaceCollection."
15900f74e643SEd Tanous                     "VLanNetworkInterfaceCollection";
15910f74e643SEd Tanous                 asyncResp->res.jsonValue["Name"] =
15920f74e643SEd Tanous                     "VLAN Network Interface Collection";
15934a0cb85cSEd Tanous 
15944a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
15954a0cb85cSEd Tanous 
15964a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
15971abe55efSEd Tanous                 {
15984a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
15994a0cb85cSEd Tanous                     {
16004a0cb85cSEd Tanous                         iface_array.push_back(
16014a0cb85cSEd Tanous                             {{"@odata.id",
16024a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
16034a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1604e439f0f8SKowalski, Kamil                     }
1605e439f0f8SKowalski, Kamil                 }
1606e439f0f8SKowalski, Kamil 
16074a0cb85cSEd Tanous                 if (iface_array.empty())
16081abe55efSEd Tanous                 {
1609f12894f8SJason M. Bills                     messages::resourceNotFound(
1610f12894f8SJason M. Bills                         asyncResp->res, "EthernetInterface", rootInterfaceName);
16114a0cb85cSEd Tanous                     return;
1612e439f0f8SKowalski, Kamil                 }
16134a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
16144a0cb85cSEd Tanous                     iface_array.size();
16154a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
16164a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
16174a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
16184a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1619e439f0f8SKowalski, Kamil             });
1620e439f0f8SKowalski, Kamil     }
1621e439f0f8SKowalski, Kamil 
162255c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
16231abe55efSEd Tanous                 const std::vector<std::string> &params) override
16241abe55efSEd Tanous     {
16254a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16261abe55efSEd Tanous         if (params.size() != 1)
16271abe55efSEd Tanous         {
1628f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1629e439f0f8SKowalski, Kamil             return;
1630e439f0f8SKowalski, Kamil         }
1631e439f0f8SKowalski, Kamil 
16320627a2c7SEd Tanous         uint32_t vlanId = 0;
16330627a2c7SEd Tanous         if (!json_util::readJson(req, res, "VLANId", vlanId))
16341abe55efSEd Tanous         {
16354a0cb85cSEd Tanous             return;
1636e439f0f8SKowalski, Kamil         }
16374a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
16384a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
16391abe55efSEd Tanous             if (ec)
16401abe55efSEd Tanous             {
16414a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
16424a0cb85cSEd Tanous                 // phosphor-network responses
1643f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
16444a0cb85cSEd Tanous                 return;
16451abe55efSEd Tanous             }
1646f12894f8SJason M. Bills             messages::created(asyncResp->res);
1647e439f0f8SKowalski, Kamil         };
16484a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
16494a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
16504a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
16514a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
16520627a2c7SEd Tanous             rootInterfaceName, vlanId);
16534a0cb85cSEd Tanous     }
16544a0cb85cSEd Tanous };
16559391bb9cSRapkiewicz, Pawel } // namespace redfish
1656