xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision f12894f8bd7fc26ffa16e5a89072e6c19095f866)
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>
204a0cb85cSEd Tanous #include <boost/optional.hpp>
21179db1d7SKowalski, Kamil #include <dbus_singleton.hpp>
22588c3f0dSKowalski, Kamil #include <error_messages.hpp>
23179db1d7SKowalski, Kamil #include <node.hpp>
24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp>
259391bb9cSRapkiewicz, Pawel 
261abe55efSEd Tanous namespace redfish
271abe55efSEd Tanous {
289391bb9cSRapkiewicz, Pawel 
299391bb9cSRapkiewicz, Pawel /**
309391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
319391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
329391bb9cSRapkiewicz, Pawel  */
33aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
34aa2e59c1SEd Tanous     std::string,
35aa2e59c1SEd Tanous     sdbusplus::message::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<
43aa2e59c1SEd Tanous             std::string, sdbusplus::message::variant<
44aa2e59c1SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
454a0cb85cSEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double>>>>>>;
464a0cb85cSEd Tanous 
474a0cb85cSEd Tanous enum class LinkType
484a0cb85cSEd Tanous {
494a0cb85cSEd Tanous     Local,
504a0cb85cSEd Tanous     Global
514a0cb85cSEd Tanous };
529391bb9cSRapkiewicz, Pawel 
539391bb9cSRapkiewicz, Pawel /**
549391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
559391bb9cSRapkiewicz, Pawel  */
561abe55efSEd Tanous struct IPv4AddressData
571abe55efSEd Tanous {
58179db1d7SKowalski, Kamil     std::string id;
594a0cb85cSEd Tanous     std::string address;
604a0cb85cSEd Tanous     std::string domain;
614a0cb85cSEd Tanous     std::string gateway;
629391bb9cSRapkiewicz, Pawel     std::string netmask;
639391bb9cSRapkiewicz, Pawel     std::string origin;
644a0cb85cSEd Tanous     LinkType linktype;
654a0cb85cSEd Tanous 
661abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
671abe55efSEd Tanous     {
684a0cb85cSEd Tanous         return id < obj.id;
691abe55efSEd Tanous     }
709391bb9cSRapkiewicz, Pawel };
719391bb9cSRapkiewicz, Pawel 
729391bb9cSRapkiewicz, Pawel /**
739391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
749391bb9cSRapkiewicz, Pawel  * available from DBus
759391bb9cSRapkiewicz, Pawel  */
761abe55efSEd Tanous struct EthernetInterfaceData
771abe55efSEd Tanous {
784a0cb85cSEd Tanous     uint32_t speed;
794a0cb85cSEd Tanous     bool auto_neg;
804a0cb85cSEd Tanous     std::string hostname;
814a0cb85cSEd Tanous     std::string default_gateway;
824a0cb85cSEd Tanous     std::string mac_address;
834a0cb85cSEd Tanous     boost::optional<uint32_t> vlan_id;
849391bb9cSRapkiewicz, Pawel };
859391bb9cSRapkiewicz, Pawel 
869391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24)
879391bb9cSRapkiewicz, Pawel // into full dot notation
881abe55efSEd Tanous inline std::string getNetmask(unsigned int bits)
891abe55efSEd Tanous {
909391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
919391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
929391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
939391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
949391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
959391bb9cSRapkiewicz, Pawel     return netmask;
969391bb9cSRapkiewicz, Pawel }
979391bb9cSRapkiewicz, Pawel 
984a0cb85cSEd Tanous inline std::string
994a0cb85cSEd Tanous     translateAddressOriginDbusToRedfish(const std::string &inputOrigin,
1004a0cb85cSEd Tanous                                         bool isIPv4)
1011abe55efSEd Tanous {
1024a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
1031abe55efSEd Tanous     {
1044a0cb85cSEd Tanous         return "Static";
1059391bb9cSRapkiewicz, Pawel     }
1064a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal")
1071abe55efSEd Tanous     {
1084a0cb85cSEd Tanous         if (isIPv4)
1091abe55efSEd Tanous         {
1104a0cb85cSEd Tanous             return "IPv4LinkLocal";
1111abe55efSEd Tanous         }
1121abe55efSEd Tanous         else
1131abe55efSEd Tanous         {
1144a0cb85cSEd Tanous             return "LinkLocal";
1159391bb9cSRapkiewicz, Pawel         }
1169391bb9cSRapkiewicz, Pawel     }
1174a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1181abe55efSEd Tanous     {
1194a0cb85cSEd Tanous         if (isIPv4)
1204a0cb85cSEd Tanous         {
1214a0cb85cSEd Tanous             return "DHCP";
1224a0cb85cSEd Tanous         }
1234a0cb85cSEd Tanous         else
1244a0cb85cSEd Tanous         {
1254a0cb85cSEd Tanous             return "DHCPv6";
1264a0cb85cSEd Tanous         }
1274a0cb85cSEd Tanous     }
1284a0cb85cSEd Tanous     if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC")
1294a0cb85cSEd Tanous     {
1304a0cb85cSEd Tanous         return "SLAAC";
1314a0cb85cSEd Tanous     }
1324a0cb85cSEd Tanous     return "";
1334a0cb85cSEd Tanous }
1344a0cb85cSEd Tanous 
1354a0cb85cSEd Tanous inline std::string
1364a0cb85cSEd Tanous     translateAddressOriginRedfishToDbus(const std::string &inputOrigin)
1374a0cb85cSEd Tanous {
1384a0cb85cSEd Tanous     if (inputOrigin == "Static")
1394a0cb85cSEd Tanous     {
1404a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
1414a0cb85cSEd Tanous     }
1424a0cb85cSEd Tanous     if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6")
1434a0cb85cSEd Tanous     {
1444a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
1454a0cb85cSEd Tanous     }
1464a0cb85cSEd Tanous     if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal")
1474a0cb85cSEd Tanous     {
1484a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal";
1494a0cb85cSEd Tanous     }
1504a0cb85cSEd Tanous     if (inputOrigin == "SLAAC")
1514a0cb85cSEd Tanous     {
1524a0cb85cSEd Tanous         return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC";
1534a0cb85cSEd Tanous     }
1544a0cb85cSEd Tanous     return "";
1554a0cb85cSEd Tanous }
1564a0cb85cSEd Tanous 
1574a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string &ethiface_id,
1584a0cb85cSEd Tanous                                          const GetManagedObjects &dbus_data,
1594a0cb85cSEd Tanous                                          EthernetInterfaceData &ethData)
1604a0cb85cSEd Tanous {
1614a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
1624a0cb85cSEd Tanous     {
1634a0cb85cSEd Tanous         if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id)
1644a0cb85cSEd Tanous         {
1654a0cb85cSEd Tanous             for (const auto &ifacePair : objpath.second)
1664a0cb85cSEd Tanous             {
1674a0cb85cSEd Tanous                 if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress")
1684a0cb85cSEd Tanous                 {
1694a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1704a0cb85cSEd Tanous                     {
1714a0cb85cSEd Tanous                         if (propertyPair.first == "MACAddress")
1724a0cb85cSEd Tanous                         {
1734a0cb85cSEd Tanous                             const std::string *mac =
1744a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
1754a0cb85cSEd Tanous                                     propertyPair.second);
1764a0cb85cSEd Tanous                             if (mac != nullptr)
1774a0cb85cSEd Tanous                             {
1784a0cb85cSEd Tanous                                 ethData.mac_address = *mac;
1794a0cb85cSEd Tanous                             }
1804a0cb85cSEd Tanous                         }
1814a0cb85cSEd Tanous                     }
1824a0cb85cSEd Tanous                 }
1834a0cb85cSEd Tanous                 else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN")
1844a0cb85cSEd Tanous                 {
1854a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
1864a0cb85cSEd Tanous                     {
1874a0cb85cSEd Tanous                         if (propertyPair.first == "Id")
1884a0cb85cSEd Tanous                         {
1894a0cb85cSEd Tanous                             const uint32_t *id = mapbox::getPtr<const uint32_t>(
1904a0cb85cSEd Tanous                                 propertyPair.second);
1914a0cb85cSEd Tanous                             if (id != nullptr)
1924a0cb85cSEd Tanous                             {
1934a0cb85cSEd Tanous                                 ethData.vlan_id = *id;
1944a0cb85cSEd Tanous                             }
1954a0cb85cSEd Tanous                         }
1964a0cb85cSEd Tanous                     }
1974a0cb85cSEd Tanous                 }
1984a0cb85cSEd Tanous                 else if (ifacePair.first ==
1994a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.EthernetInterface")
2004a0cb85cSEd Tanous                 {
2014a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2024a0cb85cSEd Tanous                     {
2034a0cb85cSEd Tanous                         if (propertyPair.first == "AutoNeg")
2044a0cb85cSEd Tanous                         {
2054a0cb85cSEd Tanous                             const bool *auto_neg =
2064a0cb85cSEd Tanous                                 mapbox::getPtr<const bool>(propertyPair.second);
2074a0cb85cSEd Tanous                             if (auto_neg != nullptr)
2084a0cb85cSEd Tanous                             {
2094a0cb85cSEd Tanous                                 ethData.auto_neg = *auto_neg;
2104a0cb85cSEd Tanous                             }
2114a0cb85cSEd Tanous                         }
2124a0cb85cSEd Tanous                         else if (propertyPair.first == "Speed")
2134a0cb85cSEd Tanous                         {
2144a0cb85cSEd Tanous                             const uint32_t *speed =
2154a0cb85cSEd Tanous                                 mapbox::getPtr<const uint32_t>(
2164a0cb85cSEd Tanous                                     propertyPair.second);
2174a0cb85cSEd Tanous                             if (speed != nullptr)
2184a0cb85cSEd Tanous                             {
2194a0cb85cSEd Tanous                                 ethData.speed = *speed;
2204a0cb85cSEd Tanous                             }
2214a0cb85cSEd Tanous                         }
2224a0cb85cSEd Tanous                     }
2234a0cb85cSEd Tanous                 }
2244a0cb85cSEd Tanous                 else if (ifacePair.first ==
2254a0cb85cSEd Tanous                          "xyz.openbmc_project.Network.SystemConfiguration")
2264a0cb85cSEd Tanous                 {
2274a0cb85cSEd Tanous                     for (const auto &propertyPair : ifacePair.second)
2284a0cb85cSEd Tanous                     {
2294a0cb85cSEd Tanous                         if (propertyPair.first == "HostName")
2304a0cb85cSEd Tanous                         {
2314a0cb85cSEd Tanous                             const std::string *hostname =
2324a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
2334a0cb85cSEd Tanous                                     propertyPair.second);
2344a0cb85cSEd Tanous                             if (hostname != nullptr)
2354a0cb85cSEd Tanous                             {
2364a0cb85cSEd Tanous                                 ethData.hostname = *hostname;
2374a0cb85cSEd Tanous                             }
2384a0cb85cSEd Tanous                         }
2394a0cb85cSEd Tanous                         else if (propertyPair.first == "DefaultGateway")
2404a0cb85cSEd Tanous                         {
2414a0cb85cSEd Tanous                             const std::string *defaultGateway =
2424a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
2434a0cb85cSEd Tanous                                     propertyPair.second);
2444a0cb85cSEd Tanous                             if (defaultGateway != nullptr)
2454a0cb85cSEd Tanous                             {
2464a0cb85cSEd Tanous                                 ethData.default_gateway = *defaultGateway;
2474a0cb85cSEd Tanous                             }
2484a0cb85cSEd Tanous                         }
2494a0cb85cSEd Tanous                     }
2504a0cb85cSEd Tanous                 }
2514a0cb85cSEd Tanous             }
2524a0cb85cSEd Tanous         }
2534a0cb85cSEd Tanous     }
2544a0cb85cSEd Tanous }
2554a0cb85cSEd Tanous 
2564a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address
2574a0cb85cSEd Tanous inline void
2584a0cb85cSEd Tanous     extractIPData(const std::string &ethiface_id,
2594a0cb85cSEd Tanous                   const GetManagedObjects &dbus_data,
2604a0cb85cSEd Tanous                   boost::container::flat_set<IPv4AddressData> &ipv4_config)
2614a0cb85cSEd Tanous {
2624a0cb85cSEd Tanous     const std::string ipv4PathStart =
2634a0cb85cSEd Tanous         "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/";
2644a0cb85cSEd Tanous 
2654a0cb85cSEd Tanous     // Since there might be several IPv4 configurations aligned with
2664a0cb85cSEd Tanous     // single ethernet interface, loop over all of them
2674a0cb85cSEd Tanous     for (const auto &objpath : dbus_data)
2684a0cb85cSEd Tanous     {
2694a0cb85cSEd Tanous         // Check if proper pattern for object path appears
2704a0cb85cSEd Tanous         if (boost::starts_with(objpath.first.str, ipv4PathStart))
2714a0cb85cSEd Tanous         {
2724a0cb85cSEd Tanous             for (auto &interface : objpath.second)
2734a0cb85cSEd Tanous             {
2744a0cb85cSEd Tanous                 if (interface.first == "xyz.openbmc_project.Network.IP")
2754a0cb85cSEd Tanous                 {
2764a0cb85cSEd Tanous                     // Instance IPv4AddressData structure, and set as
2774a0cb85cSEd Tanous                     // appropriate
2784a0cb85cSEd Tanous                     std::pair<
2794a0cb85cSEd Tanous                         boost::container::flat_set<IPv4AddressData>::iterator,
2804a0cb85cSEd Tanous                         bool>
2814a0cb85cSEd Tanous                         it = ipv4_config.insert(
2824a0cb85cSEd Tanous                             {objpath.first.str.substr(ipv4PathStart.size())});
2834a0cb85cSEd Tanous                     IPv4AddressData &ipv4_address = *it.first;
2844a0cb85cSEd Tanous                     for (auto &property : interface.second)
2854a0cb85cSEd Tanous                     {
2864a0cb85cSEd Tanous                         if (property.first == "Address")
2874a0cb85cSEd Tanous                         {
2884a0cb85cSEd Tanous                             const std::string *address =
2894a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
2904a0cb85cSEd Tanous                                     property.second);
2914a0cb85cSEd Tanous                             if (address != nullptr)
2924a0cb85cSEd Tanous                             {
2934a0cb85cSEd Tanous                                 ipv4_address.address = *address;
2944a0cb85cSEd Tanous                             }
2954a0cb85cSEd Tanous                         }
2964a0cb85cSEd Tanous                         else if (property.first == "Gateway")
2974a0cb85cSEd Tanous                         {
2984a0cb85cSEd Tanous                             const std::string *gateway =
2994a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
3004a0cb85cSEd Tanous                                     property.second);
3014a0cb85cSEd Tanous                             if (gateway != nullptr)
3024a0cb85cSEd Tanous                             {
3034a0cb85cSEd Tanous                                 ipv4_address.gateway = *gateway;
3044a0cb85cSEd Tanous                             }
3054a0cb85cSEd Tanous                         }
3064a0cb85cSEd Tanous                         else if (property.first == "Origin")
3074a0cb85cSEd Tanous                         {
3084a0cb85cSEd Tanous                             const std::string *origin =
3094a0cb85cSEd Tanous                                 mapbox::getPtr<const std::string>(
3104a0cb85cSEd Tanous                                     property.second);
3114a0cb85cSEd Tanous                             if (origin != nullptr)
3124a0cb85cSEd Tanous                             {
3134a0cb85cSEd Tanous                                 ipv4_address.origin =
3144a0cb85cSEd Tanous                                     translateAddressOriginDbusToRedfish(*origin,
3154a0cb85cSEd Tanous                                                                         true);
3164a0cb85cSEd Tanous                             }
3174a0cb85cSEd Tanous                         }
3184a0cb85cSEd Tanous                         else if (property.first == "PrefixLength")
3194a0cb85cSEd Tanous                         {
3204a0cb85cSEd Tanous                             const uint8_t *mask =
3214a0cb85cSEd Tanous                                 mapbox::getPtr<uint8_t>(property.second);
3224a0cb85cSEd Tanous                             if (mask != nullptr)
3234a0cb85cSEd Tanous                             {
3244a0cb85cSEd Tanous                                 // convert it to the string
3254a0cb85cSEd Tanous                                 ipv4_address.netmask = getNetmask(*mask);
3264a0cb85cSEd Tanous                             }
3274a0cb85cSEd Tanous                         }
3284a0cb85cSEd Tanous                         else
3294a0cb85cSEd Tanous                         {
3304a0cb85cSEd Tanous                             BMCWEB_LOG_ERROR
3314a0cb85cSEd Tanous                                 << "Got extra property: " << property.first
3324a0cb85cSEd Tanous                                 << " on the " << objpath.first.str << " object";
3334a0cb85cSEd Tanous                         }
3344a0cb85cSEd Tanous                     }
3354a0cb85cSEd Tanous                     // Check if given address is local, or global
3364a0cb85cSEd Tanous                     ipv4_address.linktype =
3374a0cb85cSEd Tanous                         boost::starts_with(ipv4_address.address, "169.254.")
3384a0cb85cSEd Tanous                             ? LinkType::Global
3394a0cb85cSEd Tanous                             : LinkType::Local;
3404a0cb85cSEd Tanous                 }
3414a0cb85cSEd Tanous             }
3424a0cb85cSEd Tanous         }
3434a0cb85cSEd Tanous     }
3444a0cb85cSEd Tanous }
345588c3f0dSKowalski, Kamil 
346588c3f0dSKowalski, Kamil /**
347588c3f0dSKowalski, Kamil  * @brief Sets given Id on the given VLAN interface through D-Bus
348588c3f0dSKowalski, Kamil  *
349588c3f0dSKowalski, Kamil  * @param[in] ifaceId       Id of VLAN interface that should be modified
350588c3f0dSKowalski, Kamil  * @param[in] inputVlanId   New ID of the VLAN
351588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
352588c3f0dSKowalski, Kamil  *
353588c3f0dSKowalski, Kamil  * @return None.
354588c3f0dSKowalski, Kamil  */
355588c3f0dSKowalski, Kamil template <typename CallbackFunc>
3564a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId,
3571abe55efSEd Tanous                   CallbackFunc &&callback)
3581abe55efSEd Tanous {
35955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
360588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
361588c3f0dSKowalski, Kamil         std::string("/xyz/openbmc_project/network/") + ifaceId,
362588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
363588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", "Id",
364588c3f0dSKowalski, Kamil         sdbusplus::message::variant<uint32_t>(inputVlanId));
3654a0cb85cSEd Tanous }
366588c3f0dSKowalski, Kamil 
367588c3f0dSKowalski, Kamil /**
368179db1d7SKowalski, Kamil  * @brief Helper function that verifies IP address to check if it is in
369179db1d7SKowalski, Kamil  *        proper format. If bits pointer is provided, also calculates active
370179db1d7SKowalski, Kamil  *        bit count for Subnet Mask.
371179db1d7SKowalski, Kamil  *
372179db1d7SKowalski, Kamil  * @param[in]  ip     IP that will be verified
373179db1d7SKowalski, Kamil  * @param[out] bits   Calculated mask in bits notation
374179db1d7SKowalski, Kamil  *
375179db1d7SKowalski, Kamil  * @return true in case of success, false otherwise
376179db1d7SKowalski, Kamil  */
3774a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
3781abe55efSEd Tanous                                        uint8_t *bits = nullptr)
3791abe55efSEd Tanous {
380179db1d7SKowalski, Kamil     std::vector<std::string> bytesInMask;
381179db1d7SKowalski, Kamil 
382179db1d7SKowalski, Kamil     boost::split(bytesInMask, ip, boost::is_any_of("."));
383179db1d7SKowalski, Kamil 
3844a0cb85cSEd Tanous     static const constexpr int ipV4AddressSectionsCount = 4;
3851abe55efSEd Tanous     if (bytesInMask.size() != ipV4AddressSectionsCount)
3861abe55efSEd Tanous     {
387179db1d7SKowalski, Kamil         return false;
388179db1d7SKowalski, Kamil     }
389179db1d7SKowalski, Kamil 
3901abe55efSEd Tanous     if (bits != nullptr)
3911abe55efSEd Tanous     {
392179db1d7SKowalski, Kamil         *bits = 0;
393179db1d7SKowalski, Kamil     }
394179db1d7SKowalski, Kamil 
395179db1d7SKowalski, Kamil     char *endPtr;
396179db1d7SKowalski, Kamil     long previousValue = 255;
397179db1d7SKowalski, Kamil     bool firstZeroInByteHit;
3981abe55efSEd Tanous     for (const std::string &byte : bytesInMask)
3991abe55efSEd Tanous     {
4001abe55efSEd Tanous         if (byte.empty())
4011abe55efSEd Tanous         {
4021db9ca37SKowalski, Kamil             return false;
4031db9ca37SKowalski, Kamil         }
4041db9ca37SKowalski, Kamil 
405179db1d7SKowalski, Kamil         // Use strtol instead of stroi to avoid exceptions
4061db9ca37SKowalski, Kamil         long value = std::strtol(byte.c_str(), &endPtr, 10);
407179db1d7SKowalski, Kamil 
4084a0cb85cSEd Tanous         // endPtr should point to the end of the string, otherwise given string
4094a0cb85cSEd Tanous         // is not 100% number
4101abe55efSEd Tanous         if (*endPtr != '\0')
4111abe55efSEd Tanous         {
412179db1d7SKowalski, Kamil             return false;
413179db1d7SKowalski, Kamil         }
414179db1d7SKowalski, Kamil 
415179db1d7SKowalski, Kamil         // Value should be contained in byte
4161abe55efSEd Tanous         if (value < 0 || value > 255)
4171abe55efSEd Tanous         {
418179db1d7SKowalski, Kamil             return false;
419179db1d7SKowalski, Kamil         }
420179db1d7SKowalski, Kamil 
4211abe55efSEd Tanous         if (bits != nullptr)
4221abe55efSEd Tanous         {
423179db1d7SKowalski, Kamil             // Mask has to be continuous between bytes
4241abe55efSEd Tanous             if (previousValue != 255 && value != 0)
4251abe55efSEd Tanous             {
426179db1d7SKowalski, Kamil                 return false;
427179db1d7SKowalski, Kamil             }
428179db1d7SKowalski, Kamil 
429179db1d7SKowalski, Kamil             // Mask has to be continuous inside bytes
430179db1d7SKowalski, Kamil             firstZeroInByteHit = false;
431179db1d7SKowalski, Kamil 
432179db1d7SKowalski, Kamil             // Count bits
4331abe55efSEd Tanous             for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
4341abe55efSEd Tanous             {
4351abe55efSEd Tanous                 if (value & (1 << bitIdx))
4361abe55efSEd Tanous                 {
4371abe55efSEd Tanous                     if (firstZeroInByteHit)
4381abe55efSEd Tanous                     {
439179db1d7SKowalski, Kamil                         // Continuity not preserved
440179db1d7SKowalski, Kamil                         return false;
4411abe55efSEd Tanous                     }
4421abe55efSEd Tanous                     else
4431abe55efSEd Tanous                     {
444179db1d7SKowalski, Kamil                         (*bits)++;
445179db1d7SKowalski, Kamil                     }
4461abe55efSEd Tanous                 }
4471abe55efSEd Tanous                 else
4481abe55efSEd Tanous                 {
449179db1d7SKowalski, Kamil                     firstZeroInByteHit = true;
450179db1d7SKowalski, Kamil                 }
451179db1d7SKowalski, Kamil             }
452179db1d7SKowalski, Kamil         }
453179db1d7SKowalski, Kamil 
454179db1d7SKowalski, Kamil         previousValue = value;
455179db1d7SKowalski, Kamil     }
456179db1d7SKowalski, Kamil 
457179db1d7SKowalski, Kamil     return true;
458179db1d7SKowalski, Kamil }
459179db1d7SKowalski, Kamil 
460179db1d7SKowalski, Kamil /**
461179db1d7SKowalski, Kamil  * @brief Changes IPv4 address type property (Address, Gateway)
462179db1d7SKowalski, Kamil  *
463179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be modified
4644a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be modified
465179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of modified IP
466179db1d7SKowalski, Kamil  * @param[in] name        Name of field in JSON representation
467179db1d7SKowalski, Kamil  * @param[in] newValue    New value that should be written
468179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
469179db1d7SKowalski, Kamil  *
470179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
471179db1d7SKowalski, Kamil  * otherwise
472179db1d7SKowalski, Kamil  */
4734a0cb85cSEd Tanous inline void changeIPv4AddressProperty(
4744a0cb85cSEd Tanous     const std::string &ifaceId, int ipIdx, const std::string &ipHash,
4754a0cb85cSEd Tanous     const std::string &name, const std::string &newValue,
4764a0cb85cSEd Tanous     const std::shared_ptr<AsyncResp> asyncResp)
4771abe55efSEd Tanous {
4784a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, name{std::string(name)},
4794a0cb85cSEd Tanous                      newValue{std::move(newValue)}](
4801abe55efSEd Tanous                         const boost::system::error_code ec) {
4811abe55efSEd Tanous         if (ec)
4821abe55efSEd Tanous         {
483*f12894f8SJason M. Bills             messages::internalError(asyncResp->res, "/IPv4Addresses/" +
484*f12894f8SJason M. Bills                                                         std::to_string(ipIdx) +
485*f12894f8SJason M. Bills                                                         "/" + name);
4861abe55efSEd Tanous         }
4871abe55efSEd Tanous         else
4881abe55efSEd Tanous         {
4894a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
490179db1d7SKowalski, Kamil         }
491179db1d7SKowalski, Kamil     };
492179db1d7SKowalski, Kamil 
49355c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
494179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
495179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
496179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
497179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", name,
498179db1d7SKowalski, Kamil         sdbusplus::message::variant<std::string>(newValue));
4994a0cb85cSEd Tanous }
500179db1d7SKowalski, Kamil 
501179db1d7SKowalski, Kamil /**
502179db1d7SKowalski, Kamil  * @brief Changes IPv4 address origin property
503179db1d7SKowalski, Kamil  *
504179db1d7SKowalski, Kamil  * @param[in] ifaceId       Id of interface whose IP should be modified
5054a0cb85cSEd Tanous  * @param[in] ipIdx         Index of IP in input array that should be
5061abe55efSEd Tanous  * modified
507179db1d7SKowalski, Kamil  * @param[in] ipHash        DBus Hash id of modified IP
508179db1d7SKowalski, Kamil  * @param[in] newValue      New value in Redfish format
509179db1d7SKowalski, Kamil  * @param[in] newValueDbus  New value in D-Bus format
510179db1d7SKowalski, Kamil  * @param[io] asyncResp     Response object that will be returned to client
511179db1d7SKowalski, Kamil  *
512179db1d7SKowalski, Kamil  * @return true if give IP is valid and has been sent do D-Bus, false
513179db1d7SKowalski, Kamil  * otherwise
514179db1d7SKowalski, Kamil  */
5154a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
5161abe55efSEd Tanous                              const std::string &ipHash,
5171abe55efSEd Tanous                              const std::string &newValue,
518179db1d7SKowalski, Kamil                              const std::string &newValueDbus,
5194a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
5201abe55efSEd Tanous {
5214a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}](
5221abe55efSEd Tanous                         const boost::system::error_code ec) {
5231abe55efSEd Tanous         if (ec)
5241abe55efSEd Tanous         {
525*f12894f8SJason M. Bills             messages::internalError(asyncResp->res, "/IPv4Addresses/" +
526*f12894f8SJason M. Bills                                                         std::to_string(ipIdx) +
527*f12894f8SJason M. Bills                                                         "/AddressOrigin");
5281abe55efSEd Tanous         }
5291abe55efSEd Tanous         else
5301abe55efSEd Tanous         {
5314a0cb85cSEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
532179db1d7SKowalski, Kamil                 newValue;
533179db1d7SKowalski, Kamil         }
534179db1d7SKowalski, Kamil     };
535179db1d7SKowalski, Kamil 
53655c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
537179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
538179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
539179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
540179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "Origin",
541179db1d7SKowalski, Kamil         sdbusplus::message::variant<std::string>(newValueDbus));
5424a0cb85cSEd Tanous }
543179db1d7SKowalski, Kamil 
544179db1d7SKowalski, Kamil /**
545179db1d7SKowalski, Kamil  * @brief Modifies SubnetMask for given IP
546179db1d7SKowalski, Kamil  *
547179db1d7SKowalski, Kamil  * @param[in] ifaceId      Id of interface whose IP should be modified
5484a0cb85cSEd Tanous  * @param[in] ipIdx        Index of IP in input array that should be
5491abe55efSEd Tanous  * modified
550179db1d7SKowalski, Kamil  * @param[in] ipHash       DBus Hash id of modified IP
551179db1d7SKowalski, Kamil  * @param[in] newValueStr  Mask in dot notation as string
552179db1d7SKowalski, Kamil  * @param[in] newValue     Mask as PrefixLength in bitcount
553179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
554179db1d7SKowalski, Kamil  *
555179db1d7SKowalski, Kamil  * @return None
556179db1d7SKowalski, Kamil  */
5574a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx,
5584a0cb85cSEd Tanous                                          const std::string &ipHash,
5594a0cb85cSEd Tanous                                          const std::string &newValueStr,
5604a0cb85cSEd Tanous                                          uint8_t &newValue,
5614a0cb85cSEd Tanous                                          std::shared_ptr<AsyncResp> asyncResp)
5621abe55efSEd Tanous {
5634a0cb85cSEd Tanous     auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}](
5641abe55efSEd Tanous                         const boost::system::error_code ec) {
5651abe55efSEd Tanous         if (ec)
5661abe55efSEd Tanous         {
567*f12894f8SJason M. Bills             messages::internalError(asyncResp->res, "/IPv4Addresses/" +
568*f12894f8SJason M. Bills                                                         std::to_string(ipIdx) +
569*f12894f8SJason M. Bills                                                         "/SubnetMask");
5701abe55efSEd Tanous         }
5711abe55efSEd Tanous         else
5721abe55efSEd Tanous         {
57355c7b7a2SEd Tanous             asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
574179db1d7SKowalski, Kamil                 newValueStr;
575179db1d7SKowalski, Kamil         }
576179db1d7SKowalski, Kamil     };
577179db1d7SKowalski, Kamil 
57855c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
579179db1d7SKowalski, Kamil         std::move(callback), "xyz.openbmc_project.Network",
580179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
581179db1d7SKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
582179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP", "PrefixLength",
583179db1d7SKowalski, Kamil         sdbusplus::message::variant<uint8_t>(newValue));
5844a0cb85cSEd Tanous }
585588c3f0dSKowalski, Kamil 
586588c3f0dSKowalski, Kamil /**
587588c3f0dSKowalski, Kamil  * @brief Sets given HostName of the machine through D-Bus
588588c3f0dSKowalski, Kamil  *
589588c3f0dSKowalski, Kamil  * @param[in] newHostname   New name that HostName will be changed to
590588c3f0dSKowalski, Kamil  * @param[in] callback      Function that will be called after the operation
591588c3f0dSKowalski, Kamil  *
592588c3f0dSKowalski, Kamil  * @return None.
593588c3f0dSKowalski, Kamil  */
594588c3f0dSKowalski, Kamil template <typename CallbackFunc>
5951abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback)
5961abe55efSEd Tanous {
59755c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
598588c3f0dSKowalski, Kamil         callback, "xyz.openbmc_project.Network",
599588c3f0dSKowalski, Kamil         "/xyz/openbmc_project/network/config",
600588c3f0dSKowalski, Kamil         "org.freedesktop.DBus.Properties", "Set",
601588c3f0dSKowalski, Kamil         "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
602588c3f0dSKowalski, Kamil         sdbusplus::message::variant<std::string>(newHostname));
6034a0cb85cSEd Tanous }
604588c3f0dSKowalski, Kamil 
605588c3f0dSKowalski, Kamil /**
606179db1d7SKowalski, Kamil  * @brief Deletes given IPv4
607179db1d7SKowalski, Kamil  *
608179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6094a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
610179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
611179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
612179db1d7SKowalski, Kamil  *
613179db1d7SKowalski, Kamil  * @return None
614179db1d7SKowalski, Kamil  */
6154a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
616179db1d7SKowalski, Kamil                        unsigned int ipIdx,
6174a0cb85cSEd Tanous                        const std::shared_ptr<AsyncResp> asyncResp)
6181abe55efSEd Tanous {
61955c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6204a0cb85cSEd Tanous         [ipIdx, asyncResp](const boost::system::error_code ec) {
6211abe55efSEd Tanous             if (ec)
6221abe55efSEd Tanous             {
623*f12894f8SJason M. Bills                 messages::internalError(asyncResp->res,
624*f12894f8SJason M. Bills                                         "/IPv4Addresses/" +
625*f12894f8SJason M. Bills                                             std::to_string(ipIdx) + "/");
6261abe55efSEd Tanous             }
6271abe55efSEd Tanous             else
6281abe55efSEd Tanous             {
62955c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
630179db1d7SKowalski, Kamil             }
631179db1d7SKowalski, Kamil         },
632179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network",
633179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
634179db1d7SKowalski, Kamil         "xyz.openbmc_project.Object.Delete", "Delete");
635179db1d7SKowalski, Kamil }
636179db1d7SKowalski, Kamil 
637179db1d7SKowalski, Kamil /**
638179db1d7SKowalski, Kamil  * @brief Creates IPv4 with given data
639179db1d7SKowalski, Kamil  *
640179db1d7SKowalski, Kamil  * @param[in] ifaceId     Id of interface whose IP should be deleted
6414a0cb85cSEd Tanous  * @param[in] ipIdx       Index of IP in input array that should be deleted
642179db1d7SKowalski, Kamil  * @param[in] ipHash      DBus Hash id of IP that should be deleted
643179db1d7SKowalski, Kamil  * @param[io] asyncResp   Response object that will be returned to client
644179db1d7SKowalski, Kamil  *
645179db1d7SKowalski, Kamil  * @return None
646179db1d7SKowalski, Kamil  */
6474a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
648179db1d7SKowalski, Kamil                        uint8_t subnetMask, const std::string &gateway,
649179db1d7SKowalski, Kamil                        const std::string &address,
6504a0cb85cSEd Tanous                        std::shared_ptr<AsyncResp> asyncResp)
6511abe55efSEd Tanous {
6524a0cb85cSEd Tanous     auto createIpHandler = [ipIdx,
6534a0cb85cSEd Tanous                             asyncResp](const boost::system::error_code ec) {
6541abe55efSEd Tanous         if (ec)
6551abe55efSEd Tanous         {
656*f12894f8SJason M. Bills             messages::internalError(asyncResp->res, "/IPv4Addresses/" +
657*f12894f8SJason M. Bills                                                         std::to_string(ipIdx) +
658*f12894f8SJason M. Bills                                                         "/");
659179db1d7SKowalski, Kamil         }
660179db1d7SKowalski, Kamil     };
661179db1d7SKowalski, Kamil 
66255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
663179db1d7SKowalski, Kamil         std::move(createIpHandler), "xyz.openbmc_project.Network",
664179db1d7SKowalski, Kamil         "/xyz/openbmc_project/network/" + ifaceId,
665179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Create", "IP",
666179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
667179db1d7SKowalski, Kamil         gateway);
668179db1d7SKowalski, Kamil }
669179db1d7SKowalski, Kamil 
670179db1d7SKowalski, Kamil /**
671179db1d7SKowalski, Kamil  * Function that retrieves all properties for given Ethernet Interface
672179db1d7SKowalski, Kamil  * Object
673179db1d7SKowalski, Kamil  * from EntityManager Network Manager
6744a0cb85cSEd Tanous  * @param ethiface_id a eth interface id to query on DBus
675179db1d7SKowalski, Kamil  * @param callback a function that shall be called to convert Dbus output
676179db1d7SKowalski, Kamil  * into JSON
677179db1d7SKowalski, Kamil  */
678179db1d7SKowalski, Kamil template <typename CallbackFunc>
6794a0cb85cSEd Tanous void getEthernetIfaceData(const std::string &ethiface_id,
6801abe55efSEd Tanous                           CallbackFunc &&callback)
6811abe55efSEd Tanous {
68255c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
6834a0cb85cSEd Tanous         [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}](
6841abe55efSEd Tanous             const boost::system::error_code error_code,
6854a0cb85cSEd Tanous             const GetManagedObjects &resp) {
68655c7b7a2SEd Tanous             EthernetInterfaceData ethData{};
6874a0cb85cSEd Tanous             boost::container::flat_set<IPv4AddressData> ipv4Data;
688179db1d7SKowalski, Kamil 
6891abe55efSEd Tanous             if (error_code)
6901abe55efSEd Tanous             {
69155c7b7a2SEd Tanous                 callback(false, ethData, ipv4Data);
692179db1d7SKowalski, Kamil                 return;
693179db1d7SKowalski, Kamil             }
694179db1d7SKowalski, Kamil 
6954a0cb85cSEd Tanous             extractEthernetInterfaceData(ethiface_id, resp, ethData);
6964a0cb85cSEd Tanous             extractIPData(ethiface_id, resp, ipv4Data);
697179db1d7SKowalski, Kamil 
698179db1d7SKowalski, Kamil             // Fix global GW
6991abe55efSEd Tanous             for (IPv4AddressData &ipv4 : ipv4Data)
7001abe55efSEd Tanous             {
7014a0cb85cSEd Tanous                 if ((ipv4.linktype == LinkType::Global) &&
7024a0cb85cSEd Tanous                     (ipv4.gateway == "0.0.0.0"))
7031abe55efSEd Tanous                 {
7044a0cb85cSEd Tanous                     ipv4.gateway = ethData.default_gateway;
705179db1d7SKowalski, Kamil                 }
706179db1d7SKowalski, Kamil             }
707179db1d7SKowalski, Kamil 
7084a0cb85cSEd Tanous             // Finally make a callback with usefull data
70955c7b7a2SEd Tanous             callback(true, ethData, ipv4Data);
710179db1d7SKowalski, Kamil         },
711179db1d7SKowalski, Kamil         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
712179db1d7SKowalski, Kamil         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
713179db1d7SKowalski, Kamil };
714179db1d7SKowalski, Kamil 
715179db1d7SKowalski, Kamil /**
7169391bb9cSRapkiewicz, Pawel  * Function that retrieves all Ethernet Interfaces available through Network
7179391bb9cSRapkiewicz, Pawel  * Manager
7181abe55efSEd Tanous  * @param callback a function that shall be called to convert Dbus output
7191abe55efSEd Tanous  * into JSON.
7209391bb9cSRapkiewicz, Pawel  */
7219391bb9cSRapkiewicz, Pawel template <typename CallbackFunc>
7221abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback)
7231abe55efSEd Tanous {
72455c7b7a2SEd Tanous     crow::connections::systemBus->async_method_call(
7254a0cb85cSEd Tanous         [callback{std::move(callback)}](
7269391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
7274a0cb85cSEd Tanous             GetManagedObjects &resp) {
7281abe55efSEd Tanous             // Callback requires vector<string> to retrieve all available
7291abe55efSEd Tanous             // ethernet interfaces
7304a0cb85cSEd Tanous             std::vector<std::string> iface_list;
7314a0cb85cSEd Tanous             iface_list.reserve(resp.size());
7321abe55efSEd Tanous             if (error_code)
7331abe55efSEd Tanous             {
7344a0cb85cSEd Tanous                 callback(false, iface_list);
7359391bb9cSRapkiewicz, Pawel                 return;
7369391bb9cSRapkiewicz, Pawel             }
7379391bb9cSRapkiewicz, Pawel 
7389391bb9cSRapkiewicz, Pawel             // Iterate over all retrieved ObjectPaths.
7394a0cb85cSEd Tanous             for (const auto &objpath : resp)
7401abe55efSEd Tanous             {
7419391bb9cSRapkiewicz, Pawel                 // And all interfaces available for certain ObjectPath.
7424a0cb85cSEd Tanous                 for (const auto &interface : objpath.second)
7431abe55efSEd Tanous                 {
7441abe55efSEd Tanous                     // If interface is
7454a0cb85cSEd Tanous                     // xyz.openbmc_project.Network.EthernetInterface, this is
7464a0cb85cSEd Tanous                     // what we're looking for.
7479391bb9cSRapkiewicz, Pawel                     if (interface.first ==
7481abe55efSEd Tanous                         "xyz.openbmc_project.Network.EthernetInterface")
7491abe55efSEd Tanous                     {
7504a0cb85cSEd Tanous                         // Cut out everyting until last "/", ...
7514a0cb85cSEd Tanous                         const std::string &iface_id = objpath.first.str;
7524a0cb85cSEd Tanous                         std::size_t last_pos = iface_id.rfind("/");
7534a0cb85cSEd Tanous                         if (last_pos != std::string::npos)
7541abe55efSEd Tanous                         {
7559391bb9cSRapkiewicz, Pawel                             // and put it into output vector.
7564a0cb85cSEd Tanous                             iface_list.emplace_back(
7574a0cb85cSEd Tanous                                 iface_id.substr(last_pos + 1));
7589391bb9cSRapkiewicz, Pawel                         }
7599391bb9cSRapkiewicz, Pawel                     }
7609391bb9cSRapkiewicz, Pawel                 }
7619391bb9cSRapkiewicz, Pawel             }
762a434f2bdSEd Tanous             // Finally make a callback with useful data
7634a0cb85cSEd Tanous             callback(true, iface_list);
7649391bb9cSRapkiewicz, Pawel         },
765aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
766aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
7679391bb9cSRapkiewicz, Pawel };
7689391bb9cSRapkiewicz, Pawel 
7699391bb9cSRapkiewicz, Pawel /**
7709391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
7719391bb9cSRapkiewicz, Pawel  */
7721abe55efSEd Tanous class EthernetCollection : public Node
7731abe55efSEd Tanous {
7749391bb9cSRapkiewicz, Pawel   public:
7754a0cb85cSEd Tanous     template <typename CrowApp>
7761abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
7774a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/")
7781abe55efSEd Tanous     {
7799391bb9cSRapkiewicz, Pawel         Node::json["@odata.type"] =
7809391bb9cSRapkiewicz, Pawel             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
7819391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
7829391bb9cSRapkiewicz, Pawel             "/redfish/v1/"
7839391bb9cSRapkiewicz, Pawel             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
7844a0cb85cSEd Tanous         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces";
7859391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Ethernet Network Interface Collection";
7869391bb9cSRapkiewicz, Pawel         Node::json["Description"] =
7879391bb9cSRapkiewicz, Pawel             "Collection of EthernetInterfaces for this Manager";
7889391bb9cSRapkiewicz, Pawel 
789588c3f0dSKowalski, Kamil         entityPrivileges = {
790588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
791e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
792e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
793e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
794e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
795e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
7969391bb9cSRapkiewicz, Pawel     }
7979391bb9cSRapkiewicz, Pawel 
7989391bb9cSRapkiewicz, Pawel   private:
7999391bb9cSRapkiewicz, Pawel     /**
8009391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8019391bb9cSRapkiewicz, Pawel      */
80255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
8031abe55efSEd Tanous                const std::vector<std::string> &params) override
8041abe55efSEd Tanous     {
8054a0cb85cSEd Tanous         res.jsonValue = Node::json;
8064a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
8071abe55efSEd Tanous         // preparation
808*f12894f8SJason M. Bills         getEthernetIfaceList(
809*f12894f8SJason M. Bills             [&res](const bool &success,
8101abe55efSEd Tanous                    const std::vector<std::string> &iface_list) {
8114a0cb85cSEd Tanous                 if (!success)
8121abe55efSEd Tanous                 {
813*f12894f8SJason M. Bills                     messages::internalError(res);
8144a0cb85cSEd Tanous                     res.end();
8154a0cb85cSEd Tanous                     return;
8164a0cb85cSEd Tanous                 }
8174a0cb85cSEd Tanous 
8184a0cb85cSEd Tanous                 nlohmann::json &iface_array = res.jsonValue["Members"];
8194a0cb85cSEd Tanous                 iface_array = nlohmann::json::array();
8204a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
8211abe55efSEd Tanous                 {
8224a0cb85cSEd Tanous                     iface_array.push_back(
8234a0cb85cSEd Tanous                         {{"@odata.id",
8244a0cb85cSEd Tanous                           "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
8254a0cb85cSEd Tanous                               iface_item}});
8269391bb9cSRapkiewicz, Pawel                 }
8274a0cb85cSEd Tanous 
8284a0cb85cSEd Tanous                 res.jsonValue["Members@odata.count"] = iface_array.size();
8294a0cb85cSEd Tanous                 res.jsonValue["@odata.id"] =
8304a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces";
8319391bb9cSRapkiewicz, Pawel                 res.end();
8329391bb9cSRapkiewicz, Pawel             });
8339391bb9cSRapkiewicz, Pawel     }
8349391bb9cSRapkiewicz, Pawel };
8359391bb9cSRapkiewicz, Pawel 
8369391bb9cSRapkiewicz, Pawel /**
8379391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
8389391bb9cSRapkiewicz, Pawel  */
8391abe55efSEd Tanous class EthernetInterface : public Node
8401abe55efSEd Tanous {
8419391bb9cSRapkiewicz, Pawel   public:
8429391bb9cSRapkiewicz, Pawel     /*
8439391bb9cSRapkiewicz, Pawel      * Default Constructor
8449391bb9cSRapkiewicz, Pawel      */
8454a0cb85cSEd Tanous     template <typename CrowApp>
8461abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
8474a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/",
8481abe55efSEd Tanous              std::string())
8491abe55efSEd Tanous     {
8501abe55efSEd Tanous         Node::json["@odata.type"] =
8511abe55efSEd Tanous             "#EthernetInterface.v1_2_0.EthernetInterface";
8529391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
8539391bb9cSRapkiewicz, Pawel             "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
8549391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Manager Ethernet Interface";
8559391bb9cSRapkiewicz, Pawel         Node::json["Description"] = "Management Network Interface";
8569391bb9cSRapkiewicz, Pawel 
857588c3f0dSKowalski, Kamil         entityPrivileges = {
858588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
859e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
860e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
861e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
862e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
863e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8649391bb9cSRapkiewicz, Pawel     }
8659391bb9cSRapkiewicz, Pawel 
866e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
867e439f0f8SKowalski, Kamil     static void handleVlanPatch(const std::string &ifaceId,
868e439f0f8SKowalski, Kamil                                 const nlohmann::json &input,
8694a0cb85cSEd Tanous                                 const EthernetInterfaceData &ethData,
8704a0cb85cSEd Tanous                                 const std::shared_ptr<AsyncResp> asyncResp)
8711abe55efSEd Tanous     {
8721abe55efSEd Tanous         if (!input.is_object())
8731abe55efSEd Tanous         {
874*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, input.dump(),
875*f12894f8SJason M. Bills                                              "VLAN", "/");
876588c3f0dSKowalski, Kamil             return;
877588c3f0dSKowalski, Kamil         }
878588c3f0dSKowalski, Kamil 
8794a0cb85cSEd Tanous         nlohmann::json::const_iterator vlanEnable = input.find("VLANEnable");
8804a0cb85cSEd Tanous         if (vlanEnable == input.end())
8811abe55efSEd Tanous         {
882*f12894f8SJason M. Bills             messages::propertyMissing(asyncResp->res, "VLANEnable",
8834a0cb85cSEd Tanous                                       "/VLANEnable");
8844a0cb85cSEd Tanous             return;
8854a0cb85cSEd Tanous         }
8864a0cb85cSEd Tanous         const bool *vlanEnableBool = vlanEnable->get_ptr<const bool *>();
8874a0cb85cSEd Tanous         if (vlanEnableBool == nullptr)
8884a0cb85cSEd Tanous         {
889*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, vlanEnable->dump(),
890*f12894f8SJason M. Bills                                              "VLANEnable", "/VLANEnable");
891588c3f0dSKowalski, Kamil             return;
892588c3f0dSKowalski, Kamil         }
893588c3f0dSKowalski, Kamil 
8944a0cb85cSEd Tanous         nlohmann::json::const_iterator vlanId = input.find("VLANId");
8954a0cb85cSEd Tanous         if (vlanId == input.end())
8964a0cb85cSEd Tanous         {
897*f12894f8SJason M. Bills             messages::propertyMissing(asyncResp->res, "VLANId", "/VLANId");
8984a0cb85cSEd Tanous             return;
8994a0cb85cSEd Tanous         }
9004a0cb85cSEd Tanous         const uint64_t *vlanIdUint = vlanId->get_ptr<const uint64_t *>();
9014a0cb85cSEd Tanous         if (vlanIdUint == nullptr)
9024a0cb85cSEd Tanous         {
903*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, vlanId->dump(),
904*f12894f8SJason M. Bills                                              "VLANId", "/VLANId");
9054a0cb85cSEd Tanous             return;
9064a0cb85cSEd Tanous         }
9074a0cb85cSEd Tanous 
9084a0cb85cSEd Tanous         if (!ethData.vlan_id)
9091abe55efSEd Tanous         {
910e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
911e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
912*f12894f8SJason M. Bills             messages::propertyNotWritable(asyncResp->res, "VLANEnable",
913*f12894f8SJason M. Bills                                           "/VLANEnable");
914588c3f0dSKowalski, Kamil 
915588c3f0dSKowalski, Kamil             return;
916588c3f0dSKowalski, Kamil         }
917588c3f0dSKowalski, Kamil 
918588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
9194a0cb85cSEd Tanous         if (*vlanEnableBool == true)
9201abe55efSEd Tanous         {
921588c3f0dSKowalski, Kamil             // Change VLAN Id
9224a0cb85cSEd Tanous             asyncResp->res.jsonValue["VLANId"] = *vlanIdUint;
9234a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9241abe55efSEd Tanous                 if (ec)
9251abe55efSEd Tanous                 {
926*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
9271abe55efSEd Tanous                 }
9281abe55efSEd Tanous                 else
9291abe55efSEd Tanous                 {
9304a0cb85cSEd Tanous                     asyncResp->res.jsonValue["VLANEnable"] = true;
931e439f0f8SKowalski, Kamil                 }
9324a0cb85cSEd Tanous             };
9334a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
9344a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
9354a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
9364a0cb85cSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
9374a0cb85cSEd Tanous                 "xyz.openbmc_project.Network.VLAN", "Id",
9384a0cb85cSEd Tanous                 sdbusplus::message::variant<uint32_t>(*vlanIdUint));
9391abe55efSEd Tanous         }
9404a0cb85cSEd Tanous         else
9411abe55efSEd Tanous         {
9424a0cb85cSEd Tanous             auto callback = [asyncResp](const boost::system::error_code ec) {
9431abe55efSEd Tanous                 if (ec)
9441abe55efSEd Tanous                 {
945*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
9464a0cb85cSEd Tanous                     return;
9471abe55efSEd Tanous                 }
9484a0cb85cSEd Tanous                 asyncResp->res.jsonValue["VLANEnable"] = false;
9494a0cb85cSEd Tanous             };
9504a0cb85cSEd Tanous 
9514a0cb85cSEd Tanous             crow::connections::systemBus->async_method_call(
9524a0cb85cSEd Tanous                 std::move(callback), "xyz.openbmc_project.Network",
9534a0cb85cSEd Tanous                 "/xyz/openbmc_project/network/" + ifaceId,
9544a0cb85cSEd Tanous                 "xyz.openbmc_project.Object.Delete", "Delete");
955588c3f0dSKowalski, Kamil         }
956588c3f0dSKowalski, Kamil     }
957588c3f0dSKowalski, Kamil 
958e439f0f8SKowalski, Kamil   private:
959588c3f0dSKowalski, Kamil     void handleHostnamePatch(const nlohmann::json &input,
9604a0cb85cSEd Tanous                              const std::shared_ptr<AsyncResp> asyncResp)
9611abe55efSEd Tanous     {
9624a0cb85cSEd Tanous         const std::string *newHostname = input.get_ptr<const std::string *>();
9634a0cb85cSEd Tanous         if (newHostname == nullptr)
9641abe55efSEd Tanous         {
965*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, input.dump(),
966*f12894f8SJason M. Bills                                              "HostName", "/HostName");
9674a0cb85cSEd Tanous             return;
9684a0cb85cSEd Tanous         }
9694a0cb85cSEd Tanous 
9704a0cb85cSEd Tanous         // Change hostname
9714a0cb85cSEd Tanous         setHostName(
9724a0cb85cSEd Tanous             *newHostname, [asyncResp, newHostname{std::string(*newHostname)}](
9734a0cb85cSEd Tanous                               const boost::system::error_code ec) {
9744a0cb85cSEd Tanous                 if (ec)
9754a0cb85cSEd Tanous                 {
976*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res, "/HostName");
9771abe55efSEd Tanous                 }
9781abe55efSEd Tanous                 else
9791abe55efSEd Tanous                 {
98055c7b7a2SEd Tanous                     asyncResp->res.jsonValue["HostName"] = newHostname;
981588c3f0dSKowalski, Kamil                 }
982588c3f0dSKowalski, Kamil             });
983588c3f0dSKowalski, Kamil     }
984588c3f0dSKowalski, Kamil 
9854a0cb85cSEd Tanous     void handleIPv4Patch(
9864a0cb85cSEd Tanous         const std::string &ifaceId, const nlohmann::json &input,
9874a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data,
9884a0cb85cSEd Tanous         const std::shared_ptr<AsyncResp> asyncResp)
9891abe55efSEd Tanous     {
9901abe55efSEd Tanous         if (!input.is_array())
9911abe55efSEd Tanous         {
992*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, input.dump(),
993*f12894f8SJason M. Bills                                              "IPv4Addresses", "/IPv4Addresses");
994179db1d7SKowalski, Kamil             return;
995179db1d7SKowalski, Kamil         }
996179db1d7SKowalski, Kamil 
997179db1d7SKowalski, Kamil         // According to Redfish PATCH definition, size must be at least equal
9984a0cb85cSEd Tanous         if (input.size() < ipv4Data.size())
9991abe55efSEd Tanous         {
10001abe55efSEd Tanous             // TODO(kkowalsk) This should be a message indicating that not
10011abe55efSEd Tanous             // enough data has been provided
1002*f12894f8SJason M. Bills             messages::internalError(asyncResp->res, "/IPv4Addresses");
1003179db1d7SKowalski, Kamil             return;
1004179db1d7SKowalski, Kamil         }
1005179db1d7SKowalski, Kamil 
10064a0cb85cSEd Tanous         int entryIdx = 0;
10074a0cb85cSEd Tanous         boost::container::flat_set<IPv4AddressData>::const_iterator thisData =
10084a0cb85cSEd Tanous             ipv4Data.begin();
10094a0cb85cSEd Tanous         for (const nlohmann::json &thisJson : input)
10101abe55efSEd Tanous         {
10114a0cb85cSEd Tanous             std::string pathString =
10124a0cb85cSEd Tanous                 "/IPv4Addresses/" + std::to_string(entryIdx);
1013179db1d7SKowalski, Kamil             // Check that entry is not of some unexpected type
10144a0cb85cSEd Tanous             if (!thisJson.is_object() && !thisJson.is_null())
10151abe55efSEd Tanous             {
10164a0cb85cSEd Tanous                 messages::propertyValueTypeError(
1017*f12894f8SJason M. Bills                     asyncResp->res, thisJson.dump(), "IPv4Address", pathString);
1018179db1d7SKowalski, Kamil 
1019179db1d7SKowalski, Kamil                 continue;
1020179db1d7SKowalski, Kamil             }
1021179db1d7SKowalski, Kamil 
10224a0cb85cSEd Tanous             nlohmann::json::const_iterator addressFieldIt =
10234a0cb85cSEd Tanous                 thisJson.find("Address");
10244a0cb85cSEd Tanous             const std::string *addressField = nullptr;
10254a0cb85cSEd Tanous             if (addressFieldIt != thisJson.end())
10261abe55efSEd Tanous             {
10274a0cb85cSEd Tanous                 addressField = addressFieldIt->get_ptr<const std::string *>();
10284a0cb85cSEd Tanous                 if (addressField == nullptr)
10291abe55efSEd Tanous                 {
10304a0cb85cSEd Tanous                     messages::propertyValueFormatError(
1031*f12894f8SJason M. Bills                         asyncResp->res, addressFieldIt->dump(), "Address",
10324a0cb85cSEd Tanous                         pathString + "/Address");
1033179db1d7SKowalski, Kamil                     continue;
1034179db1d7SKowalski, Kamil                 }
10351abe55efSEd Tanous                 else
10361abe55efSEd Tanous                 {
10374a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*addressField))
10384a0cb85cSEd Tanous                     {
1039*f12894f8SJason M. Bills                         messages::propertyValueFormatError(
1040*f12894f8SJason M. Bills                             asyncResp->res, *addressField, "Address",
10414a0cb85cSEd Tanous                             pathString + "/Address");
10424a0cb85cSEd Tanous                         continue;
10434a0cb85cSEd Tanous                     }
10444a0cb85cSEd Tanous                 }
10454a0cb85cSEd Tanous             }
10464a0cb85cSEd Tanous 
10474a0cb85cSEd Tanous             boost::optional<uint8_t> prefixLength;
10484a0cb85cSEd Tanous             const std::string *subnetField = nullptr;
10494a0cb85cSEd Tanous             nlohmann::json::const_iterator subnetFieldIt =
10504a0cb85cSEd Tanous                 thisJson.find("SubnetMask");
10514a0cb85cSEd Tanous             if (subnetFieldIt != thisJson.end())
10524a0cb85cSEd Tanous             {
10534a0cb85cSEd Tanous                 subnetField = subnetFieldIt->get_ptr<const std::string *>();
10544a0cb85cSEd Tanous                 if (subnetField == nullptr)
10554a0cb85cSEd Tanous                 {
1056*f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1057*f12894f8SJason M. Bills                         asyncResp->res, *subnetField, "SubnetMask",
10584a0cb85cSEd Tanous                         pathString + "/SubnetMask");
10594a0cb85cSEd Tanous                     continue;
10604a0cb85cSEd Tanous                 }
10614a0cb85cSEd Tanous                 else
10624a0cb85cSEd Tanous                 {
10634a0cb85cSEd Tanous                     prefixLength = 0;
10644a0cb85cSEd Tanous                     if (!ipv4VerifyIpAndGetBitcount(*subnetField,
10654a0cb85cSEd Tanous                                                     &*prefixLength))
10664a0cb85cSEd Tanous                     {
1067*f12894f8SJason M. Bills                         messages::propertyValueFormatError(
1068*f12894f8SJason M. Bills                             asyncResp->res, *subnetField, "SubnetMask",
10694a0cb85cSEd Tanous                             pathString + "/SubnetMask");
10704a0cb85cSEd Tanous                         continue;
10714a0cb85cSEd Tanous                     }
10724a0cb85cSEd Tanous                 }
10734a0cb85cSEd Tanous             }
10744a0cb85cSEd Tanous 
10754a0cb85cSEd Tanous             std::string addressOriginInDBusFormat;
10764a0cb85cSEd Tanous             const std::string *addressOriginField = nullptr;
10774a0cb85cSEd Tanous             nlohmann::json::const_iterator addressOriginFieldIt =
10784a0cb85cSEd Tanous                 thisJson.find("AddressOrigin");
10794a0cb85cSEd Tanous             if (addressOriginFieldIt != thisJson.end())
10804a0cb85cSEd Tanous             {
10814a0cb85cSEd Tanous                 const std::string *addressOriginField =
10824a0cb85cSEd Tanous                     addressOriginFieldIt->get_ptr<const std::string *>();
10834a0cb85cSEd Tanous                 if (addressOriginField == nullptr)
10844a0cb85cSEd Tanous                 {
1085*f12894f8SJason M. Bills                     messages::propertyValueFormatError(
1086*f12894f8SJason M. Bills                         asyncResp->res, *addressOriginField, "AddressOrigin",
10874a0cb85cSEd Tanous                         pathString + "/AddressOrigin");
10884a0cb85cSEd Tanous                     continue;
10894a0cb85cSEd Tanous                 }
10904a0cb85cSEd Tanous                 else
10914a0cb85cSEd Tanous                 {
10924a0cb85cSEd Tanous                     // Get Address origin in proper format
10934a0cb85cSEd Tanous                     addressOriginInDBusFormat =
10944a0cb85cSEd Tanous                         translateAddressOriginRedfishToDbus(
10954a0cb85cSEd Tanous                             *addressOriginField);
10964a0cb85cSEd Tanous                     if (addressOriginInDBusFormat.empty())
10974a0cb85cSEd Tanous                     {
10984a0cb85cSEd Tanous                         messages::propertyValueNotInList(
1099*f12894f8SJason M. Bills                             asyncResp->res, *addressOriginField,
1100*f12894f8SJason M. Bills                             "AddressOrigin", pathString + "/AddressOrigin");
11014a0cb85cSEd Tanous                         continue;
11024a0cb85cSEd Tanous                     }
11034a0cb85cSEd Tanous                 }
11044a0cb85cSEd Tanous             }
11054a0cb85cSEd Tanous 
11064a0cb85cSEd Tanous             nlohmann::json::const_iterator gatewayFieldIt =
11074a0cb85cSEd Tanous                 thisJson.find("Gateway");
11084a0cb85cSEd Tanous             const std::string *gatewayField = nullptr;
11094a0cb85cSEd Tanous             if (gatewayFieldIt != thisJson.end())
11104a0cb85cSEd Tanous             {
11114a0cb85cSEd Tanous                 const std::string *gatewayField =
11124a0cb85cSEd Tanous                     gatewayFieldIt->get_ptr<const std::string *>();
11134a0cb85cSEd Tanous                 if (gatewayField == nullptr ||
11144a0cb85cSEd Tanous                     !ipv4VerifyIpAndGetBitcount(*gatewayField))
11154a0cb85cSEd Tanous                 {
1116*f12894f8SJason M. Bills                     messages::propertyValueFormatError(asyncResp->res,
1117*f12894f8SJason M. Bills                                                        *gatewayField, "Gateway",
11184a0cb85cSEd Tanous                                                        pathString + "/Gateway");
11194a0cb85cSEd Tanous                     continue;
11204a0cb85cSEd Tanous                 }
11214a0cb85cSEd Tanous             }
11224a0cb85cSEd Tanous 
11234a0cb85cSEd Tanous             // if a vlan already exists, modify the existing
11244a0cb85cSEd Tanous             if (thisData != ipv4Data.end())
11254a0cb85cSEd Tanous             {
11261abe55efSEd Tanous                 // Existing object that should be modified/deleted/remain
11271abe55efSEd Tanous                 // unchanged
11284a0cb85cSEd Tanous                 if (thisJson.is_null())
11291abe55efSEd Tanous                 {
11304a0cb85cSEd Tanous                     auto callback = [entryIdx{std::to_string(entryIdx)},
11314a0cb85cSEd Tanous                                      asyncResp](
11324a0cb85cSEd Tanous                                         const boost::system::error_code ec) {
11334a0cb85cSEd Tanous                         if (ec)
11344a0cb85cSEd Tanous                         {
1135*f12894f8SJason M. Bills                             messages::internalError(asyncResp->res,
1136*f12894f8SJason M. Bills                                                     "/IPv4Addresses/" +
1137*f12894f8SJason M. Bills                                                         entryIdx + "/");
11384a0cb85cSEd Tanous                             return;
11391abe55efSEd Tanous                         }
11404a0cb85cSEd Tanous                         asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
11414a0cb85cSEd Tanous                             nullptr;
11424a0cb85cSEd Tanous                     };
11434a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
11444a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
11454a0cb85cSEd Tanous                         "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" +
11464a0cb85cSEd Tanous                             thisData->id,
11474a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
1148179db1d7SKowalski, Kamil                 }
11494a0cb85cSEd Tanous                 else if (thisJson.is_object())
11504a0cb85cSEd Tanous                 {
1151179db1d7SKowalski, Kamil                     // Apply changes
11524a0cb85cSEd Tanous                     if (addressField != nullptr)
11531abe55efSEd Tanous                     {
11544a0cb85cSEd Tanous                         auto callback =
11554a0cb85cSEd Tanous                             [asyncResp, entryIdx,
11564a0cb85cSEd Tanous                              addressField{std::string(*addressField)}](
11574a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
11584a0cb85cSEd Tanous                                 if (ec)
11591abe55efSEd Tanous                                 {
1160*f12894f8SJason M. Bills                                     messages::internalError(
1161*f12894f8SJason M. Bills                                         asyncResp->res,
11624a0cb85cSEd Tanous                                         "/IPv4Addresses/" +
11634a0cb85cSEd Tanous                                             std::to_string(entryIdx) +
11644a0cb85cSEd Tanous                                             "/Address");
11654a0cb85cSEd Tanous                                     return;
11664a0cb85cSEd Tanous                                 }
11674a0cb85cSEd Tanous                                 asyncResp->res
11684a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
11694a0cb85cSEd Tanous                                         entryIdx)]["Address"] = addressField;
11704a0cb85cSEd Tanous                             };
11714a0cb85cSEd Tanous 
11724a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
11734a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
11744a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
11754a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
11764a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
11774a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Address",
11784a0cb85cSEd Tanous                             sdbusplus::message::variant<std::string>(
11794a0cb85cSEd Tanous                                 *addressField));
1180179db1d7SKowalski, Kamil                     }
1181179db1d7SKowalski, Kamil 
11824a0cb85cSEd Tanous                     if (prefixLength && subnetField != nullptr)
11831abe55efSEd Tanous                     {
11844a0cb85cSEd Tanous                         changeIPv4SubnetMaskProperty(ifaceId, entryIdx,
11854a0cb85cSEd Tanous                                                      thisData->id, *subnetField,
11864a0cb85cSEd Tanous                                                      *prefixLength, asyncResp);
1187179db1d7SKowalski, Kamil                     }
1188179db1d7SKowalski, Kamil 
11894a0cb85cSEd Tanous                     if (!addressOriginInDBusFormat.empty() &&
11904a0cb85cSEd Tanous                         addressOriginField != nullptr)
11911abe55efSEd Tanous                     {
11924a0cb85cSEd Tanous                         changeIPv4Origin(ifaceId, entryIdx, thisData->id,
11934a0cb85cSEd Tanous                                          *addressOriginField,
11944a0cb85cSEd Tanous                                          addressOriginInDBusFormat, asyncResp);
1195179db1d7SKowalski, Kamil                     }
1196179db1d7SKowalski, Kamil 
11974a0cb85cSEd Tanous                     if (gatewayField != nullptr)
11981abe55efSEd Tanous                     {
11994a0cb85cSEd Tanous                         auto callback =
12004a0cb85cSEd Tanous                             [asyncResp, entryIdx,
12014a0cb85cSEd Tanous                              gatewayField{std::string(*gatewayField)}](
12024a0cb85cSEd Tanous                                 const boost::system::error_code ec) {
12034a0cb85cSEd Tanous                                 if (ec)
12041abe55efSEd Tanous                                 {
1205*f12894f8SJason M. Bills                                     messages::internalError(
1206*f12894f8SJason M. Bills                                         asyncResp->res,
12074a0cb85cSEd Tanous                                         "/IPv4Addresses/" +
12084a0cb85cSEd Tanous                                             std::to_string(entryIdx) +
12094a0cb85cSEd Tanous                                             "/Gateway");
12104a0cb85cSEd Tanous                                     return;
12114a0cb85cSEd Tanous                                 }
12124a0cb85cSEd Tanous                                 asyncResp->res
12134a0cb85cSEd Tanous                                     .jsonValue["IPv4Addresses"][std::to_string(
12144a0cb85cSEd Tanous                                         entryIdx)]["Gateway"] =
12154a0cb85cSEd Tanous                                     std::move(gatewayField);
12164a0cb85cSEd Tanous                             };
12174a0cb85cSEd Tanous 
12184a0cb85cSEd Tanous                         crow::connections::systemBus->async_method_call(
12194a0cb85cSEd Tanous                             std::move(callback), "xyz.openbmc_project.Network",
12204a0cb85cSEd Tanous                             "/xyz/openbmc_project/network/" + ifaceId +
12214a0cb85cSEd Tanous                                 "/ipv4/" + thisData->id,
12224a0cb85cSEd Tanous                             "org.freedesktop.DBus.Properties", "Set",
12234a0cb85cSEd Tanous                             "xyz.openbmc_project.Network.IP", "Gateway",
12244a0cb85cSEd Tanous                             sdbusplus::message::variant<std::string>(
12254a0cb85cSEd Tanous                                 *gatewayField));
12264a0cb85cSEd Tanous                     }
12274a0cb85cSEd Tanous                 }
12284a0cb85cSEd Tanous                 thisData++;
12291abe55efSEd Tanous             }
12301abe55efSEd Tanous             else
12311abe55efSEd Tanous             {
12324a0cb85cSEd Tanous                 // Create IPv4 with provided data
12334a0cb85cSEd Tanous                 if (gatewayField == nullptr)
12341abe55efSEd Tanous                 {
1235*f12894f8SJason M. Bills                     messages::propertyMissing(asyncResp->res, "Gateway",
12364a0cb85cSEd Tanous                                               pathString + "/Gateway");
12374a0cb85cSEd Tanous                     continue;
12384a0cb85cSEd Tanous                 }
12394a0cb85cSEd Tanous 
12404a0cb85cSEd Tanous                 if (addressField == nullptr)
12411abe55efSEd Tanous                 {
1242*f12894f8SJason M. Bills                     messages::propertyMissing(asyncResp->res, "Address",
12434a0cb85cSEd Tanous                                               pathString + "/Address");
12444a0cb85cSEd Tanous                     continue;
12454a0cb85cSEd Tanous                 }
12464a0cb85cSEd Tanous 
12474a0cb85cSEd Tanous                 if (!prefixLength)
12481abe55efSEd Tanous                 {
1249*f12894f8SJason M. Bills                     messages::propertyMissing(asyncResp->res, "SubnetMask",
12504a0cb85cSEd Tanous                                               pathString + "/SubnetMask");
12514a0cb85cSEd Tanous                     continue;
1252588c3f0dSKowalski, Kamil                 }
1253588c3f0dSKowalski, Kamil 
12544a0cb85cSEd Tanous                 createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField,
12554a0cb85cSEd Tanous                            *addressField, asyncResp);
12564a0cb85cSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson;
12574a0cb85cSEd Tanous             }
12584a0cb85cSEd Tanous             entryIdx++;
12594a0cb85cSEd Tanous         }
12604a0cb85cSEd Tanous     }
12614a0cb85cSEd Tanous 
12624a0cb85cSEd Tanous     nlohmann::json parseInterfaceData(
12634a0cb85cSEd Tanous         const std::string &iface_id, const EthernetInterfaceData &ethData,
12644a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
12654a0cb85cSEd Tanous     {
12664a0cb85cSEd Tanous         // Copy JSON object to avoid race condition
12674a0cb85cSEd Tanous         nlohmann::json json_response(Node::json);
12684a0cb85cSEd Tanous 
12694a0cb85cSEd Tanous         json_response["Id"] = iface_id;
12704a0cb85cSEd Tanous         json_response["@odata.id"] =
12714a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id;
12724a0cb85cSEd Tanous 
12734a0cb85cSEd Tanous         json_response["SpeedMbps"] = ethData.speed;
12744a0cb85cSEd Tanous         json_response["MACAddress"] = ethData.mac_address;
12754a0cb85cSEd Tanous         if (!ethData.hostname.empty())
12764a0cb85cSEd Tanous         {
12774a0cb85cSEd Tanous             json_response["HostName"] = ethData.hostname;
12784a0cb85cSEd Tanous         }
12794a0cb85cSEd Tanous 
12804a0cb85cSEd Tanous         nlohmann::json &vlanObj = json_response["VLAN"];
12814a0cb85cSEd Tanous         if (ethData.vlan_id)
12824a0cb85cSEd Tanous         {
12834a0cb85cSEd Tanous             vlanObj["VLANEnable"] = true;
12844a0cb85cSEd Tanous             vlanObj["VLANId"] = *ethData.vlan_id;
12854a0cb85cSEd Tanous         }
12864a0cb85cSEd Tanous         else
12874a0cb85cSEd Tanous         {
12884a0cb85cSEd Tanous             vlanObj["VLANEnable"] = false;
12894a0cb85cSEd Tanous             vlanObj["VLANId"] = 0;
12904a0cb85cSEd Tanous         }
12914a0cb85cSEd Tanous 
12924a0cb85cSEd Tanous         if (ipv4Data.size() > 0)
12934a0cb85cSEd Tanous         {
12944a0cb85cSEd Tanous             nlohmann::json &ipv4_array = json_response["IPv4Addresses"];
12954a0cb85cSEd Tanous             ipv4_array = nlohmann::json::array();
12964a0cb85cSEd Tanous             for (auto &ipv4_config : ipv4Data)
12974a0cb85cSEd Tanous             {
12984a0cb85cSEd Tanous                 if (!ipv4_config.address.empty())
12994a0cb85cSEd Tanous                 {
13004a0cb85cSEd Tanous                     ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin},
13014a0cb85cSEd Tanous                                           {"SubnetMask", ipv4_config.netmask},
13024a0cb85cSEd Tanous                                           {"Address", ipv4_config.address}});
13034a0cb85cSEd Tanous 
13044a0cb85cSEd Tanous                     if (!ipv4_config.gateway.empty())
13054a0cb85cSEd Tanous                     {
13064a0cb85cSEd Tanous                         ipv4_array.back()["Gateway"] = ipv4_config.gateway;
13074a0cb85cSEd Tanous                     }
13084a0cb85cSEd Tanous                 }
13094a0cb85cSEd Tanous             }
13104a0cb85cSEd Tanous         }
13114a0cb85cSEd Tanous 
13124a0cb85cSEd Tanous         return json_response;
1313588c3f0dSKowalski, Kamil     }
1314588c3f0dSKowalski, Kamil 
13159391bb9cSRapkiewicz, Pawel     /**
13169391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
13179391bb9cSRapkiewicz, Pawel      */
131855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
13191abe55efSEd Tanous                const std::vector<std::string> &params) override
13201abe55efSEd Tanous     {
13214a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13221abe55efSEd Tanous         if (params.size() != 1)
13231abe55efSEd Tanous         {
1324*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
13259391bb9cSRapkiewicz, Pawel             return;
13269391bb9cSRapkiewicz, Pawel         }
13279391bb9cSRapkiewicz, Pawel 
13284a0cb85cSEd Tanous         getEthernetIfaceData(
13294a0cb85cSEd Tanous             params[0],
13304a0cb85cSEd Tanous             [this, asyncResp, iface_id{std::string(params[0])}](
13314a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13324a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13334a0cb85cSEd Tanous                 if (!success)
13341abe55efSEd Tanous                 {
13351abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13361abe55efSEd Tanous                     // object, and other errors
1337*f12894f8SJason M. Bills                     messages::resourceNotFound(asyncResp->res,
1338*f12894f8SJason M. Bills                                                "EthernetInterface", iface_id);
13394a0cb85cSEd Tanous                     return;
13409391bb9cSRapkiewicz, Pawel                 }
13414a0cb85cSEd Tanous                 asyncResp->res.jsonValue =
13424a0cb85cSEd Tanous                     parseInterfaceData(iface_id, ethData, ipv4Data);
13439391bb9cSRapkiewicz, Pawel             });
13449391bb9cSRapkiewicz, Pawel     }
13459391bb9cSRapkiewicz, Pawel 
134655c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
13471abe55efSEd Tanous                  const std::vector<std::string> &params) override
13481abe55efSEd Tanous     {
13494a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
13501abe55efSEd Tanous         if (params.size() != 1)
13511abe55efSEd Tanous         {
1352*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1353588c3f0dSKowalski, Kamil             return;
1354588c3f0dSKowalski, Kamil         }
1355588c3f0dSKowalski, Kamil 
13564a0cb85cSEd Tanous         const std::string &iface_id = params[0];
1357588c3f0dSKowalski, Kamil 
1358179db1d7SKowalski, Kamil         nlohmann::json patchReq;
13591abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
13601abe55efSEd Tanous         {
1361588c3f0dSKowalski, Kamil             return;
1362588c3f0dSKowalski, Kamil         }
1363588c3f0dSKowalski, Kamil 
13644a0cb85cSEd Tanous         // Get single eth interface data, and call the below callback for JSON
1365588c3f0dSKowalski, Kamil         // preparation
13664a0cb85cSEd Tanous         getEthernetIfaceData(
13674a0cb85cSEd Tanous             iface_id,
13684a0cb85cSEd Tanous             [this, asyncResp, iface_id, patchReq = std::move(patchReq)](
13694a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
13704a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
13711abe55efSEd Tanous                 if (!success)
13721abe55efSEd Tanous                 {
1373588c3f0dSKowalski, Kamil                     // ... otherwise return error
13741abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
13751abe55efSEd Tanous                     // object, and other errors
1376*f12894f8SJason M. Bills                     messages::resourceNotFound(
1377*f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1378588c3f0dSKowalski, Kamil                     return;
1379588c3f0dSKowalski, Kamil                 }
1380588c3f0dSKowalski, Kamil 
13814a0cb85cSEd Tanous                 asyncResp->res.jsonValue =
13824a0cb85cSEd Tanous                     parseInterfaceData(iface_id, ethData, ipv4Data);
1383588c3f0dSKowalski, Kamil 
13844a0cb85cSEd Tanous                 for (auto propertyIt : patchReq.items())
13851abe55efSEd Tanous                 {
13861abe55efSEd Tanous                     if (propertyIt.key() == "VLAN")
13871abe55efSEd Tanous                     {
13884a0cb85cSEd Tanous                         handleVlanPatch(iface_id, propertyIt.value(), ethData,
13894a0cb85cSEd Tanous                                         asyncResp);
13901abe55efSEd Tanous                     }
13911abe55efSEd Tanous                     else if (propertyIt.key() == "HostName")
13921abe55efSEd Tanous                     {
13934a0cb85cSEd Tanous                         handleHostnamePatch(propertyIt.value(), asyncResp);
13941abe55efSEd Tanous                     }
13951abe55efSEd Tanous                     else if (propertyIt.key() == "IPv4Addresses")
13961abe55efSEd Tanous                     {
13974a0cb85cSEd Tanous                         handleIPv4Patch(iface_id, propertyIt.value(), ipv4Data,
1398179db1d7SKowalski, Kamil                                         asyncResp);
13991abe55efSEd Tanous                     }
14001abe55efSEd Tanous                     else if (propertyIt.key() == "IPv6Addresses")
14011abe55efSEd Tanous                     {
1402179db1d7SKowalski, Kamil                         // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1403*f12894f8SJason M. Bills                         messages::propertyNotWritable(
1404*f12894f8SJason M. Bills                             asyncResp->res, propertyIt.key(), propertyIt.key());
14051abe55efSEd Tanous                     }
14061abe55efSEd Tanous                     else
14071abe55efSEd Tanous                     {
14081abe55efSEd Tanous                         auto fieldInJsonIt =
14094a0cb85cSEd Tanous                             asyncResp->res.jsonValue.find(propertyIt.key());
1410588c3f0dSKowalski, Kamil 
14114a0cb85cSEd Tanous                         if (fieldInJsonIt == asyncResp->res.jsonValue.end())
14121abe55efSEd Tanous                         {
1413588c3f0dSKowalski, Kamil                             // Field not in scope of defined fields
1414*f12894f8SJason M. Bills                             messages::propertyUnknown(asyncResp->res,
1415*f12894f8SJason M. Bills                                                       propertyIt.key(),
1416*f12894f8SJason M. Bills                                                       propertyIt.key());
14171abe55efSEd Tanous                         }
14184a0cb85cSEd Tanous                         else
14191abe55efSEd Tanous                         {
1420588c3f0dSKowalski, Kamil                             // User attempted to modify non-writable field
1421*f12894f8SJason M. Bills                             messages::propertyNotWritable(asyncResp->res,
1422*f12894f8SJason M. Bills                                                           propertyIt.key(),
1423*f12894f8SJason M. Bills                                                           propertyIt.key());
1424588c3f0dSKowalski, Kamil                         }
1425588c3f0dSKowalski, Kamil                     }
1426588c3f0dSKowalski, Kamil                 }
1427588c3f0dSKowalski, Kamil             });
1428588c3f0dSKowalski, Kamil     }
14299391bb9cSRapkiewicz, Pawel };
14309391bb9cSRapkiewicz, Pawel 
1431e439f0f8SKowalski, Kamil /**
14324a0cb85cSEd Tanous  * VlanNetworkInterface derived class for delivering VLANNetworkInterface
14334a0cb85cSEd Tanous  * Schema
1434e439f0f8SKowalski, Kamil  */
14351abe55efSEd Tanous class VlanNetworkInterface : public Node
14361abe55efSEd Tanous {
1437e439f0f8SKowalski, Kamil   public:
1438e439f0f8SKowalski, Kamil     /*
1439e439f0f8SKowalski, Kamil      * Default Constructor
1440e439f0f8SKowalski, Kamil      */
1441e439f0f8SKowalski, Kamil     template <typename CrowApp>
14421abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
14434a0cb85cSEd Tanous     // one manager called openbmc.  This shall be generic, but requires to
14444a0cb85cSEd Tanous     // update GetSubroutes method
14451abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
14464a0cb85cSEd Tanous         Node(app,
14474a0cb85cSEd Tanous              "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>>/VLANs/"
14484a0cb85cSEd Tanous              "<str>",
14491abe55efSEd Tanous              std::string(), std::string())
14501abe55efSEd Tanous     {
1451e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1452e439f0f8SKowalski, Kamil             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1453e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1454e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1455e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface";
1456e439f0f8SKowalski, Kamil 
1457e439f0f8SKowalski, Kamil         entityPrivileges = {
1458e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1459e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1460e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1461e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1462e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1463e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1464e439f0f8SKowalski, Kamil     }
1465e439f0f8SKowalski, Kamil 
1466e439f0f8SKowalski, Kamil   private:
14674a0cb85cSEd Tanous     nlohmann::json parseInterfaceData(
14684a0cb85cSEd Tanous         const std::string &parent_iface_id, const std::string &iface_id,
14694a0cb85cSEd Tanous         const EthernetInterfaceData &ethData,
14704a0cb85cSEd Tanous         const boost::container::flat_set<IPv4AddressData> &ipv4Data)
14711abe55efSEd Tanous     {
1472e439f0f8SKowalski, Kamil         // Copy JSON object to avoid race condition
14734a0cb85cSEd Tanous         nlohmann::json json_response(Node::json);
1474e439f0f8SKowalski, Kamil 
1475e439f0f8SKowalski, Kamil         // Fill out obvious data...
14764a0cb85cSEd Tanous         json_response["Id"] = iface_id;
14774a0cb85cSEd Tanous         json_response["@odata.id"] =
14784a0cb85cSEd Tanous             "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id +
14794a0cb85cSEd Tanous             "/VLANs/" + iface_id;
1480e439f0f8SKowalski, Kamil 
14814a0cb85cSEd Tanous         json_response["VLANEnable"] = true;
14824a0cb85cSEd Tanous         if (ethData.vlan_id)
14834a0cb85cSEd Tanous         {
14844a0cb85cSEd Tanous             json_response["VLANId"] = *ethData.vlan_id;
14854a0cb85cSEd Tanous         }
14864a0cb85cSEd Tanous         return json_response;
1487e439f0f8SKowalski, Kamil     }
1488e439f0f8SKowalski, Kamil 
148955c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
14901abe55efSEd Tanous                      const std::string &iface)
14911abe55efSEd Tanous     {
1492*f12894f8SJason M. Bills         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
14931abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
14941abe55efSEd Tanous         {
1495*f12894f8SJason M. Bills             messages::resourceNotFound(asyncResp->res, "VLAN Network Interface",
1496*f12894f8SJason M. Bills                                        iface);
1497927a505aSKowalski, Kamil             return false;
14981abe55efSEd Tanous         }
14991abe55efSEd Tanous         else
15001abe55efSEd Tanous         {
1501927a505aSKowalski, Kamil             return true;
1502927a505aSKowalski, Kamil         }
1503927a505aSKowalski, Kamil     }
1504927a505aSKowalski, Kamil 
1505e439f0f8SKowalski, Kamil     /**
1506e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1507e439f0f8SKowalski, Kamil      */
150855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
15091abe55efSEd Tanous                const std::vector<std::string> &params) override
15101abe55efSEd Tanous     {
15114a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15124a0cb85cSEd Tanous         // TODO(Pawel) this shall be parameterized call (two params) to get
1513e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1514e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1515e439f0f8SKowalski, Kamil         // impossible.
15161abe55efSEd Tanous         if (params.size() != 2)
15171abe55efSEd Tanous         {
1518*f12894f8SJason M. Bills             messages::internalError(res);
1519e439f0f8SKowalski, Kamil             res.end();
1520e439f0f8SKowalski, Kamil             return;
1521e439f0f8SKowalski, Kamil         }
1522e439f0f8SKowalski, Kamil 
15234a0cb85cSEd Tanous         const std::string &parent_iface_id = params[0];
15244a0cb85cSEd Tanous         const std::string &iface_id = params[1];
1525e439f0f8SKowalski, Kamil 
15264a0cb85cSEd Tanous         if (!verifyNames(res, parent_iface_id, iface_id))
15271abe55efSEd Tanous         {
1528a434f2bdSEd Tanous             return;
1529a434f2bdSEd Tanous         }
1530a434f2bdSEd Tanous 
1531e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1532e439f0f8SKowalski, Kamil         // preparation
15334a0cb85cSEd Tanous         getEthernetIfaceData(
15344a0cb85cSEd Tanous             iface_id,
15354a0cb85cSEd Tanous             [this, asyncResp, parent_iface_id, iface_id](
15364a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
15374a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15384a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
15391abe55efSEd Tanous                 {
15404a0cb85cSEd Tanous                     asyncResp->res.jsonValue = parseInterfaceData(
15414a0cb85cSEd Tanous                         parent_iface_id, iface_id, ethData, ipv4Data);
15421abe55efSEd Tanous                 }
15431abe55efSEd Tanous                 else
15441abe55efSEd Tanous                 {
1545e439f0f8SKowalski, Kamil                     // ... otherwise return error
15461abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15471abe55efSEd Tanous                     // object, and other errors
1548*f12894f8SJason M. Bills                     messages::resourceNotFound(
1549*f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", iface_id);
1550e439f0f8SKowalski, Kamil                 }
1551e439f0f8SKowalski, Kamil             });
1552e439f0f8SKowalski, Kamil     }
1553e439f0f8SKowalski, Kamil 
155455c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
15551abe55efSEd Tanous                  const std::vector<std::string> &params) override
15561abe55efSEd Tanous     {
15574a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
15581abe55efSEd Tanous         if (params.size() != 2)
15591abe55efSEd Tanous         {
1560*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1561e439f0f8SKowalski, Kamil             return;
1562e439f0f8SKowalski, Kamil         }
1563e439f0f8SKowalski, Kamil 
1564d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
156555c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1566927a505aSKowalski, Kamil 
15671abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
15681abe55efSEd Tanous         {
1569927a505aSKowalski, Kamil             return;
1570927a505aSKowalski, Kamil         }
1571927a505aSKowalski, Kamil 
1572927a505aSKowalski, Kamil         nlohmann::json patchReq;
15731abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
15741abe55efSEd Tanous         {
1575927a505aSKowalski, Kamil             return;
1576927a505aSKowalski, Kamil         }
1577927a505aSKowalski, Kamil 
1578927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1579927a505aSKowalski, Kamil         // preparation
15804a0cb85cSEd Tanous         getEthernetIfaceData(
15811abe55efSEd Tanous             ifaceId,
15824a0cb85cSEd Tanous             [this, asyncResp, parentIfaceId, ifaceId,
15834a0cb85cSEd Tanous              patchReq{std::move(patchReq)}](
15844a0cb85cSEd Tanous                 const bool &success, const EthernetInterfaceData &ethData,
15854a0cb85cSEd Tanous                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
15861abe55efSEd Tanous                 if (!success)
15871abe55efSEd Tanous                 {
15881abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
15891abe55efSEd Tanous                     // object, and other errors
1590*f12894f8SJason M. Bills                     messages::resourceNotFound(
1591*f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1592927a505aSKowalski, Kamil 
1593927a505aSKowalski, Kamil                     return;
1594927a505aSKowalski, Kamil                 }
1595927a505aSKowalski, Kamil 
15964a0cb85cSEd Tanous                 asyncResp->res.jsonValue = parseInterfaceData(
15974a0cb85cSEd Tanous                     parentIfaceId, ifaceId, ethData, ipv4Data);
1598927a505aSKowalski, Kamil 
15994a0cb85cSEd Tanous                 for (auto propertyIt : patchReq.items())
16001abe55efSEd Tanous                 {
1601927a505aSKowalski, Kamil                     if (propertyIt.key() != "VLANEnable" &&
16021abe55efSEd Tanous                         propertyIt.key() != "VLANId")
16031abe55efSEd Tanous                     {
16041abe55efSEd Tanous                         auto fieldInJsonIt =
16054a0cb85cSEd Tanous                             asyncResp->res.jsonValue.find(propertyIt.key());
16064a0cb85cSEd Tanous                         if (fieldInJsonIt == asyncResp->res.jsonValue.end())
16071abe55efSEd Tanous                         {
1608927a505aSKowalski, Kamil                             // Field not in scope of defined fields
1609*f12894f8SJason M. Bills                             messages::propertyUnknown(asyncResp->res,
1610*f12894f8SJason M. Bills                                                       propertyIt.key(),
1611*f12894f8SJason M. Bills                                                       propertyIt.key());
16121abe55efSEd Tanous                         }
16134a0cb85cSEd Tanous                         else
16141abe55efSEd Tanous                         {
1615927a505aSKowalski, Kamil                             // User attempted to modify non-writable field
1616*f12894f8SJason M. Bills                             messages::propertyNotWritable(asyncResp->res,
1617*f12894f8SJason M. Bills                                                           propertyIt.key(),
1618*f12894f8SJason M. Bills                                                           propertyIt.key());
1619927a505aSKowalski, Kamil                         }
1620927a505aSKowalski, Kamil                     }
1621927a505aSKowalski, Kamil                 }
1622927a505aSKowalski, Kamil 
16234a0cb85cSEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, patchReq, ethData,
16244a0cb85cSEd Tanous                                                    asyncResp);
1625927a505aSKowalski, Kamil             });
1626e439f0f8SKowalski, Kamil     }
1627e439f0f8SKowalski, Kamil 
162855c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
16291abe55efSEd Tanous                   const std::vector<std::string> &params) override
16301abe55efSEd Tanous     {
16314a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
16321abe55efSEd Tanous         if (params.size() != 2)
16331abe55efSEd Tanous         {
1634*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1635e439f0f8SKowalski, Kamil             return;
1636e439f0f8SKowalski, Kamil         }
1637e439f0f8SKowalski, Kamil 
1638d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
163955c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1640927a505aSKowalski, Kamil 
16414a0cb85cSEd Tanous         if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId))
16421abe55efSEd Tanous         {
1643927a505aSKowalski, Kamil             return;
1644927a505aSKowalski, Kamil         }
1645927a505aSKowalski, Kamil 
1646927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1647927a505aSKowalski, Kamil         // preparation
1648*f12894f8SJason M. Bills         getEthernetIfaceData(
1649*f12894f8SJason M. Bills             ifaceId,
1650*f12894f8SJason M. Bills             [this, asyncResp, parentIfaceId{std::string(parentIfaceId)},
16514a0cb85cSEd Tanous              ifaceId{std::string(ifaceId)}](
1652*f12894f8SJason M. Bills                 const bool &success, const EthernetInterfaceData &ethData,
1653*f12894f8SJason M. Bills                 const boost::container::flat_set<IPv4AddressData> &ipv4Data) {
16544a0cb85cSEd Tanous                 if (success && ethData.vlan_id)
16551abe55efSEd Tanous                 {
16564a0cb85cSEd Tanous                     asyncResp->res.jsonValue = parseInterfaceData(
16574a0cb85cSEd Tanous                         parentIfaceId, ifaceId, ethData, ipv4Data);
1658927a505aSKowalski, Kamil 
1659*f12894f8SJason M. Bills                     auto callback =
1660*f12894f8SJason M. Bills                         [asyncResp](const boost::system::error_code ec) {
16611abe55efSEd Tanous                             if (ec)
16621abe55efSEd Tanous                             {
1663*f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
1664927a505aSKowalski, Kamil                             }
16654a0cb85cSEd Tanous                         };
16664a0cb85cSEd Tanous                     crow::connections::systemBus->async_method_call(
16674a0cb85cSEd Tanous                         std::move(callback), "xyz.openbmc_project.Network",
16684a0cb85cSEd Tanous                         std::string("/xyz/openbmc_project/network/") + ifaceId,
16694a0cb85cSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
16701abe55efSEd Tanous                 }
16711abe55efSEd Tanous                 else
16721abe55efSEd Tanous                 {
1673927a505aSKowalski, Kamil                     // ... otherwise return error
1674*f12894f8SJason M. Bills                     // TODO(Pawel)consider distinguish between non existing
1675*f12894f8SJason M. Bills                     // object, and other errors
1676*f12894f8SJason M. Bills                     messages::resourceNotFound(
1677*f12894f8SJason M. Bills                         asyncResp->res, "VLAN Network Interface", ifaceId);
1678927a505aSKowalski, Kamil                 }
1679927a505aSKowalski, Kamil             });
1680e439f0f8SKowalski, Kamil     }
1681e439f0f8SKowalski, Kamil };
1682e439f0f8SKowalski, Kamil 
1683e439f0f8SKowalski, Kamil /**
1684e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1685e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1686e439f0f8SKowalski, Kamil  */
16871abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
16881abe55efSEd Tanous {
1689e439f0f8SKowalski, Kamil   public:
1690e439f0f8SKowalski, Kamil     template <typename CrowApp>
16911abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
16924a0cb85cSEd Tanous     // one manager called openbmc.  This shall be generic, but requires to
16934a0cb85cSEd Tanous     // update GetSubroutes method
16941abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
16954a0cb85cSEd Tanous         Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/",
16964a0cb85cSEd Tanous              std::string())
16971abe55efSEd Tanous     {
1698e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1699e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1700e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1701e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata"
1702e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1703e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface Collection";
1704e439f0f8SKowalski, Kamil 
1705e439f0f8SKowalski, Kamil         entityPrivileges = {
1706e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1707e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1708e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1709e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1710e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1711e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1712e439f0f8SKowalski, Kamil     }
1713e439f0f8SKowalski, Kamil 
1714e439f0f8SKowalski, Kamil   private:
1715e439f0f8SKowalski, Kamil     /**
1716e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1717e439f0f8SKowalski, Kamil      */
171855c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
17191abe55efSEd Tanous                const std::vector<std::string> &params) override
17201abe55efSEd Tanous     {
17214a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17221abe55efSEd Tanous         if (params.size() != 1)
17231abe55efSEd Tanous         {
1724e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1725*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1726e439f0f8SKowalski, Kamil             return;
1727e439f0f8SKowalski, Kamil         }
1728e439f0f8SKowalski, Kamil 
17294a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1730e439f0f8SKowalski, Kamil 
17314a0cb85cSEd Tanous         // Get eth interface list, and call the below callback for JSON
17321abe55efSEd Tanous         // preparation
1733*f12894f8SJason M. Bills         getEthernetIfaceList(
1734*f12894f8SJason M. Bills             [this, asyncResp,
1735*f12894f8SJason M. Bills              rootInterfaceName{std::string(rootInterfaceName)}](
17361abe55efSEd Tanous                 const bool &success,
17371abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
17384a0cb85cSEd Tanous                 if (!success)
17391abe55efSEd Tanous                 {
1740*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
17414a0cb85cSEd Tanous                     return;
17421abe55efSEd Tanous                 }
17434a0cb85cSEd Tanous                 asyncResp->res.jsonValue = Node::json;
17444a0cb85cSEd Tanous 
17454a0cb85cSEd Tanous                 nlohmann::json iface_array = nlohmann::json::array();
17464a0cb85cSEd Tanous 
17474a0cb85cSEd Tanous                 for (const std::string &iface_item : iface_list)
17481abe55efSEd Tanous                 {
17494a0cb85cSEd Tanous                     if (boost::starts_with(iface_item, rootInterfaceName + "_"))
17504a0cb85cSEd Tanous                     {
17514a0cb85cSEd Tanous                         iface_array.push_back(
17524a0cb85cSEd Tanous                             {{"@odata.id",
17534a0cb85cSEd Tanous                               "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
17544a0cb85cSEd Tanous                                   rootInterfaceName + "/VLANs/" + iface_item}});
1755e439f0f8SKowalski, Kamil                     }
1756e439f0f8SKowalski, Kamil                 }
1757e439f0f8SKowalski, Kamil 
17584a0cb85cSEd Tanous                 if (iface_array.empty())
17591abe55efSEd Tanous                 {
1760*f12894f8SJason M. Bills                     messages::resourceNotFound(
1761*f12894f8SJason M. Bills                         asyncResp->res, "EthernetInterface", rootInterfaceName);
17624a0cb85cSEd Tanous                     return;
1763e439f0f8SKowalski, Kamil                 }
17644a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] =
17654a0cb85cSEd Tanous                     iface_array.size();
17664a0cb85cSEd Tanous                 asyncResp->res.jsonValue["Members"] = std::move(iface_array);
17674a0cb85cSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
17684a0cb85cSEd Tanous                     "/redfish/v1/Managers/bmc/EthernetInterfaces/" +
17694a0cb85cSEd Tanous                     rootInterfaceName + "/VLANs";
1770e439f0f8SKowalski, Kamil             });
1771e439f0f8SKowalski, Kamil     }
1772e439f0f8SKowalski, Kamil 
177355c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
17741abe55efSEd Tanous                 const std::vector<std::string> &params) override
17751abe55efSEd Tanous     {
17764a0cb85cSEd Tanous         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
17771abe55efSEd Tanous         if (params.size() != 1)
17781abe55efSEd Tanous         {
1779*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1780e439f0f8SKowalski, Kamil             return;
1781e439f0f8SKowalski, Kamil         }
1782e439f0f8SKowalski, Kamil 
1783e439f0f8SKowalski, Kamil         nlohmann::json postReq;
17841abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, postReq))
17851abe55efSEd Tanous         {
1786e439f0f8SKowalski, Kamil             return;
1787e439f0f8SKowalski, Kamil         }
1788e439f0f8SKowalski, Kamil 
17894a0cb85cSEd Tanous         auto vlanIdJson = json.find("VLANId");
17904a0cb85cSEd Tanous         if (vlanIdJson == json.end())
17911abe55efSEd Tanous         {
1792*f12894f8SJason M. Bills             messages::propertyMissing(asyncResp->res, "VLANId", "/VLANId");
1793e439f0f8SKowalski, Kamil             return;
1794e439f0f8SKowalski, Kamil         }
1795e439f0f8SKowalski, Kamil 
17964a0cb85cSEd Tanous         const uint64_t *vlanId = vlanIdJson->get_ptr<const uint64_t *>();
17974a0cb85cSEd Tanous         if (vlanId == nullptr)
17981abe55efSEd Tanous         {
1799*f12894f8SJason M. Bills             messages::propertyValueTypeError(asyncResp->res, vlanIdJson->dump(),
1800*f12894f8SJason M. Bills                                              "VLANId", "/VLANId");
18014a0cb85cSEd Tanous             return;
1802e439f0f8SKowalski, Kamil         }
18034a0cb85cSEd Tanous         const std::string &rootInterfaceName = params[0];
1804e439f0f8SKowalski, Kamil 
18054a0cb85cSEd Tanous         auto callback = [asyncResp](const boost::system::error_code ec) {
18061abe55efSEd Tanous             if (ec)
18071abe55efSEd Tanous             {
18084a0cb85cSEd Tanous                 // TODO(ed) make more consistent error messages based on
18094a0cb85cSEd Tanous                 // phosphor-network responses
1810*f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
18114a0cb85cSEd Tanous                 return;
18121abe55efSEd Tanous             }
1813*f12894f8SJason M. Bills             messages::created(asyncResp->res);
1814e439f0f8SKowalski, Kamil         };
18154a0cb85cSEd Tanous         crow::connections::systemBus->async_method_call(
18164a0cb85cSEd Tanous             std::move(callback), "xyz.openbmc_project.Network",
18174a0cb85cSEd Tanous             "/xyz/openbmc_project/network",
18184a0cb85cSEd Tanous             "xyz.openbmc_project.Network.VLAN.Create", "VLAN",
18194a0cb85cSEd Tanous             rootInterfaceName, static_cast<uint32_t>(*vlanId));
18204a0cb85cSEd Tanous     }
18214a0cb85cSEd Tanous };
18229391bb9cSRapkiewicz, Pawel } // namespace redfish
1823