xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision 1abe55ef9844afcddcab9d862ae06118f3a2390c)
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 
18*1abe55efSEd Tanous #include <boost/container/flat_map.hpp>
19179db1d7SKowalski, Kamil #include <dbus_singleton.hpp>
20588c3f0dSKowalski, Kamil #include <error_messages.hpp>
21179db1d7SKowalski, Kamil #include <node.hpp>
22588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp>
239391bb9cSRapkiewicz, Pawel 
24*1abe55efSEd Tanous namespace redfish
25*1abe55efSEd Tanous {
269391bb9cSRapkiewicz, Pawel 
279391bb9cSRapkiewicz, Pawel /**
289391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
299391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
309391bb9cSRapkiewicz, Pawel  */
31aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
32aa2e59c1SEd Tanous     std::string,
33aa2e59c1SEd Tanous     sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t,
34aa2e59c1SEd Tanous                                 int32_t, uint32_t, int64_t, uint64_t, double>>;
359391bb9cSRapkiewicz, Pawel 
369391bb9cSRapkiewicz, Pawel using GetManagedObjectsType = boost::container::flat_map<
37aa2e59c1SEd Tanous     sdbusplus::message::object_path,
38aa2e59c1SEd Tanous     boost::container::flat_map<
39aa2e59c1SEd Tanous         std::string,
40aa2e59c1SEd Tanous         boost::container::flat_map<
41aa2e59c1SEd Tanous             std::string, sdbusplus::message::variant<
42aa2e59c1SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
43aa2e59c1SEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double>>>>;
449391bb9cSRapkiewicz, Pawel 
459391bb9cSRapkiewicz, Pawel /**
469391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
479391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider change everything to ptr, or to non-ptr values.
489391bb9cSRapkiewicz, Pawel  */
49*1abe55efSEd Tanous struct IPv4AddressData
50*1abe55efSEd Tanous {
51179db1d7SKowalski, Kamil     std::string id;
529391bb9cSRapkiewicz, Pawel     const std::string *address;
539391bb9cSRapkiewicz, Pawel     const std::string *domain;
549391bb9cSRapkiewicz, Pawel     const std::string *gateway;
559391bb9cSRapkiewicz, Pawel     std::string netmask;
569391bb9cSRapkiewicz, Pawel     std::string origin;
579391bb9cSRapkiewicz, Pawel     bool global;
58179db1d7SKowalski, Kamil     /**
59179db1d7SKowalski, Kamil      * @brief Operator< to enable sorting
60179db1d7SKowalski, Kamil      *
61179db1d7SKowalski, Kamil      * @param[in] obj   Object to compare with
62179db1d7SKowalski, Kamil      *
63179db1d7SKowalski, Kamil      * @return This object id < supplied object id
64179db1d7SKowalski, Kamil      */
65*1abe55efSEd Tanous     bool operator<(const IPv4AddressData &obj) const
66*1abe55efSEd Tanous     {
67*1abe55efSEd Tanous         return (id < obj.id);
68*1abe55efSEd Tanous     }
699391bb9cSRapkiewicz, Pawel };
709391bb9cSRapkiewicz, Pawel 
719391bb9cSRapkiewicz, Pawel /**
729391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
739391bb9cSRapkiewicz, Pawel  * available from DBus
749391bb9cSRapkiewicz, Pawel  */
75*1abe55efSEd Tanous struct EthernetInterfaceData
76*1abe55efSEd Tanous {
779391bb9cSRapkiewicz, Pawel     const unsigned int *speed;
7855c7b7a2SEd Tanous     const bool *autoNeg;
799391bb9cSRapkiewicz, Pawel     const std::string *hostname;
8055c7b7a2SEd Tanous     const std::string *defaultGateway;
8155c7b7a2SEd Tanous     const std::string *macAddress;
8255c7b7a2SEd Tanous     const unsigned int *vlanId;
839391bb9cSRapkiewicz, Pawel };
849391bb9cSRapkiewicz, Pawel 
859391bb9cSRapkiewicz, Pawel /**
869391bb9cSRapkiewicz, Pawel  * OnDemandEthernetProvider
87274fad5aSGunnar Mills  * Ethernet provider class that retrieves data directly from dbus, before
88274fad5aSGunnar Mills  * setting it into JSON output. This does not cache any data.
899391bb9cSRapkiewicz, Pawel  *
909391bb9cSRapkiewicz, Pawel  * TODO(Pawel)
919391bb9cSRapkiewicz, Pawel  * This perhaps shall be different file, which has to be chosen on compile time
929391bb9cSRapkiewicz, Pawel  * depending on OEM needs
939391bb9cSRapkiewicz, Pawel  */
94*1abe55efSEd Tanous class OnDemandEthernetProvider
95*1abe55efSEd Tanous {
969391bb9cSRapkiewicz, Pawel   private:
97*1abe55efSEd Tanous     // Consts that may have influence on EthernetProvider performance/memory
98*1abe55efSEd Tanous     // usage
9955c7b7a2SEd Tanous     const size_t maxIpV4AddressesPerInterface = 10;
1009391bb9cSRapkiewicz, Pawel 
1019391bb9cSRapkiewicz, Pawel     // Helper function that allows to extract GetAllPropertiesType from
1029391bb9cSRapkiewicz, Pawel     // GetManagedObjectsType, based on object path, and interface name
1039391bb9cSRapkiewicz, Pawel     const PropertiesMapType *extractInterfaceProperties(
104aa2e59c1SEd Tanous         const sdbusplus::message::object_path &objpath,
105*1abe55efSEd Tanous         const std::string &interface, const GetManagedObjectsType &dbus_data)
106*1abe55efSEd Tanous     {
10755c7b7a2SEd Tanous         const auto &dbusObj = dbus_data.find(objpath);
108*1abe55efSEd Tanous         if (dbusObj != dbus_data.end())
109*1abe55efSEd Tanous         {
11055c7b7a2SEd Tanous             const auto &iface = dbusObj->second.find(interface);
111*1abe55efSEd Tanous             if (iface != dbusObj->second.end())
112*1abe55efSEd Tanous             {
1139391bb9cSRapkiewicz, Pawel                 return &iface->second;
1149391bb9cSRapkiewicz, Pawel             }
1159391bb9cSRapkiewicz, Pawel         }
1169391bb9cSRapkiewicz, Pawel         return nullptr;
1179391bb9cSRapkiewicz, Pawel     }
1189391bb9cSRapkiewicz, Pawel 
1199391bb9cSRapkiewicz, Pawel     // Helper Wrapper that does inline object_path conversion from string
120aa2e59c1SEd Tanous     // into sdbusplus::message::object_path type
121*1abe55efSEd Tanous     inline const PropertiesMapType *
122*1abe55efSEd Tanous         extractInterfaceProperties(const std::string &objpath,
123*1abe55efSEd Tanous                                    const std::string &interface,
124*1abe55efSEd Tanous                                    const GetManagedObjectsType &dbus_data)
125*1abe55efSEd Tanous     {
12655c7b7a2SEd Tanous         const auto &dbusObj = sdbusplus::message::object_path{objpath};
12755c7b7a2SEd Tanous         return extractInterfaceProperties(dbusObj, interface, dbus_data);
1289391bb9cSRapkiewicz, Pawel     }
1299391bb9cSRapkiewicz, Pawel 
1309391bb9cSRapkiewicz, Pawel     // Helper function that allows to get pointer to the property from
1319391bb9cSRapkiewicz, Pawel     // GetAllPropertiesType native, or extracted by GetAllPropertiesType
1329391bb9cSRapkiewicz, Pawel     template <typename T>
133aa2e59c1SEd Tanous     inline T const *const extractProperty(const PropertiesMapType &properties,
134*1abe55efSEd Tanous                                           const std::string &name)
135*1abe55efSEd Tanous     {
1369391bb9cSRapkiewicz, Pawel         const auto &property = properties.find(name);
137*1abe55efSEd Tanous         if (property != properties.end())
138*1abe55efSEd Tanous         {
13955c7b7a2SEd Tanous             return mapbox::getPtr<const T>(property->second);
1409391bb9cSRapkiewicz, Pawel         }
1419391bb9cSRapkiewicz, Pawel         return nullptr;
1429391bb9cSRapkiewicz, Pawel     }
1439391bb9cSRapkiewicz, Pawel     // TODO(Pawel) Consider to move the above functions to dbus
1449391bb9cSRapkiewicz, Pawel     // generic_interfaces.hpp
1459391bb9cSRapkiewicz, Pawel 
1469391bb9cSRapkiewicz, Pawel     // Helper function that extracts data from several dbus objects and several
1479391bb9cSRapkiewicz, Pawel     // interfaces required by single ethernet interface instance
14855c7b7a2SEd Tanous     void extractEthernetInterfaceData(const std::string &ethifaceId,
1499391bb9cSRapkiewicz, Pawel                                       const GetManagedObjectsType &dbus_data,
150*1abe55efSEd Tanous                                       EthernetInterfaceData &eth_data)
151*1abe55efSEd Tanous     {
1529391bb9cSRapkiewicz, Pawel         // Extract data that contains MAC Address
15355c7b7a2SEd Tanous         const PropertiesMapType *macProperties = extractInterfaceProperties(
15455c7b7a2SEd Tanous             "/xyz/openbmc_project/network/" + ethifaceId,
1559391bb9cSRapkiewicz, Pawel             "xyz.openbmc_project.Network.MACAddress", dbus_data);
1569391bb9cSRapkiewicz, Pawel 
157*1abe55efSEd Tanous         if (macProperties != nullptr)
158*1abe55efSEd Tanous         {
15955c7b7a2SEd Tanous             eth_data.macAddress =
16055c7b7a2SEd Tanous                 extractProperty<std::string>(*macProperties, "MACAddress");
1619391bb9cSRapkiewicz, Pawel         }
1629391bb9cSRapkiewicz, Pawel 
16355c7b7a2SEd Tanous         const PropertiesMapType *vlanProperties = extractInterfaceProperties(
16455c7b7a2SEd Tanous             "/xyz/openbmc_project/network/" + ethifaceId,
165c7070ac2SKowalski, Kamil             "xyz.openbmc_project.Network.VLAN", dbus_data);
166c7070ac2SKowalski, Kamil 
167*1abe55efSEd Tanous         if (vlanProperties != nullptr)
168*1abe55efSEd Tanous         {
169*1abe55efSEd Tanous             eth_data.vlanId =
170*1abe55efSEd Tanous                 extractProperty<unsigned int>(*vlanProperties, "Id");
171c7070ac2SKowalski, Kamil         }
172c7070ac2SKowalski, Kamil 
173*1abe55efSEd Tanous         // Extract data that contains link information (auto negotiation and
174*1abe55efSEd Tanous         // speed)
17555c7b7a2SEd Tanous         const PropertiesMapType *ethProperties = extractInterfaceProperties(
17655c7b7a2SEd Tanous             "/xyz/openbmc_project/network/" + ethifaceId,
1779391bb9cSRapkiewicz, Pawel             "xyz.openbmc_project.Network.EthernetInterface", dbus_data);
1789391bb9cSRapkiewicz, Pawel 
179*1abe55efSEd Tanous         if (ethProperties != nullptr)
180*1abe55efSEd Tanous         {
18155c7b7a2SEd Tanous             eth_data.autoNeg = extractProperty<bool>(*ethProperties, "AutoNeg");
182*1abe55efSEd Tanous             eth_data.speed =
183*1abe55efSEd Tanous                 extractProperty<unsigned int>(*ethProperties, "Speed");
1849391bb9cSRapkiewicz, Pawel         }
1859391bb9cSRapkiewicz, Pawel 
1869391bb9cSRapkiewicz, Pawel         // Extract data that contains network config (HostName and DefaultGW)
18755c7b7a2SEd Tanous         const PropertiesMapType *configProperties = extractInterfaceProperties(
1889391bb9cSRapkiewicz, Pawel             "/xyz/openbmc_project/network/config",
1899391bb9cSRapkiewicz, Pawel             "xyz.openbmc_project.Network.SystemConfiguration", dbus_data);
1909391bb9cSRapkiewicz, Pawel 
191*1abe55efSEd Tanous         if (configProperties != nullptr)
192*1abe55efSEd Tanous         {
1939391bb9cSRapkiewicz, Pawel             eth_data.hostname =
19455c7b7a2SEd Tanous                 extractProperty<std::string>(*configProperties, "HostName");
195*1abe55efSEd Tanous             eth_data.defaultGateway = extractProperty<std::string>(
196*1abe55efSEd Tanous                 *configProperties, "DefaultGateway");
1979391bb9cSRapkiewicz, Pawel         }
1989391bb9cSRapkiewicz, Pawel     }
1999391bb9cSRapkiewicz, Pawel 
2009391bb9cSRapkiewicz, Pawel     // Helper function that changes bits netmask notation (i.e. /24)
2019391bb9cSRapkiewicz, Pawel     // into full dot notation
202*1abe55efSEd Tanous     inline std::string getNetmask(unsigned int bits)
203*1abe55efSEd Tanous     {
2049391bb9cSRapkiewicz, Pawel         uint32_t value = 0xffffffff << (32 - bits);
2059391bb9cSRapkiewicz, Pawel         std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
2069391bb9cSRapkiewicz, Pawel                               std::to_string((value >> 16) & 0xff) + "." +
2079391bb9cSRapkiewicz, Pawel                               std::to_string((value >> 8) & 0xff) + "." +
2089391bb9cSRapkiewicz, Pawel                               std::to_string(value & 0xff);
2099391bb9cSRapkiewicz, Pawel         return netmask;
2109391bb9cSRapkiewicz, Pawel     }
2119391bb9cSRapkiewicz, Pawel 
2129391bb9cSRapkiewicz, Pawel     // Helper function that extracts data for single ethernet ipv4 address
21355c7b7a2SEd Tanous     void extractIPv4Data(const std::string &ethifaceId,
2149391bb9cSRapkiewicz, Pawel                          const GetManagedObjectsType &dbus_data,
215*1abe55efSEd Tanous                          std::vector<IPv4AddressData> &ipv4_config)
216*1abe55efSEd Tanous     {
217179db1d7SKowalski, Kamil         const std::string pathStart =
21855c7b7a2SEd Tanous             "/xyz/openbmc_project/network/" + ethifaceId + "/ipv4/";
219179db1d7SKowalski, Kamil 
2209391bb9cSRapkiewicz, Pawel         // Since there might be several IPv4 configurations aligned with
2219391bb9cSRapkiewicz, Pawel         // single ethernet interface, loop over all of them
222*1abe55efSEd Tanous         for (auto &objpath : dbus_data)
223*1abe55efSEd Tanous         {
224274fad5aSGunnar Mills             // Check if proper patter for object path appears
225*1abe55efSEd Tanous             if (boost::starts_with(
226*1abe55efSEd Tanous                     static_cast<const std::string &>(objpath.first), pathStart))
227*1abe55efSEd Tanous             {
2289391bb9cSRapkiewicz, Pawel                 // and get approrpiate interface
2299391bb9cSRapkiewicz, Pawel                 const auto &interface =
2309391bb9cSRapkiewicz, Pawel                     objpath.second.find("xyz.openbmc_project.Network.IP");
231*1abe55efSEd Tanous                 if (interface != objpath.second.end())
232*1abe55efSEd Tanous                 {
233*1abe55efSEd Tanous                     // Make a properties 'shortcut', to make everything more
234*1abe55efSEd Tanous                     // readable
2359391bb9cSRapkiewicz, Pawel                     const PropertiesMapType &properties = interface->second;
236*1abe55efSEd Tanous                     // Instance IPv4AddressData structure, and set as
237*1abe55efSEd Tanous                     // appropriate
23855c7b7a2SEd Tanous                     IPv4AddressData ipv4Address;
239179db1d7SKowalski, Kamil 
240*1abe55efSEd Tanous                     ipv4Address.id =
241*1abe55efSEd Tanous                         static_cast<const std::string &>(objpath.first)
242179db1d7SKowalski, Kamil                             .substr(pathStart.size());
243179db1d7SKowalski, Kamil 
2449391bb9cSRapkiewicz, Pawel                     // IPv4 address
24555c7b7a2SEd Tanous                     ipv4Address.address =
2469391bb9cSRapkiewicz, Pawel                         extractProperty<std::string>(properties, "Address");
2479391bb9cSRapkiewicz, Pawel                     // IPv4 gateway
24855c7b7a2SEd Tanous                     ipv4Address.gateway =
2499391bb9cSRapkiewicz, Pawel                         extractProperty<std::string>(properties, "Gateway");
2509391bb9cSRapkiewicz, Pawel 
2519391bb9cSRapkiewicz, Pawel                     // Origin is kind of DBus object so fetch pointer...
2529391bb9cSRapkiewicz, Pawel                     const std::string *origin =
2539391bb9cSRapkiewicz, Pawel                         extractProperty<std::string>(properties, "Origin");
254*1abe55efSEd Tanous                     if (origin != nullptr)
255*1abe55efSEd Tanous                     {
25655c7b7a2SEd Tanous                         ipv4Address.origin =
257*1abe55efSEd Tanous                             translateAddressOriginBetweenDBusAndRedfish(
258*1abe55efSEd Tanous                                 origin, true, true);
2599391bb9cSRapkiewicz, Pawel                     }
2609391bb9cSRapkiewicz, Pawel 
2619391bb9cSRapkiewicz, Pawel                     // Netmask is presented as PrefixLength
2629391bb9cSRapkiewicz, Pawel                     const auto *mask =
2639391bb9cSRapkiewicz, Pawel                         extractProperty<uint8_t>(properties, "PrefixLength");
264*1abe55efSEd Tanous                     if (mask != nullptr)
265*1abe55efSEd Tanous                     {
2669391bb9cSRapkiewicz, Pawel                         // convert it to the string
26755c7b7a2SEd Tanous                         ipv4Address.netmask = getNetmask(*mask);
2689391bb9cSRapkiewicz, Pawel                     }
2699391bb9cSRapkiewicz, Pawel 
2709391bb9cSRapkiewicz, Pawel                     // Attach IPv4 only if address is present
271*1abe55efSEd Tanous                     if (ipv4Address.address != nullptr)
272*1abe55efSEd Tanous                     {
273a434f2bdSEd Tanous                         // Check if given address is local, or global
274*1abe55efSEd Tanous                         if (boost::starts_with(*ipv4Address.address, "169.254"))
275*1abe55efSEd Tanous                         {
27655c7b7a2SEd Tanous                             ipv4Address.global = false;
277*1abe55efSEd Tanous                         }
278*1abe55efSEd Tanous                         else
279*1abe55efSEd Tanous                         {
28055c7b7a2SEd Tanous                             ipv4Address.global = true;
2819391bb9cSRapkiewicz, Pawel                         }
28255c7b7a2SEd Tanous                         ipv4_config.emplace_back(std::move(ipv4Address));
2839391bb9cSRapkiewicz, Pawel                     }
2849391bb9cSRapkiewicz, Pawel                 }
2859391bb9cSRapkiewicz, Pawel             }
2869391bb9cSRapkiewicz, Pawel         }
287179db1d7SKowalski, Kamil 
288179db1d7SKowalski, Kamil         /**
289179db1d7SKowalski, Kamil          * We have to sort this vector and ensure that order of IPv4 addresses
290*1abe55efSEd Tanous          * is consistent between GETs to allow modification and deletion in
291*1abe55efSEd Tanous          * PATCHes
292179db1d7SKowalski, Kamil          */
293179db1d7SKowalski, Kamil         std::sort(ipv4_config.begin(), ipv4_config.end());
2949391bb9cSRapkiewicz, Pawel     }
2959391bb9cSRapkiewicz, Pawel 
296179db1d7SKowalski, Kamil     static const constexpr int ipV4AddressSectionsCount = 4;
297179db1d7SKowalski, Kamil 
2989391bb9cSRapkiewicz, Pawel   public:
2999391bb9cSRapkiewicz, Pawel     /**
300588c3f0dSKowalski, Kamil      * @brief Creates VLAN for given interface with given Id through D-Bus
301588c3f0dSKowalski, Kamil      *
302588c3f0dSKowalski, Kamil      * @param[in] ifaceId       Id of interface for which VLAN will be created
303588c3f0dSKowalski, Kamil      * @param[in] inputVlanId   ID of the new VLAN
304588c3f0dSKowalski, Kamil      * @param[in] callback      Function that will be called after the operation
305588c3f0dSKowalski, Kamil      *
306588c3f0dSKowalski, Kamil      * @return None.
307588c3f0dSKowalski, Kamil      */
308588c3f0dSKowalski, Kamil     template <typename CallbackFunc>
309588c3f0dSKowalski, Kamil     void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId,
310*1abe55efSEd Tanous                     CallbackFunc &&callback)
311*1abe55efSEd Tanous     {
31255c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
313*1abe55efSEd Tanous             callback, "xyz.openbmc_project.Network",
314*1abe55efSEd Tanous             "/xyz/openbmc_project/network",
315588c3f0dSKowalski, Kamil             "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId,
316588c3f0dSKowalski, Kamil             static_cast<uint32_t>(inputVlanId));
317588c3f0dSKowalski, Kamil     };
318588c3f0dSKowalski, Kamil 
319588c3f0dSKowalski, Kamil     /**
320588c3f0dSKowalski, Kamil      * @brief Sets given Id on the given VLAN interface through D-Bus
321588c3f0dSKowalski, Kamil      *
322588c3f0dSKowalski, Kamil      * @param[in] ifaceId       Id of VLAN interface that should be modified
323588c3f0dSKowalski, Kamil      * @param[in] inputVlanId   New ID of the VLAN
324588c3f0dSKowalski, Kamil      * @param[in] callback      Function that will be called after the operation
325588c3f0dSKowalski, Kamil      *
326588c3f0dSKowalski, Kamil      * @return None.
327588c3f0dSKowalski, Kamil      */
328588c3f0dSKowalski, Kamil     template <typename CallbackFunc>
329e439f0f8SKowalski, Kamil     static void changeVlanId(const std::string &ifaceId,
330e439f0f8SKowalski, Kamil                              const uint32_t &inputVlanId,
331*1abe55efSEd Tanous                              CallbackFunc &&callback)
332*1abe55efSEd Tanous     {
33355c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
334588c3f0dSKowalski, Kamil             callback, "xyz.openbmc_project.Network",
335588c3f0dSKowalski, Kamil             std::string("/xyz/openbmc_project/network/") + ifaceId,
336588c3f0dSKowalski, Kamil             "org.freedesktop.DBus.Properties", "Set",
337588c3f0dSKowalski, Kamil             "xyz.openbmc_project.Network.VLAN", "Id",
338588c3f0dSKowalski, Kamil             sdbusplus::message::variant<uint32_t>(inputVlanId));
339588c3f0dSKowalski, Kamil     };
340588c3f0dSKowalski, Kamil 
341588c3f0dSKowalski, Kamil     /**
342179db1d7SKowalski, Kamil      * @brief Helper function that verifies IP address to check if it is in
343179db1d7SKowalski, Kamil      *        proper format. If bits pointer is provided, also calculates active
344179db1d7SKowalski, Kamil      *        bit count for Subnet Mask.
345179db1d7SKowalski, Kamil      *
346179db1d7SKowalski, Kamil      * @param[in]  ip     IP that will be verified
347179db1d7SKowalski, Kamil      * @param[out] bits   Calculated mask in bits notation
348179db1d7SKowalski, Kamil      *
349179db1d7SKowalski, Kamil      * @return true in case of success, false otherwise
350179db1d7SKowalski, Kamil      */
351179db1d7SKowalski, Kamil     bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
352*1abe55efSEd Tanous                                     uint8_t *bits = nullptr)
353*1abe55efSEd Tanous     {
354179db1d7SKowalski, Kamil         std::vector<std::string> bytesInMask;
355179db1d7SKowalski, Kamil 
356179db1d7SKowalski, Kamil         boost::split(bytesInMask, ip, boost::is_any_of("."));
357179db1d7SKowalski, Kamil 
358*1abe55efSEd Tanous         if (bytesInMask.size() != ipV4AddressSectionsCount)
359*1abe55efSEd Tanous         {
360179db1d7SKowalski, Kamil             return false;
361179db1d7SKowalski, Kamil         }
362179db1d7SKowalski, Kamil 
363*1abe55efSEd Tanous         if (bits != nullptr)
364*1abe55efSEd Tanous         {
365179db1d7SKowalski, Kamil             *bits = 0;
366179db1d7SKowalski, Kamil         }
367179db1d7SKowalski, Kamil 
368179db1d7SKowalski, Kamil         char *endPtr;
369179db1d7SKowalski, Kamil         long previousValue = 255;
370179db1d7SKowalski, Kamil         bool firstZeroInByteHit;
371*1abe55efSEd Tanous         for (const std::string &byte : bytesInMask)
372*1abe55efSEd Tanous         {
373*1abe55efSEd Tanous             if (byte.empty())
374*1abe55efSEd Tanous             {
3751db9ca37SKowalski, Kamil                 return false;
3761db9ca37SKowalski, Kamil             }
3771db9ca37SKowalski, Kamil 
378179db1d7SKowalski, Kamil             // Use strtol instead of stroi to avoid exceptions
3791db9ca37SKowalski, Kamil             long value = std::strtol(byte.c_str(), &endPtr, 10);
380179db1d7SKowalski, Kamil 
381*1abe55efSEd Tanous             // endPtr should point to the end of the string, otherwise given
382*1abe55efSEd Tanous             // string is not 100% number
383*1abe55efSEd Tanous             if (*endPtr != '\0')
384*1abe55efSEd Tanous             {
385179db1d7SKowalski, Kamil                 return false;
386179db1d7SKowalski, Kamil             }
387179db1d7SKowalski, Kamil 
388179db1d7SKowalski, Kamil             // Value should be contained in byte
389*1abe55efSEd Tanous             if (value < 0 || value > 255)
390*1abe55efSEd Tanous             {
391179db1d7SKowalski, Kamil                 return false;
392179db1d7SKowalski, Kamil             }
393179db1d7SKowalski, Kamil 
394*1abe55efSEd Tanous             if (bits != nullptr)
395*1abe55efSEd Tanous             {
396179db1d7SKowalski, Kamil                 // Mask has to be continuous between bytes
397*1abe55efSEd Tanous                 if (previousValue != 255 && value != 0)
398*1abe55efSEd Tanous                 {
399179db1d7SKowalski, Kamil                     return false;
400179db1d7SKowalski, Kamil                 }
401179db1d7SKowalski, Kamil 
402179db1d7SKowalski, Kamil                 // Mask has to be continuous inside bytes
403179db1d7SKowalski, Kamil                 firstZeroInByteHit = false;
404179db1d7SKowalski, Kamil 
405179db1d7SKowalski, Kamil                 // Count bits
406*1abe55efSEd Tanous                 for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
407*1abe55efSEd Tanous                 {
408*1abe55efSEd Tanous                     if (value & (1 << bitIdx))
409*1abe55efSEd Tanous                     {
410*1abe55efSEd Tanous                         if (firstZeroInByteHit)
411*1abe55efSEd Tanous                         {
412179db1d7SKowalski, Kamil                             // Continuity not preserved
413179db1d7SKowalski, Kamil                             return false;
414*1abe55efSEd Tanous                         }
415*1abe55efSEd Tanous                         else
416*1abe55efSEd Tanous                         {
417179db1d7SKowalski, Kamil                             (*bits)++;
418179db1d7SKowalski, Kamil                         }
419*1abe55efSEd Tanous                     }
420*1abe55efSEd Tanous                     else
421*1abe55efSEd Tanous                     {
422179db1d7SKowalski, Kamil                         firstZeroInByteHit = true;
423179db1d7SKowalski, Kamil                     }
424179db1d7SKowalski, Kamil                 }
425179db1d7SKowalski, Kamil             }
426179db1d7SKowalski, Kamil 
427179db1d7SKowalski, Kamil             previousValue = value;
428179db1d7SKowalski, Kamil         }
429179db1d7SKowalski, Kamil 
430179db1d7SKowalski, Kamil         return true;
431179db1d7SKowalski, Kamil     }
432179db1d7SKowalski, Kamil 
433179db1d7SKowalski, Kamil     /**
434179db1d7SKowalski, Kamil      * @brief Changes IPv4 address type property (Address, Gateway)
435179db1d7SKowalski, Kamil      *
436179db1d7SKowalski, Kamil      * @param[in] ifaceId     Id of interface whose IP should be modified
43755c7b7a2SEd Tanous      * @param[in] ipIdx       index of IP in input array that should be modified
438179db1d7SKowalski, Kamil      * @param[in] ipHash      DBus Hash id of modified IP
439179db1d7SKowalski, Kamil      * @param[in] name        Name of field in JSON representation
440179db1d7SKowalski, Kamil      * @param[in] newValue    New value that should be written
441179db1d7SKowalski, Kamil      * @param[io] asyncResp   Response object that will be returned to client
442179db1d7SKowalski, Kamil      *
443179db1d7SKowalski, Kamil      * @return true if give IP is valid and has been sent do D-Bus, false
444179db1d7SKowalski, Kamil      * otherwise
445179db1d7SKowalski, Kamil      */
446179db1d7SKowalski, Kamil     void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx,
447179db1d7SKowalski, Kamil                                    const std::string &ipHash,
448179db1d7SKowalski, Kamil                                    const std::string &name,
449179db1d7SKowalski, Kamil                                    const std::string &newValue,
450*1abe55efSEd Tanous                                    const std::shared_ptr<AsyncResp> &asyncResp)
451*1abe55efSEd Tanous     {
452*1abe55efSEd Tanous         auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
453*1abe55efSEd Tanous                          name{std::move(name)}, newValue{std::move(newValue)}](
454*1abe55efSEd Tanous                             const boost::system::error_code ec) {
455*1abe55efSEd Tanous             if (ec)
456*1abe55efSEd Tanous             {
457179db1d7SKowalski, Kamil                 messages::addMessageToJson(
45855c7b7a2SEd Tanous                     asyncResp->res.jsonValue, messages::internalError(),
459179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name);
460*1abe55efSEd Tanous             }
461*1abe55efSEd Tanous             else
462*1abe55efSEd Tanous             {
463*1abe55efSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] =
464*1abe55efSEd Tanous                     newValue;
465179db1d7SKowalski, Kamil             }
466179db1d7SKowalski, Kamil         };
467179db1d7SKowalski, Kamil 
46855c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
469179db1d7SKowalski, Kamil             std::move(callback), "xyz.openbmc_project.Network",
470179db1d7SKowalski, Kamil             "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
471179db1d7SKowalski, Kamil             "org.freedesktop.DBus.Properties", "Set",
472179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network.IP", name,
473179db1d7SKowalski, Kamil             sdbusplus::message::variant<std::string>(newValue));
474179db1d7SKowalski, Kamil     };
475179db1d7SKowalski, Kamil 
476179db1d7SKowalski, Kamil     /**
477179db1d7SKowalski, Kamil      * @brief Changes IPv4 address origin property
478179db1d7SKowalski, Kamil      *
479179db1d7SKowalski, Kamil      * @param[in] ifaceId       Id of interface whose IP should be modified
480*1abe55efSEd Tanous      * @param[in] ipIdx         index of IP in input array that should be
481*1abe55efSEd Tanous      * modified
482179db1d7SKowalski, Kamil      * @param[in] ipHash        DBus Hash id of modified IP
483179db1d7SKowalski, Kamil      * @param[in] newValue      New value in Redfish format
484179db1d7SKowalski, Kamil      * @param[in] newValueDbus  New value in D-Bus format
485179db1d7SKowalski, Kamil      * @param[io] asyncResp     Response object that will be returned to client
486179db1d7SKowalski, Kamil      *
487179db1d7SKowalski, Kamil      * @return true if give IP is valid and has been sent do D-Bus, false
488179db1d7SKowalski, Kamil      * otherwise
489179db1d7SKowalski, Kamil      */
490179db1d7SKowalski, Kamil     void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
491*1abe55efSEd Tanous                           const std::string &ipHash,
492*1abe55efSEd Tanous                           const std::string &newValue,
493179db1d7SKowalski, Kamil                           const std::string &newValueDbus,
494*1abe55efSEd Tanous                           const std::shared_ptr<AsyncResp> &asyncResp)
495*1abe55efSEd Tanous     {
496*1abe55efSEd Tanous         auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
497*1abe55efSEd Tanous                          newValue{std::move(newValue)}](
498*1abe55efSEd Tanous                             const boost::system::error_code ec) {
499*1abe55efSEd Tanous             if (ec)
500*1abe55efSEd Tanous             {
501179db1d7SKowalski, Kamil                 messages::addMessageToJson(
50255c7b7a2SEd Tanous                     asyncResp->res.jsonValue, messages::internalError(),
503*1abe55efSEd Tanous                     "/IPv4Addresses/" + std::to_string(ipIdx) +
504*1abe55efSEd Tanous                         "/AddressOrigin");
505*1abe55efSEd Tanous             }
506*1abe55efSEd Tanous             else
507*1abe55efSEd Tanous             {
508*1abe55efSEd Tanous                 asyncResp->res
509*1abe55efSEd Tanous                     .jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
510179db1d7SKowalski, Kamil                     newValue;
511179db1d7SKowalski, Kamil             }
512179db1d7SKowalski, Kamil         };
513179db1d7SKowalski, Kamil 
51455c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
515179db1d7SKowalski, Kamil             std::move(callback), "xyz.openbmc_project.Network",
516179db1d7SKowalski, Kamil             "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
517179db1d7SKowalski, Kamil             "org.freedesktop.DBus.Properties", "Set",
518179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network.IP", "Origin",
519179db1d7SKowalski, Kamil             sdbusplus::message::variant<std::string>(newValueDbus));
520179db1d7SKowalski, Kamil     };
521179db1d7SKowalski, Kamil 
522179db1d7SKowalski, Kamil     /**
523179db1d7SKowalski, Kamil      * @brief Modifies SubnetMask for given IP
524179db1d7SKowalski, Kamil      *
525179db1d7SKowalski, Kamil      * @param[in] ifaceId      Id of interface whose IP should be modified
526*1abe55efSEd Tanous      * @param[in] ipIdx        index of IP in input array that should be
527*1abe55efSEd Tanous      * modified
528179db1d7SKowalski, Kamil      * @param[in] ipHash       DBus Hash id of modified IP
529179db1d7SKowalski, Kamil      * @param[in] newValueStr  Mask in dot notation as string
530179db1d7SKowalski, Kamil      * @param[in] newValue     Mask as PrefixLength in bitcount
531179db1d7SKowalski, Kamil      * @param[io] asyncResp   Response object that will be returned to client
532179db1d7SKowalski, Kamil      *
533179db1d7SKowalski, Kamil      * @return None
534179db1d7SKowalski, Kamil      */
535179db1d7SKowalski, Kamil     void changeIPv4SubnetMaskProperty(
536179db1d7SKowalski, Kamil         const std::string &ifaceId, int ipIdx, const std::string &ipHash,
537179db1d7SKowalski, Kamil         const std::string &newValueStr, uint8_t &newValue,
538*1abe55efSEd Tanous         const std::shared_ptr<AsyncResp> &asyncResp)
539*1abe55efSEd Tanous     {
540*1abe55efSEd Tanous         auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
541*1abe55efSEd Tanous                          newValueStr{std::move(newValueStr)}](
542*1abe55efSEd Tanous                             const boost::system::error_code ec) {
543*1abe55efSEd Tanous             if (ec)
544*1abe55efSEd Tanous             {
545179db1d7SKowalski, Kamil                 messages::addMessageToJson(
54655c7b7a2SEd Tanous                     asyncResp->res.jsonValue, messages::internalError(),
547179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask");
548*1abe55efSEd Tanous             }
549*1abe55efSEd Tanous             else
550*1abe55efSEd Tanous             {
55155c7b7a2SEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
552179db1d7SKowalski, Kamil                     newValueStr;
553179db1d7SKowalski, Kamil             }
554179db1d7SKowalski, Kamil         };
555179db1d7SKowalski, Kamil 
55655c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
557179db1d7SKowalski, Kamil             std::move(callback), "xyz.openbmc_project.Network",
558179db1d7SKowalski, Kamil             "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
559179db1d7SKowalski, Kamil             "org.freedesktop.DBus.Properties", "Set",
560179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network.IP", "PrefixLength",
561179db1d7SKowalski, Kamil             sdbusplus::message::variant<uint8_t>(newValue));
562179db1d7SKowalski, Kamil     };
563179db1d7SKowalski, Kamil 
564179db1d7SKowalski, Kamil     /**
565588c3f0dSKowalski, Kamil      * @brief Disables VLAN with given ifaceId
566588c3f0dSKowalski, Kamil      *
567588c3f0dSKowalski, Kamil      * @param[in] ifaceId   Id of VLAN interface that should be disabled
568588c3f0dSKowalski, Kamil      * @param[in] callback  Function that will be called after the operation
569588c3f0dSKowalski, Kamil      *
570588c3f0dSKowalski, Kamil      * @return None.
571588c3f0dSKowalski, Kamil      */
572588c3f0dSKowalski, Kamil     template <typename CallbackFunc>
573*1abe55efSEd Tanous     static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback)
574*1abe55efSEd Tanous     {
57555c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
576588c3f0dSKowalski, Kamil             callback, "xyz.openbmc_project.Network",
577588c3f0dSKowalski, Kamil             std::string("/xyz/openbmc_project/network/") + ifaceId,
578588c3f0dSKowalski, Kamil             "xyz.openbmc_project.Object.Delete", "Delete");
579588c3f0dSKowalski, Kamil     };
580588c3f0dSKowalski, Kamil 
581588c3f0dSKowalski, Kamil     /**
582588c3f0dSKowalski, Kamil      * @brief Sets given HostName of the machine through D-Bus
583588c3f0dSKowalski, Kamil      *
584588c3f0dSKowalski, Kamil      * @param[in] newHostname   New name that HostName will be changed to
585588c3f0dSKowalski, Kamil      * @param[in] callback      Function that will be called after the operation
586588c3f0dSKowalski, Kamil      *
587588c3f0dSKowalski, Kamil      * @return None.
588588c3f0dSKowalski, Kamil      */
589588c3f0dSKowalski, Kamil     template <typename CallbackFunc>
590*1abe55efSEd Tanous     void setHostName(const std::string &newHostname, CallbackFunc &&callback)
591*1abe55efSEd Tanous     {
59255c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
593588c3f0dSKowalski, Kamil             callback, "xyz.openbmc_project.Network",
594588c3f0dSKowalski, Kamil             "/xyz/openbmc_project/network/config",
595588c3f0dSKowalski, Kamil             "org.freedesktop.DBus.Properties", "Set",
596588c3f0dSKowalski, Kamil             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
597588c3f0dSKowalski, Kamil             sdbusplus::message::variant<std::string>(newHostname));
598588c3f0dSKowalski, Kamil     };
599588c3f0dSKowalski, Kamil 
600588c3f0dSKowalski, Kamil     /**
601179db1d7SKowalski, Kamil      * @brief Deletes given IPv4
602179db1d7SKowalski, Kamil      *
603179db1d7SKowalski, Kamil      * @param[in] ifaceId     Id of interface whose IP should be deleted
60455c7b7a2SEd Tanous      * @param[in] ipIdx       index of IP in input array that should be deleted
605179db1d7SKowalski, Kamil      * @param[in] ipHash      DBus Hash id of IP that should be deleted
606179db1d7SKowalski, Kamil      * @param[io] asyncResp   Response object that will be returned to client
607179db1d7SKowalski, Kamil      *
608179db1d7SKowalski, Kamil      * @return None
609179db1d7SKowalski, Kamil      */
610179db1d7SKowalski, Kamil     void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
611179db1d7SKowalski, Kamil                     unsigned int ipIdx,
612*1abe55efSEd Tanous                     const std::shared_ptr<AsyncResp> &asyncResp)
613*1abe55efSEd Tanous     {
61455c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
6158ceb2ecaSEd Tanous             [ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)}](
6168ceb2ecaSEd Tanous                 const boost::system::error_code ec) {
617*1abe55efSEd Tanous                 if (ec)
618*1abe55efSEd Tanous                 {
619179db1d7SKowalski, Kamil                     messages::addMessageToJson(
62055c7b7a2SEd Tanous                         asyncResp->res.jsonValue, messages::internalError(),
621179db1d7SKowalski, Kamil                         "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
622*1abe55efSEd Tanous                 }
623*1abe55efSEd Tanous                 else
624*1abe55efSEd Tanous                 {
62555c7b7a2SEd Tanous                     asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
626179db1d7SKowalski, Kamil                 }
627179db1d7SKowalski, Kamil             },
628179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network",
629179db1d7SKowalski, Kamil             "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
630179db1d7SKowalski, Kamil             "xyz.openbmc_project.Object.Delete", "Delete");
631179db1d7SKowalski, Kamil     }
632179db1d7SKowalski, Kamil 
633179db1d7SKowalski, Kamil     /**
634179db1d7SKowalski, Kamil      * @brief Creates IPv4 with given data
635179db1d7SKowalski, Kamil      *
636179db1d7SKowalski, Kamil      * @param[in] ifaceId     Id of interface whose IP should be deleted
63755c7b7a2SEd Tanous      * @param[in] ipIdx       index of IP in input array that should be deleted
638179db1d7SKowalski, Kamil      * @param[in] ipHash      DBus Hash id of IP that should be deleted
639179db1d7SKowalski, Kamil      * @param[io] asyncResp   Response object that will be returned to client
640179db1d7SKowalski, Kamil      *
641179db1d7SKowalski, Kamil      * @return None
642179db1d7SKowalski, Kamil      */
643179db1d7SKowalski, Kamil     void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
644179db1d7SKowalski, Kamil                     uint8_t subnetMask, const std::string &gateway,
645179db1d7SKowalski, Kamil                     const std::string &address,
646*1abe55efSEd Tanous                     const std::shared_ptr<AsyncResp> &asyncResp)
647*1abe55efSEd Tanous     {
648*1abe55efSEd Tanous         auto createIpHandler = [ipIdx{std::move(ipIdx)},
649*1abe55efSEd Tanous                                 asyncResp{std::move(asyncResp)}](
650*1abe55efSEd Tanous                                    const boost::system::error_code ec) {
651*1abe55efSEd Tanous             if (ec)
652*1abe55efSEd Tanous             {
653179db1d7SKowalski, Kamil                 messages::addMessageToJson(
65455c7b7a2SEd Tanous                     asyncResp->res.jsonValue, messages::internalError(),
655179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
656179db1d7SKowalski, Kamil             }
657179db1d7SKowalski, Kamil         };
658179db1d7SKowalski, Kamil 
65955c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
660179db1d7SKowalski, Kamil             std::move(createIpHandler), "xyz.openbmc_project.Network",
661179db1d7SKowalski, Kamil             "/xyz/openbmc_project/network/" + ifaceId,
662179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network.IP.Create", "IP",
663179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
664179db1d7SKowalski, Kamil             gateway);
665179db1d7SKowalski, Kamil     }
666179db1d7SKowalski, Kamil 
667179db1d7SKowalski, Kamil     /**
668179db1d7SKowalski, Kamil      * @brief Translates Address Origin value from D-Bus to Redfish format and
669179db1d7SKowalski, Kamil      *        vice-versa
670179db1d7SKowalski, Kamil      *
671179db1d7SKowalski, Kamil      * @param[in] inputOrigin Input value that should be translated
672179db1d7SKowalski, Kamil      * @param[in] isIPv4      True for IPv4 origins, False for IPv6
673*1abe55efSEd Tanous      * @param[in] isFromDBus  True for DBus->Redfish conversion, false for
674*1abe55efSEd Tanous      * reverse
675179db1d7SKowalski, Kamil      *
676179db1d7SKowalski, Kamil      * @return Empty string in case of failure, translated value otherwise
677179db1d7SKowalski, Kamil      */
678179db1d7SKowalski, Kamil     std::string translateAddressOriginBetweenDBusAndRedfish(
679*1abe55efSEd Tanous         const std::string *inputOrigin, bool isIPv4, bool isFromDBus)
680*1abe55efSEd Tanous     {
681179db1d7SKowalski, Kamil         // Invalid pointer
682*1abe55efSEd Tanous         if (inputOrigin == nullptr)
683*1abe55efSEd Tanous         {
684179db1d7SKowalski, Kamil             return "";
685179db1d7SKowalski, Kamil         }
686179db1d7SKowalski, Kamil 
687179db1d7SKowalski, Kamil         static const constexpr unsigned int firstIPv4OnlyIdx = 1;
688179db1d7SKowalski, Kamil         static const constexpr unsigned int firstIPv6OnlyIdx = 3;
689179db1d7SKowalski, Kamil 
690179db1d7SKowalski, Kamil         std::array<std::pair<const char *, const char *>, 6> translationTable{
691179db1d7SKowalski, Kamil             {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"},
692179db1d7SKowalski, Kamil              {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"},
693179db1d7SKowalski, Kamil              {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
694179db1d7SKowalski, Kamil               "IPv4LinkLocal"},
695179db1d7SKowalski, Kamil              {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"},
696179db1d7SKowalski, Kamil              {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
697179db1d7SKowalski, Kamil               "LinkLocal"},
698179db1d7SKowalski, Kamil              {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}};
699179db1d7SKowalski, Kamil 
700*1abe55efSEd Tanous         for (unsigned int i = 0; i < translationTable.size(); i++)
701*1abe55efSEd Tanous         {
702179db1d7SKowalski, Kamil             // Skip unrelated
703*1abe55efSEd Tanous             if (isIPv4 && i >= firstIPv6OnlyIdx)
704*1abe55efSEd Tanous                 break;
705*1abe55efSEd Tanous             if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx)
706*1abe55efSEd Tanous                 continue;
707179db1d7SKowalski, Kamil 
708179db1d7SKowalski, Kamil             // When translating D-Bus to Redfish compare input to first element
709179db1d7SKowalski, Kamil             if (isFromDBus && translationTable[i].first == *inputOrigin)
710179db1d7SKowalski, Kamil                 return translationTable[i].second;
711179db1d7SKowalski, Kamil 
712179db1d7SKowalski, Kamil             // When translating Redfish to D-Bus compare input to second element
713179db1d7SKowalski, Kamil             if (!isFromDBus && translationTable[i].second == *inputOrigin)
714179db1d7SKowalski, Kamil                 return translationTable[i].first;
715179db1d7SKowalski, Kamil         }
716179db1d7SKowalski, Kamil 
717179db1d7SKowalski, Kamil         // If we are still here, that means that value has not been found
718179db1d7SKowalski, Kamil         return "";
719179db1d7SKowalski, Kamil     }
720179db1d7SKowalski, Kamil 
721179db1d7SKowalski, Kamil     /**
722179db1d7SKowalski, Kamil      * Function that retrieves all properties for given Ethernet Interface
723179db1d7SKowalski, Kamil      * Object
724179db1d7SKowalski, Kamil      * from EntityManager Network Manager
72555c7b7a2SEd Tanous      * @param ethifaceId a eth interface id to query on DBus
726179db1d7SKowalski, Kamil      * @param callback a function that shall be called to convert Dbus output
727179db1d7SKowalski, Kamil      * into JSON
728179db1d7SKowalski, Kamil      */
729179db1d7SKowalski, Kamil     template <typename CallbackFunc>
73055c7b7a2SEd Tanous     void getEthernetIfaceData(const std::string &ethifaceId,
731*1abe55efSEd Tanous                               CallbackFunc &&callback)
732*1abe55efSEd Tanous     {
73355c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
734*1abe55efSEd Tanous             [this, ethifaceId{std::move(ethifaceId)},
735*1abe55efSEd Tanous              callback{std::move(callback)}](
736*1abe55efSEd Tanous                 const boost::system::error_code error_code,
737179db1d7SKowalski, Kamil                 const GetManagedObjectsType &resp) {
73855c7b7a2SEd Tanous                 EthernetInterfaceData ethData{};
73955c7b7a2SEd Tanous                 std::vector<IPv4AddressData> ipv4Data;
74055c7b7a2SEd Tanous                 ipv4Data.reserve(maxIpV4AddressesPerInterface);
741179db1d7SKowalski, Kamil 
742*1abe55efSEd Tanous                 if (error_code)
743*1abe55efSEd Tanous                 {
744*1abe55efSEd Tanous                     // Something wrong on DBus, the error_code is not important
745*1abe55efSEd Tanous                     // at this moment, just return success=false, and empty
746*1abe55efSEd Tanous                     // output. Since size of vector may vary depending on
747*1abe55efSEd Tanous                     // information from Network Manager, and empty output could
748*1abe55efSEd Tanous                     // not be treated same way as error.
74955c7b7a2SEd Tanous                     callback(false, ethData, ipv4Data);
750179db1d7SKowalski, Kamil                     return;
751179db1d7SKowalski, Kamil                 }
752179db1d7SKowalski, Kamil 
753927a505aSKowalski, Kamil                 // Find interface
75455c7b7a2SEd Tanous                 if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) ==
755*1abe55efSEd Tanous                     resp.end())
756*1abe55efSEd Tanous                 {
757927a505aSKowalski, Kamil                     // Interface has not been found
75855c7b7a2SEd Tanous                     callback(false, ethData, ipv4Data);
759927a505aSKowalski, Kamil                     return;
760927a505aSKowalski, Kamil                 }
761927a505aSKowalski, Kamil 
76255c7b7a2SEd Tanous                 extractEthernetInterfaceData(ethifaceId, resp, ethData);
76355c7b7a2SEd Tanous                 extractIPv4Data(ethifaceId, resp, ipv4Data);
764179db1d7SKowalski, Kamil 
765179db1d7SKowalski, Kamil                 // Fix global GW
766*1abe55efSEd Tanous                 for (IPv4AddressData &ipv4 : ipv4Data)
767*1abe55efSEd Tanous                 {
768*1abe55efSEd Tanous                     if ((ipv4.global) && ((ipv4.gateway == nullptr) ||
769*1abe55efSEd Tanous                                           (*ipv4.gateway == "0.0.0.0")))
770*1abe55efSEd Tanous                     {
77155c7b7a2SEd Tanous                         ipv4.gateway = ethData.defaultGateway;
772179db1d7SKowalski, Kamil                     }
773179db1d7SKowalski, Kamil                 }
774179db1d7SKowalski, Kamil 
775a434f2bdSEd Tanous                 // Finally make a callback with useful data
77655c7b7a2SEd Tanous                 callback(true, ethData, ipv4Data);
777179db1d7SKowalski, Kamil             },
778179db1d7SKowalski, Kamil             "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
779179db1d7SKowalski, Kamil             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
780179db1d7SKowalski, Kamil     };
781179db1d7SKowalski, Kamil 
782179db1d7SKowalski, Kamil     /**
7839391bb9cSRapkiewicz, Pawel      * Function that retrieves all Ethernet Interfaces available through Network
7849391bb9cSRapkiewicz, Pawel      * Manager
785*1abe55efSEd Tanous      * @param callback a function that shall be called to convert Dbus output
786*1abe55efSEd Tanous      * into JSON.
7879391bb9cSRapkiewicz, Pawel      */
7889391bb9cSRapkiewicz, Pawel     template <typename CallbackFunc>
789*1abe55efSEd Tanous     void getEthernetIfaceList(CallbackFunc &&callback)
790*1abe55efSEd Tanous     {
79155c7b7a2SEd Tanous         crow::connections::systemBus->async_method_call(
7929391bb9cSRapkiewicz, Pawel             [this, callback{std::move(callback)}](
7939391bb9cSRapkiewicz, Pawel                 const boost::system::error_code error_code,
794aa2e59c1SEd Tanous                 GetManagedObjectsType &resp) {
795*1abe55efSEd Tanous                 // Callback requires vector<string> to retrieve all available
796*1abe55efSEd Tanous                 // ethernet interfaces
79755c7b7a2SEd Tanous                 std::vector<std::string> ifaceList;
79855c7b7a2SEd Tanous                 ifaceList.reserve(resp.size());
799*1abe55efSEd Tanous                 if (error_code)
800*1abe55efSEd Tanous                 {
801*1abe55efSEd Tanous                     // Something wrong on DBus, the error_code is not important
802*1abe55efSEd Tanous                     // at this moment, just return success=false, and empty
803*1abe55efSEd Tanous                     // output. Since size of vector may vary depending on
804*1abe55efSEd Tanous                     // information from Network Manager, and empty output could
805*1abe55efSEd Tanous                     // not be treated same way as error.
80655c7b7a2SEd Tanous                     callback(false, ifaceList);
8079391bb9cSRapkiewicz, Pawel                     return;
8089391bb9cSRapkiewicz, Pawel                 }
8099391bb9cSRapkiewicz, Pawel 
8109391bb9cSRapkiewicz, Pawel                 // Iterate over all retrieved ObjectPaths.
811*1abe55efSEd Tanous                 for (auto &objpath : resp)
812*1abe55efSEd Tanous                 {
8139391bb9cSRapkiewicz, Pawel                     // And all interfaces available for certain ObjectPath.
814*1abe55efSEd Tanous                     for (auto &interface : objpath.second)
815*1abe55efSEd Tanous                     {
816*1abe55efSEd Tanous                         // If interface is
817*1abe55efSEd Tanous                         // xyz.openbmc_project.Network.EthernetInterface, this
818*1abe55efSEd Tanous                         // is what we're looking for.
8199391bb9cSRapkiewicz, Pawel                         if (interface.first ==
820*1abe55efSEd Tanous                             "xyz.openbmc_project.Network.EthernetInterface")
821*1abe55efSEd Tanous                         {
822a434f2bdSEd Tanous                             // Cut out everything until last "/", ...
82355c7b7a2SEd Tanous                             const std::string &ifaceId =
824daf36e2eSEd Tanous                                 static_cast<const std::string &>(objpath.first);
82555c7b7a2SEd Tanous                             std::size_t lastPos = ifaceId.rfind("/");
826*1abe55efSEd Tanous                             if (lastPos != std::string::npos)
827*1abe55efSEd Tanous                             {
8289391bb9cSRapkiewicz, Pawel                                 // and put it into output vector.
829*1abe55efSEd Tanous                                 ifaceList.emplace_back(
830*1abe55efSEd Tanous                                     ifaceId.substr(lastPos + 1));
8319391bb9cSRapkiewicz, Pawel                             }
8329391bb9cSRapkiewicz, Pawel                         }
8339391bb9cSRapkiewicz, Pawel                     }
8349391bb9cSRapkiewicz, Pawel                 }
835a434f2bdSEd Tanous                 // Finally make a callback with useful data
83655c7b7a2SEd Tanous                 callback(true, ifaceList);
8379391bb9cSRapkiewicz, Pawel             },
838aa2e59c1SEd Tanous             "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
839aa2e59c1SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
8409391bb9cSRapkiewicz, Pawel     };
8419391bb9cSRapkiewicz, Pawel };
8429391bb9cSRapkiewicz, Pawel 
8439391bb9cSRapkiewicz, Pawel /**
8449391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
8459391bb9cSRapkiewicz, Pawel  */
846*1abe55efSEd Tanous class EthernetCollection : public Node
847*1abe55efSEd Tanous {
8489391bb9cSRapkiewicz, Pawel   public:
849*1abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
850*1abe55efSEd Tanous     // one manager called openbmc This shall be generic, but requires to update
8519391bb9cSRapkiewicz, Pawel     // GetSubroutes method
852*1abe55efSEd Tanous     EthernetCollection(CrowApp &app) :
853*1abe55efSEd Tanous         Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/")
854*1abe55efSEd Tanous     {
8559391bb9cSRapkiewicz, Pawel         Node::json["@odata.type"] =
8569391bb9cSRapkiewicz, Pawel             "#EthernetInterfaceCollection.EthernetInterfaceCollection";
8579391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
8589391bb9cSRapkiewicz, Pawel             "/redfish/v1/"
8599391bb9cSRapkiewicz, Pawel             "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
860*1abe55efSEd Tanous         Node::json["@odata.id"] =
861*1abe55efSEd Tanous             "/redfish/v1/Managers/openbmc/EthernetInterfaces";
8629391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Ethernet Network Interface Collection";
8639391bb9cSRapkiewicz, Pawel         Node::json["Description"] =
8649391bb9cSRapkiewicz, Pawel             "Collection of EthernetInterfaces for this Manager";
8659391bb9cSRapkiewicz, Pawel 
866588c3f0dSKowalski, Kamil         entityPrivileges = {
867588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
868e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
869e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
870e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
871e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
872e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
8739391bb9cSRapkiewicz, Pawel     }
8749391bb9cSRapkiewicz, Pawel 
8759391bb9cSRapkiewicz, Pawel   private:
8769391bb9cSRapkiewicz, Pawel     /**
8779391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
8789391bb9cSRapkiewicz, Pawel      */
87955c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
880*1abe55efSEd Tanous                const std::vector<std::string> &params) override
881*1abe55efSEd Tanous     {
882*1abe55efSEd Tanous         // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
883*1abe55efSEd Tanous         // for any Manager, not only hardcoded 'openbmc'.
88455c7b7a2SEd Tanous         std::string managerId = "openbmc";
8859391bb9cSRapkiewicz, Pawel 
886*1abe55efSEd Tanous         // get eth interface list, and call the below callback for JSON
887*1abe55efSEd Tanous         // preparation
888*1abe55efSEd Tanous         ethernetProvider.getEthernetIfaceList(
889*1abe55efSEd Tanous             [&, managerId{std::move(managerId)}](
890*1abe55efSEd Tanous                 const bool &success,
891*1abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
892*1abe55efSEd Tanous                 if (success)
893*1abe55efSEd Tanous                 {
89455c7b7a2SEd Tanous                     nlohmann::json ifaceArray = nlohmann::json::array();
895*1abe55efSEd Tanous                     for (const std::string &ifaceItem : iface_list)
896*1abe55efSEd Tanous                     {
89755c7b7a2SEd Tanous                         ifaceArray.push_back(
89855c7b7a2SEd Tanous                             {{"@odata.id", "/redfish/v1/Managers/" + managerId +
899*1abe55efSEd Tanous                                                "/EthernetInterfaces/" +
900*1abe55efSEd Tanous                                                ifaceItem}});
9019391bb9cSRapkiewicz, Pawel                     }
90255c7b7a2SEd Tanous                     Node::json["Members"] = ifaceArray;
90355c7b7a2SEd Tanous                     Node::json["Members@odata.count"] = ifaceArray.size();
904*1abe55efSEd Tanous                     Node::json["@odata.id"] = "/redfish/v1/Managers/" +
905*1abe55efSEd Tanous                                               managerId + "/EthernetInterfaces";
90655c7b7a2SEd Tanous                     res.jsonValue = Node::json;
907*1abe55efSEd Tanous                 }
908*1abe55efSEd Tanous                 else
909*1abe55efSEd Tanous                 {
9109391bb9cSRapkiewicz, Pawel                     // No success, best what we can do is return INTERNALL ERROR
911*1abe55efSEd Tanous                     res.result(
912*1abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
9139391bb9cSRapkiewicz, Pawel                 }
9149391bb9cSRapkiewicz, Pawel                 res.end();
9159391bb9cSRapkiewicz, Pawel             });
9169391bb9cSRapkiewicz, Pawel     }
9179391bb9cSRapkiewicz, Pawel 
9189391bb9cSRapkiewicz, Pawel     // Ethernet Provider object
9199391bb9cSRapkiewicz, Pawel     // TODO(Pawel) consider move it to singleton
92055c7b7a2SEd Tanous     OnDemandEthernetProvider ethernetProvider;
9219391bb9cSRapkiewicz, Pawel };
9229391bb9cSRapkiewicz, Pawel 
9239391bb9cSRapkiewicz, Pawel /**
9249391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
9259391bb9cSRapkiewicz, Pawel  */
926*1abe55efSEd Tanous class EthernetInterface : public Node
927*1abe55efSEd Tanous {
9289391bb9cSRapkiewicz, Pawel   public:
9299391bb9cSRapkiewicz, Pawel     /*
9309391bb9cSRapkiewicz, Pawel      * Default Constructor
9319391bb9cSRapkiewicz, Pawel      */
932*1abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
933*1abe55efSEd Tanous     // one manager called openbmc This shall be generic, but requires to update
9349391bb9cSRapkiewicz, Pawel     // GetSubroutes method
935*1abe55efSEd Tanous     EthernetInterface(CrowApp &app) :
936*1abe55efSEd Tanous         Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/",
937*1abe55efSEd Tanous              std::string())
938*1abe55efSEd Tanous     {
939*1abe55efSEd Tanous         Node::json["@odata.type"] =
940*1abe55efSEd Tanous             "#EthernetInterface.v1_2_0.EthernetInterface";
9419391bb9cSRapkiewicz, Pawel         Node::json["@odata.context"] =
9429391bb9cSRapkiewicz, Pawel             "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
9439391bb9cSRapkiewicz, Pawel         Node::json["Name"] = "Manager Ethernet Interface";
9449391bb9cSRapkiewicz, Pawel         Node::json["Description"] = "Management Network Interface";
9459391bb9cSRapkiewicz, Pawel 
946588c3f0dSKowalski, Kamil         entityPrivileges = {
947588c3f0dSKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
948e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
949e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
950e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
951e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
952e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
9539391bb9cSRapkiewicz, Pawel     }
9549391bb9cSRapkiewicz, Pawel 
955e439f0f8SKowalski, Kamil     // TODO(kkowalsk) Find a suitable class/namespace for this
956e439f0f8SKowalski, Kamil     static void handleVlanPatch(const std::string &ifaceId,
957e439f0f8SKowalski, Kamil                                 const nlohmann::json &input,
958588c3f0dSKowalski, Kamil                                 const EthernetInterfaceData &eth_data,
959e439f0f8SKowalski, Kamil                                 const std::string &pathPrefix,
960*1abe55efSEd Tanous                                 const std::shared_ptr<AsyncResp> &asyncResp)
961*1abe55efSEd Tanous     {
962*1abe55efSEd Tanous         if (!input.is_object())
963*1abe55efSEd Tanous         {
964588c3f0dSKowalski, Kamil             messages::addMessageToJson(
96555c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
966*1abe55efSEd Tanous                 messages::propertyValueTypeError(input.dump(), "VLAN"),
967*1abe55efSEd Tanous                 pathPrefix);
968588c3f0dSKowalski, Kamil             return;
969588c3f0dSKowalski, Kamil         }
970588c3f0dSKowalski, Kamil 
971e439f0f8SKowalski, Kamil         const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix;
972e439f0f8SKowalski, Kamil         nlohmann::json &paramsJson =
973e439f0f8SKowalski, Kamil             (pathPrefix == "/")
97455c7b7a2SEd Tanous                 ? asyncResp->res.jsonValue
975*1abe55efSEd Tanous                 : asyncResp->res
976*1abe55efSEd Tanous                       .jsonValue[nlohmann::json_pointer<nlohmann::json>(
977e439f0f8SKowalski, Kamil                           pathPrefix)];
978588c3f0dSKowalski, Kamil         bool inputVlanEnabled;
979588c3f0dSKowalski, Kamil         uint64_t inputVlanId;
980e439f0f8SKowalski, Kamil 
981588c3f0dSKowalski, Kamil         json_util::Result inputVlanEnabledState = json_util::getBool(
982588c3f0dSKowalski, Kamil             "VLANEnable", input, inputVlanEnabled,
983588c3f0dSKowalski, Kamil             static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
98455c7b7a2SEd Tanous             asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable"));
985588c3f0dSKowalski, Kamil         json_util::Result inputVlanIdState = json_util::getUnsigned(
986588c3f0dSKowalski, Kamil             "VLANId", input, inputVlanId,
987588c3f0dSKowalski, Kamil             static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
98855c7b7a2SEd Tanous             asyncResp->res.jsonValue, std::string(pathStart + "/VLANId"));
989588c3f0dSKowalski, Kamil         bool inputInvalid = false;
990588c3f0dSKowalski, Kamil 
991588c3f0dSKowalski, Kamil         // Do not proceed if fields in VLAN object were of wrong type
992588c3f0dSKowalski, Kamil         if (inputVlanEnabledState == json_util::Result::WRONG_TYPE ||
993*1abe55efSEd Tanous             inputVlanIdState == json_util::Result::WRONG_TYPE)
994*1abe55efSEd Tanous         {
995588c3f0dSKowalski, Kamil             return;
996588c3f0dSKowalski, Kamil         }
997588c3f0dSKowalski, Kamil 
998588c3f0dSKowalski, Kamil         // Verify input
999*1abe55efSEd Tanous         if (eth_data.vlanId == nullptr)
1000*1abe55efSEd Tanous         {
1001e439f0f8SKowalski, Kamil             // This interface is not a VLAN. Cannot do anything with it
1002e439f0f8SKowalski, Kamil             // TODO(kkowalsk) Change this message
100355c7b7a2SEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
1004588c3f0dSKowalski, Kamil                                        messages::propertyMissing("VLANEnable"),
1005e439f0f8SKowalski, Kamil                                        pathPrefix);
1006588c3f0dSKowalski, Kamil 
1007588c3f0dSKowalski, Kamil             inputInvalid = true;
1008*1abe55efSEd Tanous         }
1009*1abe55efSEd Tanous         else
1010*1abe55efSEd Tanous         {
1011588c3f0dSKowalski, Kamil             // Load actual data into field values if they were not provided
1012*1abe55efSEd Tanous             if (inputVlanEnabledState == json_util::Result::NOT_EXIST)
1013*1abe55efSEd Tanous             {
1014588c3f0dSKowalski, Kamil                 inputVlanEnabled = true;
1015588c3f0dSKowalski, Kamil             }
1016588c3f0dSKowalski, Kamil 
1017*1abe55efSEd Tanous             if (inputVlanIdState == json_util::Result::NOT_EXIST)
1018*1abe55efSEd Tanous             {
101955c7b7a2SEd Tanous                 inputVlanId = *eth_data.vlanId;
1020588c3f0dSKowalski, Kamil             }
1021588c3f0dSKowalski, Kamil         }
1022588c3f0dSKowalski, Kamil 
1023588c3f0dSKowalski, Kamil         // Do not proceed if input has not been valid
1024*1abe55efSEd Tanous         if (inputInvalid)
1025*1abe55efSEd Tanous         {
1026588c3f0dSKowalski, Kamil             return;
1027588c3f0dSKowalski, Kamil         }
1028588c3f0dSKowalski, Kamil 
1029588c3f0dSKowalski, Kamil         // VLAN is configured on the interface
1030*1abe55efSEd Tanous         if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId)
1031*1abe55efSEd Tanous         {
1032588c3f0dSKowalski, Kamil             // Change VLAN Id
1033e439f0f8SKowalski, Kamil             paramsJson["VLANId"] = inputVlanId;
1034e439f0f8SKowalski, Kamil             OnDemandEthernetProvider::changeVlanId(
1035e439f0f8SKowalski, Kamil                 ifaceId, static_cast<uint32_t>(inputVlanId),
1036e439f0f8SKowalski, Kamil                 [&, asyncResp, pathPrefx{std::move(pathPrefix)}](
1037e439f0f8SKowalski, Kamil                     const boost::system::error_code ec) {
1038*1abe55efSEd Tanous                     if (ec)
1039*1abe55efSEd Tanous                     {
104055c7b7a2SEd Tanous                         messages::addMessageToJson(asyncResp->res.jsonValue,
1041*1abe55efSEd Tanous                                                    messages::internalError(),
1042*1abe55efSEd Tanous                                                    pathPrefix);
1043*1abe55efSEd Tanous                     }
1044*1abe55efSEd Tanous                     else
1045*1abe55efSEd Tanous                     {
1046e439f0f8SKowalski, Kamil                         paramsJson["VLANEnable"] = true;
1047e439f0f8SKowalski, Kamil                     }
1048e439f0f8SKowalski, Kamil                 });
1049*1abe55efSEd Tanous         }
1050*1abe55efSEd Tanous         else if (inputVlanEnabled == false)
1051*1abe55efSEd Tanous         {
1052e439f0f8SKowalski, Kamil             // Disable VLAN
1053e439f0f8SKowalski, Kamil             OnDemandEthernetProvider::disableVlan(
1054e439f0f8SKowalski, Kamil                 ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)}](
1055e439f0f8SKowalski, Kamil                              const boost::system::error_code ec) {
1056*1abe55efSEd Tanous                     if (ec)
1057*1abe55efSEd Tanous                     {
105855c7b7a2SEd Tanous                         messages::addMessageToJson(asyncResp->res.jsonValue,
1059*1abe55efSEd Tanous                                                    messages::internalError(),
1060*1abe55efSEd Tanous                                                    pathPrefix);
1061*1abe55efSEd Tanous                     }
1062*1abe55efSEd Tanous                     else
1063*1abe55efSEd Tanous                     {
1064e439f0f8SKowalski, Kamil                         paramsJson["VLANEnable"] = false;
1065588c3f0dSKowalski, Kamil                     }
1066588c3f0dSKowalski, Kamil                 });
1067588c3f0dSKowalski, Kamil         }
1068588c3f0dSKowalski, Kamil     }
1069588c3f0dSKowalski, Kamil 
1070e439f0f8SKowalski, Kamil   private:
1071588c3f0dSKowalski, Kamil     void handleHostnamePatch(const nlohmann::json &input,
1072588c3f0dSKowalski, Kamil                              const EthernetInterfaceData &eth_data,
1073*1abe55efSEd Tanous                              const std::shared_ptr<AsyncResp> &asyncResp)
1074*1abe55efSEd Tanous     {
1075*1abe55efSEd Tanous         if (input.is_string())
1076*1abe55efSEd Tanous         {
1077588c3f0dSKowalski, Kamil             std::string newHostname = input.get<std::string>();
1078588c3f0dSKowalski, Kamil 
1079*1abe55efSEd Tanous             if (eth_data.hostname == nullptr ||
1080*1abe55efSEd Tanous                 newHostname != *eth_data.hostname)
1081*1abe55efSEd Tanous             {
1082588c3f0dSKowalski, Kamil                 // Change hostname
108355c7b7a2SEd Tanous                 ethernetProvider.setHostName(
1084*1abe55efSEd Tanous                     newHostname, [asyncResp, newHostname](
1085*1abe55efSEd Tanous                                      const boost::system::error_code ec) {
1086*1abe55efSEd Tanous                         if (ec)
1087*1abe55efSEd Tanous                         {
1088*1abe55efSEd Tanous                             messages::addMessageToJson(
1089*1abe55efSEd Tanous                                 asyncResp->res.jsonValue,
1090*1abe55efSEd Tanous                                 messages::internalError(), "/HostName");
1091*1abe55efSEd Tanous                         }
1092*1abe55efSEd Tanous                         else
1093*1abe55efSEd Tanous                         {
109455c7b7a2SEd Tanous                             asyncResp->res.jsonValue["HostName"] = newHostname;
1095588c3f0dSKowalski, Kamil                         }
1096588c3f0dSKowalski, Kamil                     });
1097588c3f0dSKowalski, Kamil             }
1098*1abe55efSEd Tanous         }
1099*1abe55efSEd Tanous         else
1100*1abe55efSEd Tanous         {
1101588c3f0dSKowalski, Kamil             messages::addMessageToJson(
110255c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1103588c3f0dSKowalski, Kamil                 messages::propertyValueTypeError(input.dump(), "HostName"),
1104588c3f0dSKowalski, Kamil                 "/HostName");
1105588c3f0dSKowalski, Kamil         }
1106588c3f0dSKowalski, Kamil     }
1107588c3f0dSKowalski, Kamil 
1108*1abe55efSEd Tanous     void handleIPv4Patch(const std::string &ifaceId,
1109*1abe55efSEd Tanous                          const nlohmann::json &input,
1110179db1d7SKowalski, Kamil                          const std::vector<IPv4AddressData> &ipv4_data,
1111*1abe55efSEd Tanous                          const std::shared_ptr<AsyncResp> &asyncResp)
1112*1abe55efSEd Tanous     {
1113*1abe55efSEd Tanous         if (!input.is_array())
1114*1abe55efSEd Tanous         {
1115179db1d7SKowalski, Kamil             messages::addMessageToJson(
111655c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1117179db1d7SKowalski, Kamil                 messages::propertyValueTypeError(input.dump(), "IPv4Addresses"),
1118179db1d7SKowalski, Kamil                 "/IPv4Addresses");
1119179db1d7SKowalski, Kamil             return;
1120179db1d7SKowalski, Kamil         }
1121179db1d7SKowalski, Kamil 
1122179db1d7SKowalski, Kamil         // According to Redfish PATCH definition, size must be at least equal
1123*1abe55efSEd Tanous         if (input.size() < ipv4_data.size())
1124*1abe55efSEd Tanous         {
1125*1abe55efSEd Tanous             // TODO(kkowalsk) This should be a message indicating that not
1126*1abe55efSEd Tanous             // enough data has been provided
112755c7b7a2SEd Tanous             messages::addMessageToJson(asyncResp->res.jsonValue,
1128*1abe55efSEd Tanous                                        messages::internalError(),
1129*1abe55efSEd Tanous                                        "/IPv4Addresses");
1130179db1d7SKowalski, Kamil             return;
1131179db1d7SKowalski, Kamil         }
1132179db1d7SKowalski, Kamil 
1133179db1d7SKowalski, Kamil         json_util::Result addressFieldState;
1134179db1d7SKowalski, Kamil         json_util::Result subnetMaskFieldState;
1135179db1d7SKowalski, Kamil         json_util::Result addressOriginFieldState;
1136179db1d7SKowalski, Kamil         json_util::Result gatewayFieldState;
1137179db1d7SKowalski, Kamil         const std::string *addressFieldValue;
1138179db1d7SKowalski, Kamil         const std::string *subnetMaskFieldValue;
1139179db1d7SKowalski, Kamil         const std::string *addressOriginFieldValue = nullptr;
1140179db1d7SKowalski, Kamil         const std::string *gatewayFieldValue;
1141179db1d7SKowalski, Kamil         uint8_t subnetMaskAsPrefixLength;
1142179db1d7SKowalski, Kamil         std::string addressOriginInDBusFormat;
1143179db1d7SKowalski, Kamil 
1144179db1d7SKowalski, Kamil         bool errorDetected = false;
1145*1abe55efSEd Tanous         for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++)
1146*1abe55efSEd Tanous         {
1147179db1d7SKowalski, Kamil             // Check that entry is not of some unexpected type
1148*1abe55efSEd Tanous             if (!input[entryIdx].is_object() && !input[entryIdx].is_null())
1149*1abe55efSEd Tanous             {
1150179db1d7SKowalski, Kamil                 // Invalid object type
1151179db1d7SKowalski, Kamil                 messages::addMessageToJson(
115255c7b7a2SEd Tanous                     asyncResp->res.jsonValue,
1153179db1d7SKowalski, Kamil                     messages::propertyValueTypeError(input[entryIdx].dump(),
1154179db1d7SKowalski, Kamil                                                      "IPv4Address"),
1155179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(entryIdx));
1156179db1d7SKowalski, Kamil 
1157179db1d7SKowalski, Kamil                 continue;
1158179db1d7SKowalski, Kamil             }
1159179db1d7SKowalski, Kamil 
1160179db1d7SKowalski, Kamil             // Try to load fields
1161179db1d7SKowalski, Kamil             addressFieldState = json_util::getString(
1162179db1d7SKowalski, Kamil                 "Address", input[entryIdx], addressFieldValue,
1163179db1d7SKowalski, Kamil                 static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
116455c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1165179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
1166179db1d7SKowalski, Kamil             subnetMaskFieldState = json_util::getString(
1167179db1d7SKowalski, Kamil                 "SubnetMask", input[entryIdx], subnetMaskFieldValue,
1168179db1d7SKowalski, Kamil                 static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
116955c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1170179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask");
1171179db1d7SKowalski, Kamil             addressOriginFieldState = json_util::getString(
1172179db1d7SKowalski, Kamil                 "AddressOrigin", input[entryIdx], addressOriginFieldValue,
1173179db1d7SKowalski, Kamil                 static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
117455c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1175*1abe55efSEd Tanous                 "/IPv4Addresses/" + std::to_string(entryIdx) +
1176*1abe55efSEd Tanous                     "/AddressOrigin");
1177179db1d7SKowalski, Kamil             gatewayFieldState = json_util::getString(
1178179db1d7SKowalski, Kamil                 "Gateway", input[entryIdx], gatewayFieldValue,
1179179db1d7SKowalski, Kamil                 static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
118055c7b7a2SEd Tanous                 asyncResp->res.jsonValue,
1181179db1d7SKowalski, Kamil                 "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
1182179db1d7SKowalski, Kamil 
1183179db1d7SKowalski, Kamil             if (addressFieldState == json_util::Result::WRONG_TYPE ||
1184179db1d7SKowalski, Kamil                 subnetMaskFieldState == json_util::Result::WRONG_TYPE ||
1185179db1d7SKowalski, Kamil                 addressOriginFieldState == json_util::Result::WRONG_TYPE ||
1186*1abe55efSEd Tanous                 gatewayFieldState == json_util::Result::WRONG_TYPE)
1187*1abe55efSEd Tanous             {
1188179db1d7SKowalski, Kamil                 return;
1189179db1d7SKowalski, Kamil             }
1190179db1d7SKowalski, Kamil 
1191179db1d7SKowalski, Kamil             if (addressFieldState == json_util::Result::SUCCESS &&
1192*1abe55efSEd Tanous                 !ethernetProvider.ipv4VerifyIpAndGetBitcount(
1193*1abe55efSEd Tanous                     *addressFieldValue))
1194*1abe55efSEd Tanous             {
1195179db1d7SKowalski, Kamil                 errorDetected = true;
1196179db1d7SKowalski, Kamil                 messages::addMessageToJson(
119755c7b7a2SEd Tanous                     asyncResp->res.jsonValue,
1198*1abe55efSEd Tanous                     messages::propertyValueFormatError(*addressFieldValue,
1199*1abe55efSEd Tanous                                                        "Address"),
1200179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
1201179db1d7SKowalski, Kamil             }
1202179db1d7SKowalski, Kamil 
1203179db1d7SKowalski, Kamil             if (subnetMaskFieldState == json_util::Result::SUCCESS &&
120455c7b7a2SEd Tanous                 !ethernetProvider.ipv4VerifyIpAndGetBitcount(
1205*1abe55efSEd Tanous                     *subnetMaskFieldValue, &subnetMaskAsPrefixLength))
1206*1abe55efSEd Tanous             {
1207179db1d7SKowalski, Kamil                 errorDetected = true;
1208179db1d7SKowalski, Kamil                 messages::addMessageToJson(
120955c7b7a2SEd Tanous                     asyncResp->res.jsonValue,
1210179db1d7SKowalski, Kamil                     messages::propertyValueFormatError(*subnetMaskFieldValue,
1211179db1d7SKowalski, Kamil                                                        "SubnetMask"),
1212*1abe55efSEd Tanous                     "/IPv4Addresses/" + std::to_string(entryIdx) +
1213*1abe55efSEd Tanous                         "/SubnetMask");
1214179db1d7SKowalski, Kamil             }
1215179db1d7SKowalski, Kamil 
121655c7b7a2SEd Tanous             // get Address origin in proper format
1217179db1d7SKowalski, Kamil             addressOriginInDBusFormat =
121855c7b7a2SEd Tanous                 ethernetProvider.translateAddressOriginBetweenDBusAndRedfish(
1219179db1d7SKowalski, Kamil                     addressOriginFieldValue, true, false);
1220179db1d7SKowalski, Kamil 
1221179db1d7SKowalski, Kamil             if (addressOriginFieldState == json_util::Result::SUCCESS &&
1222*1abe55efSEd Tanous                 addressOriginInDBusFormat.empty())
1223*1abe55efSEd Tanous             {
1224179db1d7SKowalski, Kamil                 errorDetected = true;
1225179db1d7SKowalski, Kamil                 messages::addMessageToJson(
122655c7b7a2SEd Tanous                     asyncResp->res.jsonValue,
1227179db1d7SKowalski, Kamil                     messages::propertyValueNotInList(*addressOriginFieldValue,
1228179db1d7SKowalski, Kamil                                                      "AddressOrigin"),
1229*1abe55efSEd Tanous                     "/IPv4Addresses/" + std::to_string(entryIdx) +
1230*1abe55efSEd Tanous                         "/AddressOrigin");
1231179db1d7SKowalski, Kamil             }
1232179db1d7SKowalski, Kamil 
1233179db1d7SKowalski, Kamil             if (gatewayFieldState == json_util::Result::SUCCESS &&
1234*1abe55efSEd Tanous                 !ethernetProvider.ipv4VerifyIpAndGetBitcount(
1235*1abe55efSEd Tanous                     *gatewayFieldValue))
1236*1abe55efSEd Tanous             {
1237179db1d7SKowalski, Kamil                 errorDetected = true;
1238179db1d7SKowalski, Kamil                 messages::addMessageToJson(
123955c7b7a2SEd Tanous                     asyncResp->res.jsonValue,
1240*1abe55efSEd Tanous                     messages::propertyValueFormatError(*gatewayFieldValue,
1241*1abe55efSEd Tanous                                                        "Gateway"),
1242179db1d7SKowalski, Kamil                     "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
1243179db1d7SKowalski, Kamil             }
1244179db1d7SKowalski, Kamil 
1245*1abe55efSEd Tanous             // If any error occured do not proceed with current entry, but do
1246*1abe55efSEd Tanous             // not end loop
1247*1abe55efSEd Tanous             if (errorDetected)
1248*1abe55efSEd Tanous             {
1249179db1d7SKowalski, Kamil                 errorDetected = false;
1250179db1d7SKowalski, Kamil                 continue;
1251179db1d7SKowalski, Kamil             }
1252179db1d7SKowalski, Kamil 
1253*1abe55efSEd Tanous             if (entryIdx >= ipv4_data.size())
1254*1abe55efSEd Tanous             {
1255*1abe55efSEd Tanous                 asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
1256*1abe55efSEd Tanous                     input[entryIdx];
1257179db1d7SKowalski, Kamil 
1258179db1d7SKowalski, Kamil                 // Verify that all field were provided
1259*1abe55efSEd Tanous                 if (addressFieldState == json_util::Result::NOT_EXIST)
1260*1abe55efSEd Tanous                 {
1261179db1d7SKowalski, Kamil                     errorDetected = true;
1262179db1d7SKowalski, Kamil                     messages::addMessageToJson(
1263*1abe55efSEd Tanous                         asyncResp->res.jsonValue,
1264*1abe55efSEd Tanous                         messages::propertyMissing("Address"),
1265*1abe55efSEd Tanous                         "/IPv4Addresses/" + std::to_string(entryIdx) +
1266*1abe55efSEd Tanous                             "/Address");
1267179db1d7SKowalski, Kamil                 }
1268179db1d7SKowalski, Kamil 
1269*1abe55efSEd Tanous                 if (subnetMaskFieldState == json_util::Result::NOT_EXIST)
1270*1abe55efSEd Tanous                 {
1271179db1d7SKowalski, Kamil                     errorDetected = true;
1272179db1d7SKowalski, Kamil                     messages::addMessageToJson(
1273*1abe55efSEd Tanous                         asyncResp->res.jsonValue,
1274*1abe55efSEd Tanous                         messages::propertyMissing("SubnetMask"),
1275*1abe55efSEd Tanous                         "/IPv4Addresses/" + std::to_string(entryIdx) +
1276*1abe55efSEd Tanous                             "/SubnetMask");
1277179db1d7SKowalski, Kamil                 }
1278179db1d7SKowalski, Kamil 
1279*1abe55efSEd Tanous                 if (addressOriginFieldState == json_util::Result::NOT_EXIST)
1280*1abe55efSEd Tanous                 {
1281179db1d7SKowalski, Kamil                     errorDetected = true;
1282179db1d7SKowalski, Kamil                     messages::addMessageToJson(
128355c7b7a2SEd Tanous                         asyncResp->res.jsonValue,
1284179db1d7SKowalski, Kamil                         messages::propertyMissing("AddressOrigin"),
1285*1abe55efSEd Tanous                         "/IPv4Addresses/" + std::to_string(entryIdx) +
1286*1abe55efSEd Tanous                             "/AddressOrigin");
1287179db1d7SKowalski, Kamil                 }
1288179db1d7SKowalski, Kamil 
1289*1abe55efSEd Tanous                 if (gatewayFieldState == json_util::Result::NOT_EXIST)
1290*1abe55efSEd Tanous                 {
1291179db1d7SKowalski, Kamil                     errorDetected = true;
1292179db1d7SKowalski, Kamil                     messages::addMessageToJson(
1293*1abe55efSEd Tanous                         asyncResp->res.jsonValue,
1294*1abe55efSEd Tanous                         messages::propertyMissing("Gateway"),
1295*1abe55efSEd Tanous                         "/IPv4Addresses/" + std::to_string(entryIdx) +
1296*1abe55efSEd Tanous                             "/Gateway");
1297179db1d7SKowalski, Kamil                 }
1298179db1d7SKowalski, Kamil 
1299*1abe55efSEd Tanous                 // If any error occured do not proceed with current entry, but
1300*1abe55efSEd Tanous                 // do not end loop
1301*1abe55efSEd Tanous                 if (errorDetected)
1302*1abe55efSEd Tanous                 {
1303179db1d7SKowalski, Kamil                     errorDetected = false;
1304179db1d7SKowalski, Kamil                     continue;
1305179db1d7SKowalski, Kamil                 }
1306179db1d7SKowalski, Kamil 
1307179db1d7SKowalski, Kamil                 // Create IPv4 with provided data
1308*1abe55efSEd Tanous                 ethernetProvider.createIPv4(
1309*1abe55efSEd Tanous                     ifaceId, entryIdx, subnetMaskAsPrefixLength,
1310*1abe55efSEd Tanous                     *gatewayFieldValue, *addressFieldValue, asyncResp);
1311*1abe55efSEd Tanous             }
1312*1abe55efSEd Tanous             else
1313*1abe55efSEd Tanous             {
1314*1abe55efSEd Tanous                 // Existing object that should be modified/deleted/remain
1315*1abe55efSEd Tanous                 // unchanged
1316*1abe55efSEd Tanous                 if (input[entryIdx].is_null())
1317*1abe55efSEd Tanous                 {
1318179db1d7SKowalski, Kamil                     // Object should be deleted
1319*1abe55efSEd Tanous                     ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id,
1320*1abe55efSEd Tanous                                                 entryIdx, asyncResp);
1321*1abe55efSEd Tanous                 }
1322*1abe55efSEd Tanous                 else if (input[entryIdx].is_object())
1323*1abe55efSEd Tanous                 {
1324*1abe55efSEd Tanous                     if (input[entryIdx].size() == 0)
1325*1abe55efSEd Tanous                     {
1326179db1d7SKowalski, Kamil                         // Object shall remain unchanged
1327179db1d7SKowalski, Kamil                         continue;
1328179db1d7SKowalski, Kamil                     }
1329179db1d7SKowalski, Kamil 
1330179db1d7SKowalski, Kamil                     // Apply changes
1331179db1d7SKowalski, Kamil                     if (addressFieldState == json_util::Result::SUCCESS &&
1332179db1d7SKowalski, Kamil                         ipv4_data[entryIdx].address != nullptr &&
1333*1abe55efSEd Tanous                         *ipv4_data[entryIdx].address != *addressFieldValue)
1334*1abe55efSEd Tanous                     {
133555c7b7a2SEd Tanous                         ethernetProvider.changeIPv4AddressProperty(
1336*1abe55efSEd Tanous                             ifaceId, entryIdx, ipv4_data[entryIdx].id,
1337*1abe55efSEd Tanous                             "Address", *addressFieldValue, asyncResp);
1338179db1d7SKowalski, Kamil                     }
1339179db1d7SKowalski, Kamil 
1340179db1d7SKowalski, Kamil                     if (subnetMaskFieldState == json_util::Result::SUCCESS &&
1341*1abe55efSEd Tanous                         ipv4_data[entryIdx].netmask != *subnetMaskFieldValue)
1342*1abe55efSEd Tanous                     {
134355c7b7a2SEd Tanous                         ethernetProvider.changeIPv4SubnetMaskProperty(
1344179db1d7SKowalski, Kamil                             ifaceId, entryIdx, ipv4_data[entryIdx].id,
1345*1abe55efSEd Tanous                             *subnetMaskFieldValue, subnetMaskAsPrefixLength,
1346*1abe55efSEd Tanous                             asyncResp);
1347179db1d7SKowalski, Kamil                     }
1348179db1d7SKowalski, Kamil 
1349179db1d7SKowalski, Kamil                     if (addressOriginFieldState == json_util::Result::SUCCESS &&
1350*1abe55efSEd Tanous                         ipv4_data[entryIdx].origin != *addressFieldValue)
1351*1abe55efSEd Tanous                     {
135255c7b7a2SEd Tanous                         ethernetProvider.changeIPv4Origin(
1353179db1d7SKowalski, Kamil                             ifaceId, entryIdx, ipv4_data[entryIdx].id,
1354*1abe55efSEd Tanous                             *addressOriginFieldValue, addressOriginInDBusFormat,
1355*1abe55efSEd Tanous                             asyncResp);
1356179db1d7SKowalski, Kamil                     }
1357179db1d7SKowalski, Kamil 
1358179db1d7SKowalski, Kamil                     if (gatewayFieldState == json_util::Result::SUCCESS &&
1359179db1d7SKowalski, Kamil                         ipv4_data[entryIdx].gateway != nullptr &&
1360*1abe55efSEd Tanous                         *ipv4_data[entryIdx].gateway != *gatewayFieldValue)
1361*1abe55efSEd Tanous                     {
136255c7b7a2SEd Tanous                         ethernetProvider.changeIPv4AddressProperty(
1363*1abe55efSEd Tanous                             ifaceId, entryIdx, ipv4_data[entryIdx].id,
1364*1abe55efSEd Tanous                             "Gateway", *gatewayFieldValue, asyncResp);
1365179db1d7SKowalski, Kamil                     }
1366179db1d7SKowalski, Kamil                 }
1367179db1d7SKowalski, Kamil             }
1368179db1d7SKowalski, Kamil         }
1369179db1d7SKowalski, Kamil     }
1370179db1d7SKowalski, Kamil 
1371*1abe55efSEd Tanous     nlohmann::json
1372*1abe55efSEd Tanous         parseInterfaceData(const std::string &ifaceId,
1373*1abe55efSEd Tanous                            const EthernetInterfaceData &eth_data,
1374*1abe55efSEd Tanous                            const std::vector<IPv4AddressData> &ipv4_data)
1375*1abe55efSEd Tanous     {
1376588c3f0dSKowalski, Kamil         // Copy JSON object to avoid race condition
137755c7b7a2SEd Tanous         nlohmann::json jsonResponse(Node::json);
1378588c3f0dSKowalski, Kamil 
1379588c3f0dSKowalski, Kamil         // Fill out obvious data...
138055c7b7a2SEd Tanous         jsonResponse["Id"] = ifaceId;
138155c7b7a2SEd Tanous         jsonResponse["@odata.id"] =
138255c7b7a2SEd Tanous             "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId;
1383588c3f0dSKowalski, Kamil 
1384588c3f0dSKowalski, Kamil         // ... then the one from DBus, regarding eth iface...
1385*1abe55efSEd Tanous         if (eth_data.speed != nullptr)
1386*1abe55efSEd Tanous             jsonResponse["SpeedMbps"] = *eth_data.speed;
1387588c3f0dSKowalski, Kamil 
138855c7b7a2SEd Tanous         if (eth_data.macAddress != nullptr)
138955c7b7a2SEd Tanous             jsonResponse["MACAddress"] = *eth_data.macAddress;
1390588c3f0dSKowalski, Kamil 
1391588c3f0dSKowalski, Kamil         if (eth_data.hostname != nullptr)
139255c7b7a2SEd Tanous             jsonResponse["HostName"] = *eth_data.hostname;
1393588c3f0dSKowalski, Kamil 
1394*1abe55efSEd Tanous         if (eth_data.vlanId != nullptr)
1395*1abe55efSEd Tanous         {
139655c7b7a2SEd Tanous             nlohmann::json &vlanObj = jsonResponse["VLAN"];
1397588c3f0dSKowalski, Kamil             vlanObj["VLANEnable"] = true;
139855c7b7a2SEd Tanous             vlanObj["VLANId"] = *eth_data.vlanId;
1399*1abe55efSEd Tanous         }
1400*1abe55efSEd Tanous         else
1401*1abe55efSEd Tanous         {
140255c7b7a2SEd Tanous             nlohmann::json &vlanObj = jsonResponse["VLANs"];
1403eb547730SKowalski, Kamil             vlanObj["@odata.id"] =
140455c7b7a2SEd Tanous                 "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId +
1405eb547730SKowalski, Kamil                 "/VLANs";
1406588c3f0dSKowalski, Kamil         }
1407588c3f0dSKowalski, Kamil 
1408588c3f0dSKowalski, Kamil         // ... at last, check if there are IPv4 data and prepare appropriate
1409588c3f0dSKowalski, Kamil         // collection
1410*1abe55efSEd Tanous         if (ipv4_data.size() > 0)
1411*1abe55efSEd Tanous         {
141255c7b7a2SEd Tanous             nlohmann::json ipv4Array = nlohmann::json::array();
1413*1abe55efSEd Tanous             for (auto &ipv4Config : ipv4_data)
1414*1abe55efSEd Tanous             {
141555c7b7a2SEd Tanous                 nlohmann::json jsonIpv4;
1416*1abe55efSEd Tanous                 if (ipv4Config.address != nullptr)
1417*1abe55efSEd Tanous                 {
141855c7b7a2SEd Tanous                     jsonIpv4["Address"] = *ipv4Config.address;
141955c7b7a2SEd Tanous                     if (ipv4Config.gateway != nullptr)
142055c7b7a2SEd Tanous                         jsonIpv4["Gateway"] = *ipv4Config.gateway;
1421588c3f0dSKowalski, Kamil 
142255c7b7a2SEd Tanous                     jsonIpv4["AddressOrigin"] = ipv4Config.origin;
142355c7b7a2SEd Tanous                     jsonIpv4["SubnetMask"] = ipv4Config.netmask;
1424588c3f0dSKowalski, Kamil 
142555c7b7a2SEd Tanous                     ipv4Array.push_back(std::move(jsonIpv4));
1426588c3f0dSKowalski, Kamil                 }
1427588c3f0dSKowalski, Kamil             }
142855c7b7a2SEd Tanous             jsonResponse["IPv4Addresses"] = std::move(ipv4Array);
1429588c3f0dSKowalski, Kamil         }
1430588c3f0dSKowalski, Kamil 
143155c7b7a2SEd Tanous         return jsonResponse;
1432588c3f0dSKowalski, Kamil     }
1433588c3f0dSKowalski, Kamil 
14349391bb9cSRapkiewicz, Pawel     /**
14359391bb9cSRapkiewicz, Pawel      * Functions triggers appropriate requests on DBus
14369391bb9cSRapkiewicz, Pawel      */
143755c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1438*1abe55efSEd Tanous                const std::vector<std::string> &params) override
1439*1abe55efSEd Tanous     {
14409391bb9cSRapkiewicz, Pawel         // TODO(Pawel) this shall be parametrized call (two params) to get
14419391bb9cSRapkiewicz, Pawel         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
14429391bb9cSRapkiewicz, Pawel         // Check if there is required param, truly entering this shall be
14439391bb9cSRapkiewicz, Pawel         // impossible.
1444*1abe55efSEd Tanous         if (params.size() != 1)
1445*1abe55efSEd Tanous         {
1446e0d918bcSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
14479391bb9cSRapkiewicz, Pawel             res.end();
14489391bb9cSRapkiewicz, Pawel             return;
14499391bb9cSRapkiewicz, Pawel         }
14509391bb9cSRapkiewicz, Pawel 
145155c7b7a2SEd Tanous         const std::string &ifaceId = params[0];
14529391bb9cSRapkiewicz, Pawel 
145355c7b7a2SEd Tanous         // get single eth interface data, and call the below callback for JSON
14549391bb9cSRapkiewicz, Pawel         // preparation
145555c7b7a2SEd Tanous         ethernetProvider.getEthernetIfaceData(
145655c7b7a2SEd Tanous             ifaceId,
1457*1abe55efSEd Tanous             [&, ifaceId](const bool &success,
1458*1abe55efSEd Tanous                          const EthernetInterfaceData &eth_data,
14599391bb9cSRapkiewicz, Pawel                          const std::vector<IPv4AddressData> &ipv4_data) {
1460*1abe55efSEd Tanous                 if (success)
1461*1abe55efSEd Tanous                 {
1462*1abe55efSEd Tanous                     res.jsonValue =
1463*1abe55efSEd Tanous                         parseInterfaceData(ifaceId, eth_data, ipv4_data);
1464*1abe55efSEd Tanous                 }
1465*1abe55efSEd Tanous                 else
1466*1abe55efSEd Tanous                 {
14679391bb9cSRapkiewicz, Pawel                     // ... otherwise return error
1468*1abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
1469*1abe55efSEd Tanous                     // object, and other errors
1470e439f0f8SKowalski, Kamil                     messages::addMessageToErrorJson(
1471*1abe55efSEd Tanous                         res.jsonValue, messages::resourceNotFound(
1472*1abe55efSEd Tanous                                            "EthernetInterface", ifaceId));
1473e0d918bcSEd Tanous                     res.result(boost::beast::http::status::not_found);
14749391bb9cSRapkiewicz, Pawel                 }
14759391bb9cSRapkiewicz, Pawel                 res.end();
14769391bb9cSRapkiewicz, Pawel             });
14779391bb9cSRapkiewicz, Pawel     }
14789391bb9cSRapkiewicz, Pawel 
147955c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
1480*1abe55efSEd Tanous                  const std::vector<std::string> &params) override
1481*1abe55efSEd Tanous     {
1482588c3f0dSKowalski, Kamil         // TODO(Pawel) this shall be parametrized call (two params) to get
1483588c3f0dSKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1484588c3f0dSKowalski, Kamil         // Check if there is required param, truly entering this shall be
1485588c3f0dSKowalski, Kamil         // impossible.
1486*1abe55efSEd Tanous         if (params.size() != 1)
1487*1abe55efSEd Tanous         {
1488588c3f0dSKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1489588c3f0dSKowalski, Kamil             res.end();
1490588c3f0dSKowalski, Kamil             return;
1491588c3f0dSKowalski, Kamil         }
1492588c3f0dSKowalski, Kamil 
149355c7b7a2SEd Tanous         const std::string &ifaceId = params[0];
1494588c3f0dSKowalski, Kamil 
1495179db1d7SKowalski, Kamil         nlohmann::json patchReq;
1496588c3f0dSKowalski, Kamil 
1497*1abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
1498*1abe55efSEd Tanous         {
1499588c3f0dSKowalski, Kamil             return;
1500588c3f0dSKowalski, Kamil         }
1501588c3f0dSKowalski, Kamil 
150255c7b7a2SEd Tanous         // get single eth interface data, and call the below callback for JSON
1503588c3f0dSKowalski, Kamil         // preparation
150455c7b7a2SEd Tanous         ethernetProvider.getEthernetIfaceData(
1505*1abe55efSEd Tanous             ifaceId,
1506*1abe55efSEd Tanous             [&, ifaceId, patchReq = std::move(patchReq)](
1507588c3f0dSKowalski, Kamil                 const bool &success, const EthernetInterfaceData &eth_data,
1508588c3f0dSKowalski, Kamil                 const std::vector<IPv4AddressData> &ipv4_data) {
1509*1abe55efSEd Tanous                 if (!success)
1510*1abe55efSEd Tanous                 {
1511588c3f0dSKowalski, Kamil                     // ... otherwise return error
1512*1abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
1513*1abe55efSEd Tanous                     // object, and other errors
1514927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1515*1abe55efSEd Tanous                         res.jsonValue, messages::resourceNotFound(
1516*1abe55efSEd Tanous                                            "VLAN Network Interface", ifaceId));
1517588c3f0dSKowalski, Kamil                     res.result(boost::beast::http::status::not_found);
1518588c3f0dSKowalski, Kamil                     res.end();
1519588c3f0dSKowalski, Kamil 
1520588c3f0dSKowalski, Kamil                     return;
1521588c3f0dSKowalski, Kamil                 }
1522588c3f0dSKowalski, Kamil 
1523*1abe55efSEd Tanous                 res.jsonValue =
1524*1abe55efSEd Tanous                     parseInterfaceData(ifaceId, eth_data, ipv4_data);
1525588c3f0dSKowalski, Kamil 
1526588c3f0dSKowalski, Kamil                 std::shared_ptr<AsyncResp> asyncResp =
1527588c3f0dSKowalski, Kamil                     std::make_shared<AsyncResp>(res);
1528588c3f0dSKowalski, Kamil 
1529*1abe55efSEd Tanous                 for (auto propertyIt = patchReq.begin();
1530*1abe55efSEd Tanous                      propertyIt != patchReq.end(); ++propertyIt)
1531*1abe55efSEd Tanous                 {
1532*1abe55efSEd Tanous                     if (propertyIt.key() == "VLAN")
1533*1abe55efSEd Tanous                     {
1534*1abe55efSEd Tanous                         handleVlanPatch(ifaceId, propertyIt.value(), eth_data,
1535*1abe55efSEd Tanous                                         "/VLAN", asyncResp);
1536*1abe55efSEd Tanous                     }
1537*1abe55efSEd Tanous                     else if (propertyIt.key() == "HostName")
1538*1abe55efSEd Tanous                     {
1539*1abe55efSEd Tanous                         handleHostnamePatch(propertyIt.value(), eth_data,
1540588c3f0dSKowalski, Kamil                                             asyncResp);
1541*1abe55efSEd Tanous                     }
1542*1abe55efSEd Tanous                     else if (propertyIt.key() == "IPv4Addresses")
1543*1abe55efSEd Tanous                     {
154455c7b7a2SEd Tanous                         handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data,
1545179db1d7SKowalski, Kamil                                         asyncResp);
1546*1abe55efSEd Tanous                     }
1547*1abe55efSEd Tanous                     else if (propertyIt.key() == "IPv6Addresses")
1548*1abe55efSEd Tanous                     {
1549179db1d7SKowalski, Kamil                         // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
1550179db1d7SKowalski, Kamil                         messages::addMessageToJsonRoot(
155155c7b7a2SEd Tanous                             res.jsonValue,
1552179db1d7SKowalski, Kamil                             messages::propertyNotWritable(propertyIt.key()));
1553*1abe55efSEd Tanous                     }
1554*1abe55efSEd Tanous                     else
1555*1abe55efSEd Tanous                     {
1556*1abe55efSEd Tanous                         auto fieldInJsonIt =
1557*1abe55efSEd Tanous                             res.jsonValue.find(propertyIt.key());
1558588c3f0dSKowalski, Kamil 
1559*1abe55efSEd Tanous                         if (fieldInJsonIt == res.jsonValue.end())
1560*1abe55efSEd Tanous                         {
1561588c3f0dSKowalski, Kamil                             // Field not in scope of defined fields
1562588c3f0dSKowalski, Kamil                             messages::addMessageToJsonRoot(
1563*1abe55efSEd Tanous                                 res.jsonValue,
1564*1abe55efSEd Tanous                                 messages::propertyUnknown(propertyIt.key()));
1565*1abe55efSEd Tanous                         }
1566*1abe55efSEd Tanous                         else if (*fieldInJsonIt != *propertyIt)
1567*1abe55efSEd Tanous                         {
1568588c3f0dSKowalski, Kamil                             // User attempted to modify non-writable field
1569588c3f0dSKowalski, Kamil                             messages::addMessageToJsonRoot(
1570*1abe55efSEd Tanous                                 res.jsonValue, messages::propertyNotWritable(
1571*1abe55efSEd Tanous                                                    propertyIt.key()));
1572588c3f0dSKowalski, Kamil                         }
1573588c3f0dSKowalski, Kamil                     }
1574588c3f0dSKowalski, Kamil                 }
1575588c3f0dSKowalski, Kamil             });
1576588c3f0dSKowalski, Kamil     }
1577588c3f0dSKowalski, Kamil 
15789391bb9cSRapkiewicz, Pawel     // Ethernet Provider object
15799391bb9cSRapkiewicz, Pawel     // TODO(Pawel) consider move it to singleton
158055c7b7a2SEd Tanous     OnDemandEthernetProvider ethernetProvider;
15819391bb9cSRapkiewicz, Pawel };
15829391bb9cSRapkiewicz, Pawel 
1583e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection;
1584e439f0f8SKowalski, Kamil 
1585e439f0f8SKowalski, Kamil /**
1586e439f0f8SKowalski, Kamil  * VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema
1587e439f0f8SKowalski, Kamil  */
1588*1abe55efSEd Tanous class VlanNetworkInterface : public Node
1589*1abe55efSEd Tanous {
1590e439f0f8SKowalski, Kamil   public:
1591e439f0f8SKowalski, Kamil     /*
1592e439f0f8SKowalski, Kamil      * Default Constructor
1593e439f0f8SKowalski, Kamil      */
1594e439f0f8SKowalski, Kamil     template <typename CrowApp>
1595*1abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
1596*1abe55efSEd Tanous     // one manager called openbmc This shall be generic, but requires to update
1597e439f0f8SKowalski, Kamil     // GetSubroutes method
1598*1abe55efSEd Tanous     VlanNetworkInterface(CrowApp &app) :
1599*1abe55efSEd Tanous         Node(
1600eb547730SKowalski, Kamil             app,
1601eb547730SKowalski, Kamil             "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/<str>",
1602*1abe55efSEd Tanous             std::string(), std::string())
1603*1abe55efSEd Tanous     {
1604e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1605e439f0f8SKowalski, Kamil             "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
1606e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1607e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
1608e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface";
1609e439f0f8SKowalski, Kamil 
1610e439f0f8SKowalski, Kamil         entityPrivileges = {
1611e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1612e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1613e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1614e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1615e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1616e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1617e439f0f8SKowalski, Kamil     }
1618e439f0f8SKowalski, Kamil 
1619e439f0f8SKowalski, Kamil   private:
1620*1abe55efSEd Tanous     nlohmann::json
1621*1abe55efSEd Tanous         parseInterfaceData(const std::string &parent_ifaceId,
1622*1abe55efSEd Tanous                            const std::string &ifaceId,
1623e439f0f8SKowalski, Kamil                            const EthernetInterfaceData &eth_data,
1624*1abe55efSEd Tanous                            const std::vector<IPv4AddressData> &ipv4_data)
1625*1abe55efSEd Tanous     {
1626e439f0f8SKowalski, Kamil         // Copy JSON object to avoid race condition
162755c7b7a2SEd Tanous         nlohmann::json jsonResponse(Node::json);
1628e439f0f8SKowalski, Kamil 
1629e439f0f8SKowalski, Kamil         // Fill out obvious data...
163055c7b7a2SEd Tanous         jsonResponse["Id"] = ifaceId;
163155c7b7a2SEd Tanous         jsonResponse["@odata.id"] =
1632*1abe55efSEd Tanous             "/redfish/v1/Managers/openbmc/EthernetInterfaces/" +
1633*1abe55efSEd Tanous             parent_ifaceId + "/VLANs/" + ifaceId;
1634e439f0f8SKowalski, Kamil 
163555c7b7a2SEd Tanous         jsonResponse["VLANEnable"] = true;
163655c7b7a2SEd Tanous         jsonResponse["VLANId"] = *eth_data.vlanId;
1637e439f0f8SKowalski, Kamil 
163855c7b7a2SEd Tanous         return jsonResponse;
1639e439f0f8SKowalski, Kamil     }
1640e439f0f8SKowalski, Kamil 
164155c7b7a2SEd Tanous     bool verifyNames(crow::Response &res, const std::string &parent,
1642*1abe55efSEd Tanous                      const std::string &iface)
1643*1abe55efSEd Tanous     {
1644*1abe55efSEd Tanous         if (!boost::starts_with(iface, parent + "_"))
1645*1abe55efSEd Tanous         {
1646927a505aSKowalski, Kamil             messages::addMessageToErrorJson(
164755c7b7a2SEd Tanous                 res.jsonValue,
1648927a505aSKowalski, Kamil                 messages::resourceNotFound("VLAN Network Interface", iface));
1649927a505aSKowalski, Kamil             res.result(boost::beast::http::status::not_found);
1650927a505aSKowalski, Kamil             res.end();
1651927a505aSKowalski, Kamil 
1652927a505aSKowalski, Kamil             return false;
1653*1abe55efSEd Tanous         }
1654*1abe55efSEd Tanous         else
1655*1abe55efSEd Tanous         {
1656927a505aSKowalski, Kamil             return true;
1657927a505aSKowalski, Kamil         }
1658927a505aSKowalski, Kamil     }
1659927a505aSKowalski, Kamil 
1660e439f0f8SKowalski, Kamil     /**
1661e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1662e439f0f8SKowalski, Kamil      */
166355c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1664*1abe55efSEd Tanous                const std::vector<std::string> &params) override
1665*1abe55efSEd Tanous     {
1666e439f0f8SKowalski, Kamil         // TODO(Pawel) this shall be parametrized call (two params) to get
1667e439f0f8SKowalski, Kamil         // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
1668e439f0f8SKowalski, Kamil         // Check if there is required param, truly entering this shall be
1669e439f0f8SKowalski, Kamil         // impossible.
1670*1abe55efSEd Tanous         if (params.size() != 2)
1671*1abe55efSEd Tanous         {
1672e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1673e439f0f8SKowalski, Kamil             res.end();
1674e439f0f8SKowalski, Kamil             return;
1675e439f0f8SKowalski, Kamil         }
1676e439f0f8SKowalski, Kamil 
167755c7b7a2SEd Tanous         const std::string &parentIfaceId = params[0];
167855c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1679e439f0f8SKowalski, Kamil 
1680*1abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
1681*1abe55efSEd Tanous         {
1682a434f2bdSEd Tanous             return;
1683a434f2bdSEd Tanous         }
1684a434f2bdSEd Tanous 
1685e439f0f8SKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1686e439f0f8SKowalski, Kamil         // preparation
168755c7b7a2SEd Tanous         ethernetProvider.getEthernetIfaceData(
1688*1abe55efSEd Tanous             ifaceId, [&, parentIfaceId,
1689*1abe55efSEd Tanous                       ifaceId](const bool &success,
1690*1abe55efSEd Tanous                                const EthernetInterfaceData &eth_data,
1691e439f0f8SKowalski, Kamil                                const std::vector<IPv4AddressData> &ipv4_data) {
1692*1abe55efSEd Tanous                 if (success && eth_data.vlanId != nullptr)
1693*1abe55efSEd Tanous                 {
1694*1abe55efSEd Tanous                     res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
1695*1abe55efSEd Tanous                                                        eth_data, ipv4_data);
1696*1abe55efSEd Tanous                 }
1697*1abe55efSEd Tanous                 else
1698*1abe55efSEd Tanous                 {
1699e439f0f8SKowalski, Kamil                     // ... otherwise return error
1700*1abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
1701*1abe55efSEd Tanous                     // object, and other errors
1702927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1703*1abe55efSEd Tanous                         res.jsonValue, messages::resourceNotFound(
1704*1abe55efSEd Tanous                                            "VLAN Network Interface", ifaceId));
1705e439f0f8SKowalski, Kamil                     res.result(boost::beast::http::status::not_found);
1706e439f0f8SKowalski, Kamil                 }
1707e439f0f8SKowalski, Kamil                 res.end();
1708e439f0f8SKowalski, Kamil             });
1709e439f0f8SKowalski, Kamil     }
1710e439f0f8SKowalski, Kamil 
171155c7b7a2SEd Tanous     void doPatch(crow::Response &res, const crow::Request &req,
1712*1abe55efSEd Tanous                  const std::vector<std::string> &params) override
1713*1abe55efSEd Tanous     {
1714*1abe55efSEd Tanous         if (params.size() != 2)
1715*1abe55efSEd Tanous         {
1716e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1717e439f0f8SKowalski, Kamil             res.end();
1718e439f0f8SKowalski, Kamil             return;
1719e439f0f8SKowalski, Kamil         }
1720e439f0f8SKowalski, Kamil 
1721d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
172255c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1723927a505aSKowalski, Kamil 
1724*1abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
1725*1abe55efSEd Tanous         {
1726927a505aSKowalski, Kamil             return;
1727927a505aSKowalski, Kamil         }
1728927a505aSKowalski, Kamil 
1729927a505aSKowalski, Kamil         nlohmann::json patchReq;
1730927a505aSKowalski, Kamil 
1731*1abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, patchReq))
1732*1abe55efSEd Tanous         {
1733927a505aSKowalski, Kamil             return;
1734927a505aSKowalski, Kamil         }
1735927a505aSKowalski, Kamil 
1736927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1737927a505aSKowalski, Kamil         // preparation
173855c7b7a2SEd Tanous         ethernetProvider.getEthernetIfaceData(
1739*1abe55efSEd Tanous             ifaceId,
1740*1abe55efSEd Tanous             [&, parentIfaceId, ifaceId, patchReq = std::move(patchReq)](
1741927a505aSKowalski, Kamil                 const bool &success, const EthernetInterfaceData &eth_data,
1742927a505aSKowalski, Kamil                 const std::vector<IPv4AddressData> &ipv4_data) {
1743*1abe55efSEd Tanous                 if (!success)
1744*1abe55efSEd Tanous                 {
1745927a505aSKowalski, Kamil                     // ... otherwise return error
1746*1abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
1747*1abe55efSEd Tanous                     // object, and other errors
1748927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1749*1abe55efSEd Tanous                         res.jsonValue, messages::resourceNotFound(
1750*1abe55efSEd Tanous                                            "VLAN Network Interface", ifaceId));
1751927a505aSKowalski, Kamil                     res.result(boost::beast::http::status::not_found);
1752e439f0f8SKowalski, Kamil                     res.end();
1753927a505aSKowalski, Kamil 
1754927a505aSKowalski, Kamil                     return;
1755927a505aSKowalski, Kamil                 }
1756927a505aSKowalski, Kamil 
1757*1abe55efSEd Tanous                 res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
1758*1abe55efSEd Tanous                                                    eth_data, ipv4_data);
1759927a505aSKowalski, Kamil 
1760927a505aSKowalski, Kamil                 std::shared_ptr<AsyncResp> asyncResp =
1761927a505aSKowalski, Kamil                     std::make_shared<AsyncResp>(res);
1762927a505aSKowalski, Kamil 
1763*1abe55efSEd Tanous                 for (auto propertyIt = patchReq.begin();
1764*1abe55efSEd Tanous                      propertyIt != patchReq.end(); ++propertyIt)
1765*1abe55efSEd Tanous                 {
1766927a505aSKowalski, Kamil                     if (propertyIt.key() != "VLANEnable" &&
1767*1abe55efSEd Tanous                         propertyIt.key() != "VLANId")
1768*1abe55efSEd Tanous                     {
1769*1abe55efSEd Tanous                         auto fieldInJsonIt =
1770*1abe55efSEd Tanous                             res.jsonValue.find(propertyIt.key());
1771927a505aSKowalski, Kamil 
1772*1abe55efSEd Tanous                         if (fieldInJsonIt == res.jsonValue.end())
1773*1abe55efSEd Tanous                         {
1774927a505aSKowalski, Kamil                             // Field not in scope of defined fields
1775927a505aSKowalski, Kamil                             messages::addMessageToJsonRoot(
1776*1abe55efSEd Tanous                                 res.jsonValue,
1777*1abe55efSEd Tanous                                 messages::propertyUnknown(propertyIt.key()));
1778*1abe55efSEd Tanous                         }
1779*1abe55efSEd Tanous                         else if (*fieldInJsonIt != *propertyIt)
1780*1abe55efSEd Tanous                         {
1781927a505aSKowalski, Kamil                             // User attempted to modify non-writable field
1782927a505aSKowalski, Kamil                             messages::addMessageToJsonRoot(
1783*1abe55efSEd Tanous                                 res.jsonValue, messages::propertyNotWritable(
1784*1abe55efSEd Tanous                                                    propertyIt.key()));
1785927a505aSKowalski, Kamil                         }
1786927a505aSKowalski, Kamil                     }
1787927a505aSKowalski, Kamil                 }
1788927a505aSKowalski, Kamil 
1789*1abe55efSEd Tanous                 EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data,
1790*1abe55efSEd Tanous                                                    "/", asyncResp);
1791927a505aSKowalski, Kamil             });
1792e439f0f8SKowalski, Kamil     }
1793e439f0f8SKowalski, Kamil 
179455c7b7a2SEd Tanous     void doDelete(crow::Response &res, const crow::Request &req,
1795*1abe55efSEd Tanous                   const std::vector<std::string> &params) override
1796*1abe55efSEd Tanous     {
1797*1abe55efSEd Tanous         if (params.size() != 2)
1798*1abe55efSEd Tanous         {
1799e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1800e439f0f8SKowalski, Kamil             res.end();
1801e439f0f8SKowalski, Kamil             return;
1802e439f0f8SKowalski, Kamil         }
1803e439f0f8SKowalski, Kamil 
1804d76323e5SEd Tanous         const std::string &parentIfaceId = params[0];
180555c7b7a2SEd Tanous         const std::string &ifaceId = params[1];
1806927a505aSKowalski, Kamil 
1807*1abe55efSEd Tanous         if (!verifyNames(res, parentIfaceId, ifaceId))
1808*1abe55efSEd Tanous         {
1809927a505aSKowalski, Kamil             return;
1810927a505aSKowalski, Kamil         }
1811927a505aSKowalski, Kamil 
1812927a505aSKowalski, Kamil         // Get single eth interface data, and call the below callback for JSON
1813927a505aSKowalski, Kamil         // preparation
181455c7b7a2SEd Tanous         ethernetProvider.getEthernetIfaceData(
1815*1abe55efSEd Tanous             ifaceId, [&, parentIfaceId,
1816*1abe55efSEd Tanous                       ifaceId](const bool &success,
1817*1abe55efSEd Tanous                                const EthernetInterfaceData &eth_data,
1818927a505aSKowalski, Kamil                                const std::vector<IPv4AddressData> &ipv4_data) {
1819*1abe55efSEd Tanous                 if (success && eth_data.vlanId != nullptr)
1820*1abe55efSEd Tanous                 {
1821*1abe55efSEd Tanous                     res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
1822*1abe55efSEd Tanous                                                        eth_data, ipv4_data);
1823927a505aSKowalski, Kamil 
1824927a505aSKowalski, Kamil                     // Disable VLAN
1825927a505aSKowalski, Kamil                     OnDemandEthernetProvider::disableVlan(
182655c7b7a2SEd Tanous                         ifaceId, [&](const boost::system::error_code ec) {
1827*1abe55efSEd Tanous                             if (ec)
1828*1abe55efSEd Tanous                             {
182955c7b7a2SEd Tanous                                 res.jsonValue = nlohmann::json::object();
1830*1abe55efSEd Tanous                                 messages::addMessageToErrorJson(
1831*1abe55efSEd Tanous                                     res.jsonValue, messages::internalError());
1832*1abe55efSEd Tanous                                 res.result(boost::beast::http::status::
1833*1abe55efSEd Tanous                                                internal_server_error);
1834927a505aSKowalski, Kamil                             }
1835e439f0f8SKowalski, Kamil                             res.end();
1836927a505aSKowalski, Kamil                         });
1837*1abe55efSEd Tanous                 }
1838*1abe55efSEd Tanous                 else
1839*1abe55efSEd Tanous                 {
1840927a505aSKowalski, Kamil                     // ... otherwise return error
1841*1abe55efSEd Tanous                     // TODO(Pawel)consider distinguish between non existing
1842*1abe55efSEd Tanous                     // object, and other errors
1843927a505aSKowalski, Kamil                     messages::addMessageToErrorJson(
1844*1abe55efSEd Tanous                         res.jsonValue, messages::resourceNotFound(
1845*1abe55efSEd Tanous                                            "VLAN Network Interface", ifaceId));
1846927a505aSKowalski, Kamil                     res.result(boost::beast::http::status::not_found);
1847927a505aSKowalski, Kamil                     res.end();
1848927a505aSKowalski, Kamil                 }
1849927a505aSKowalski, Kamil             });
1850e439f0f8SKowalski, Kamil     }
1851e439f0f8SKowalski, Kamil 
1852e439f0f8SKowalski, Kamil     /**
1853e439f0f8SKowalski, Kamil      * This allows VlanNetworkInterfaceCollection to reuse this class' doGet
1854e439f0f8SKowalski, Kamil      * method, to maintain consistency of returned data, as Collection's doPost
1855e439f0f8SKowalski, Kamil      * should return data for created member which should match member's doGet
1856e439f0f8SKowalski, Kamil      * result in 100%.
1857e439f0f8SKowalski, Kamil      */
1858e439f0f8SKowalski, Kamil     friend VlanNetworkInterfaceCollection;
1859e439f0f8SKowalski, Kamil 
1860e439f0f8SKowalski, Kamil     // Ethernet Provider object
1861e439f0f8SKowalski, Kamil     // TODO(Pawel) consider move it to singleton
186255c7b7a2SEd Tanous     OnDemandEthernetProvider ethernetProvider;
1863e439f0f8SKowalski, Kamil };
1864e439f0f8SKowalski, Kamil 
1865e439f0f8SKowalski, Kamil /**
1866e439f0f8SKowalski, Kamil  * VlanNetworkInterfaceCollection derived class for delivering
1867e439f0f8SKowalski, Kamil  * VLANNetworkInterface Collection Schema
1868e439f0f8SKowalski, Kamil  */
1869*1abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node
1870*1abe55efSEd Tanous {
1871e439f0f8SKowalski, Kamil   public:
1872e439f0f8SKowalski, Kamil     template <typename CrowApp>
1873*1abe55efSEd Tanous     // TODO(Pawel) Remove line from below, where we assume that there is only
1874*1abe55efSEd Tanous     // one manager called openbmc This shall be generic, but requires to update
1875e439f0f8SKowalski, Kamil     // GetSubroutes method
1876*1abe55efSEd Tanous     VlanNetworkInterfaceCollection(CrowApp &app) :
1877*1abe55efSEd Tanous         Node(app,
1878e439f0f8SKowalski, Kamil              "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/",
1879e439f0f8SKowalski, Kamil              std::string()),
1880*1abe55efSEd Tanous         memberVlan(app)
1881*1abe55efSEd Tanous     {
1882e439f0f8SKowalski, Kamil         Node::json["@odata.type"] =
1883e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1884e439f0f8SKowalski, Kamil         Node::json["@odata.context"] =
1885e439f0f8SKowalski, Kamil             "/redfish/v1/$metadata"
1886e439f0f8SKowalski, Kamil             "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
1887e439f0f8SKowalski, Kamil         Node::json["Name"] = "VLAN Network Interface Collection";
1888e439f0f8SKowalski, Kamil 
1889e439f0f8SKowalski, Kamil         entityPrivileges = {
1890e439f0f8SKowalski, Kamil             {boost::beast::http::verb::get, {{"Login"}}},
1891e439f0f8SKowalski, Kamil             {boost::beast::http::verb::head, {{"Login"}}},
1892e439f0f8SKowalski, Kamil             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1893e439f0f8SKowalski, Kamil             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1894e439f0f8SKowalski, Kamil             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1895e439f0f8SKowalski, Kamil             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1896e439f0f8SKowalski, Kamil     }
1897e439f0f8SKowalski, Kamil 
1898e439f0f8SKowalski, Kamil   private:
1899e439f0f8SKowalski, Kamil     /**
1900e439f0f8SKowalski, Kamil      * Functions triggers appropriate requests on DBus
1901e439f0f8SKowalski, Kamil      */
190255c7b7a2SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1903*1abe55efSEd Tanous                const std::vector<std::string> &params) override
1904*1abe55efSEd Tanous     {
1905*1abe55efSEd Tanous         if (params.size() != 1)
1906*1abe55efSEd Tanous         {
1907e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1908e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1909e439f0f8SKowalski, Kamil             res.end();
1910e439f0f8SKowalski, Kamil 
1911e439f0f8SKowalski, Kamil             return;
1912e439f0f8SKowalski, Kamil         }
1913e439f0f8SKowalski, Kamil 
1914*1abe55efSEd Tanous         // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
1915*1abe55efSEd Tanous         // for any Manager, not only hardcoded 'openbmc'.
191655c7b7a2SEd Tanous         std::string managerId = "openbmc";
1917e439f0f8SKowalski, Kamil         std::string rootInterfaceName = params[0];
1918e439f0f8SKowalski, Kamil 
1919*1abe55efSEd Tanous         // get eth interface list, and call the below callback for JSON
1920*1abe55efSEd Tanous         // preparation
1921*1abe55efSEd Tanous         ethernetProvider.getEthernetIfaceList(
1922*1abe55efSEd Tanous             [&, managerId{std::move(managerId)},
1923*1abe55efSEd Tanous              rootInterfaceName{std::move(rootInterfaceName)}](
1924*1abe55efSEd Tanous                 const bool &success,
1925*1abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
1926*1abe55efSEd Tanous                 if (success)
1927*1abe55efSEd Tanous                 {
1928e439f0f8SKowalski, Kamil                     bool rootInterfaceFound = false;
192955c7b7a2SEd Tanous                     nlohmann::json ifaceArray = nlohmann::json::array();
1930e439f0f8SKowalski, Kamil 
1931*1abe55efSEd Tanous                     for (const std::string &ifaceItem : iface_list)
1932*1abe55efSEd Tanous                     {
1933*1abe55efSEd Tanous                         if (ifaceItem == rootInterfaceName)
1934*1abe55efSEd Tanous                         {
1935e439f0f8SKowalski, Kamil                             rootInterfaceFound = true;
1936*1abe55efSEd Tanous                         }
1937*1abe55efSEd Tanous                         else if (boost::starts_with(ifaceItem,
1938*1abe55efSEd Tanous                                                     rootInterfaceName + "_"))
1939*1abe55efSEd Tanous                         {
194055c7b7a2SEd Tanous                             ifaceArray.push_back(
1941*1abe55efSEd Tanous                                 {{"@odata.id", "/redfish/v1/Managers/" +
1942*1abe55efSEd Tanous                                                    managerId +
1943*1abe55efSEd Tanous                                                    "/EthernetInterfaces/" +
1944*1abe55efSEd Tanous                                                    rootInterfaceName +
19458ceb2ecaSEd Tanous                                                    "/VLANs/" + ifaceItem}});
1946e439f0f8SKowalski, Kamil                         }
1947e439f0f8SKowalski, Kamil                     }
1948e439f0f8SKowalski, Kamil 
1949*1abe55efSEd Tanous                     if (rootInterfaceFound)
1950*1abe55efSEd Tanous                     {
195155c7b7a2SEd Tanous                         Node::json["Members"] = ifaceArray;
195255c7b7a2SEd Tanous                         Node::json["Members@odata.count"] = ifaceArray.size();
1953*1abe55efSEd Tanous                         Node::json["@odata.id"] = "/redfish/v1/Managers/" +
1954*1abe55efSEd Tanous                                                   managerId +
1955*1abe55efSEd Tanous                                                   "/EthernetInterfaces/" +
1956*1abe55efSEd Tanous                                                   rootInterfaceName + "/VLANs";
195755c7b7a2SEd Tanous                         res.jsonValue = Node::json;
1958*1abe55efSEd Tanous                     }
1959*1abe55efSEd Tanous                     else
1960*1abe55efSEd Tanous                     {
1961e439f0f8SKowalski, Kamil                         messages::addMessageToErrorJson(
1962*1abe55efSEd Tanous                             res.jsonValue,
1963*1abe55efSEd Tanous                             messages::resourceNotFound("EthernetInterface",
1964e439f0f8SKowalski, Kamil                                                        rootInterfaceName));
1965e439f0f8SKowalski, Kamil                         res.result(boost::beast::http::status::not_found);
1966e439f0f8SKowalski, Kamil                         res.end();
1967e439f0f8SKowalski, Kamil                     }
1968*1abe55efSEd Tanous                 }
1969*1abe55efSEd Tanous                 else
1970*1abe55efSEd Tanous                 {
1971e439f0f8SKowalski, Kamil                     // No success, best what we can do is return INTERNALL ERROR
1972*1abe55efSEd Tanous                     res.result(
1973*1abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
1974e439f0f8SKowalski, Kamil                 }
1975e439f0f8SKowalski, Kamil                 res.end();
1976e439f0f8SKowalski, Kamil             });
1977e439f0f8SKowalski, Kamil     }
1978e439f0f8SKowalski, Kamil 
197955c7b7a2SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
1980*1abe55efSEd Tanous                 const std::vector<std::string> &params) override
1981*1abe55efSEd Tanous     {
1982*1abe55efSEd Tanous         if (params.size() != 1)
1983*1abe55efSEd Tanous         {
1984e439f0f8SKowalski, Kamil             // This means there is a problem with the router
1985e439f0f8SKowalski, Kamil             res.result(boost::beast::http::status::internal_server_error);
1986e439f0f8SKowalski, Kamil             res.end();
1987e439f0f8SKowalski, Kamil             return;
1988e439f0f8SKowalski, Kamil         }
1989e439f0f8SKowalski, Kamil 
1990e439f0f8SKowalski, Kamil         nlohmann::json postReq;
1991e439f0f8SKowalski, Kamil 
1992*1abe55efSEd Tanous         if (!json_util::processJsonFromRequest(res, req, postReq))
1993*1abe55efSEd Tanous         {
1994e439f0f8SKowalski, Kamil             return;
1995e439f0f8SKowalski, Kamil         }
1996e439f0f8SKowalski, Kamil 
1997*1abe55efSEd Tanous         // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
1998*1abe55efSEd Tanous         // for any Manager, not only hardcoded 'openbmc'.
199955c7b7a2SEd Tanous         std::string managerId = "openbmc";
2000e439f0f8SKowalski, Kamil         std::string rootInterfaceName = params[0];
2001e439f0f8SKowalski, Kamil         uint64_t vlanId;
2002e439f0f8SKowalski, Kamil         bool errorDetected;
2003e439f0f8SKowalski, Kamil 
2004e439f0f8SKowalski, Kamil         if (json_util::getUnsigned(
2005e439f0f8SKowalski, Kamil                 "VLANId", postReq, vlanId,
2006e439f0f8SKowalski, Kamil                 static_cast<uint8_t>(json_util::MessageSetting::MISSING) |
2007e439f0f8SKowalski, Kamil                     static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
2008*1abe55efSEd Tanous                 res.jsonValue, "/VLANId") != json_util::Result::SUCCESS)
2009*1abe55efSEd Tanous         {
2010e439f0f8SKowalski, Kamil             res.end();
2011e439f0f8SKowalski, Kamil             return;
2012e439f0f8SKowalski, Kamil         }
2013e439f0f8SKowalski, Kamil 
2014*1abe55efSEd Tanous         // get eth interface list, and call the below callback for JSON
2015*1abe55efSEd Tanous         // preparation
2016*1abe55efSEd Tanous         ethernetProvider.getEthernetIfaceList(
2017*1abe55efSEd Tanous             [&, managerId{std::move(managerId)},
2018*1abe55efSEd Tanous              rootInterfaceName{std::move(rootInterfaceName)}](
2019*1abe55efSEd Tanous                 const bool &success,
2020*1abe55efSEd Tanous                 const std::vector<std::string> &iface_list) {
2021*1abe55efSEd Tanous                 if (success)
2022*1abe55efSEd Tanous                 {
2023e439f0f8SKowalski, Kamil                     bool rootInterfaceFound = false;
2024e439f0f8SKowalski, Kamil 
2025*1abe55efSEd Tanous                     for (const std::string &ifaceItem : iface_list)
2026*1abe55efSEd Tanous                     {
2027*1abe55efSEd Tanous                         if (ifaceItem == rootInterfaceName)
2028*1abe55efSEd Tanous                         {
2029e439f0f8SKowalski, Kamil                             rootInterfaceFound = true;
2030e439f0f8SKowalski, Kamil                             break;
2031e439f0f8SKowalski, Kamil                         }
2032e439f0f8SKowalski, Kamil                     }
2033e439f0f8SKowalski, Kamil 
2034*1abe55efSEd Tanous                     if (rootInterfaceFound)
2035*1abe55efSEd Tanous                     {
203655c7b7a2SEd Tanous                         ethernetProvider.createVlan(
2037e439f0f8SKowalski, Kamil                             rootInterfaceName, vlanId,
2038*1abe55efSEd Tanous                             [&, vlanId, rootInterfaceName, req{std::move(req)}](
2039*1abe55efSEd Tanous                                 const boost::system::error_code ec) {
2040*1abe55efSEd Tanous                                 if (ec)
2041*1abe55efSEd Tanous                                 {
2042*1abe55efSEd Tanous                                     messages::addMessageToErrorJson(
2043*1abe55efSEd Tanous                                         res.jsonValue,
20448ceb2ecaSEd Tanous                                         messages::internalError());
2045e439f0f8SKowalski, Kamil                                     res.end();
2046*1abe55efSEd Tanous                                 }
2047*1abe55efSEd Tanous                                 else
2048*1abe55efSEd Tanous                                 {
2049e439f0f8SKowalski, Kamil                                     memberVlan.doGet(
2050e439f0f8SKowalski, Kamil                                         res, req,
2051e439f0f8SKowalski, Kamil                                         {rootInterfaceName,
2052*1abe55efSEd Tanous                                          rootInterfaceName + "_" +
2053*1abe55efSEd Tanous                                              std::to_string(vlanId)});
2054e439f0f8SKowalski, Kamil                                 }
2055e439f0f8SKowalski, Kamil                             });
2056*1abe55efSEd Tanous                     }
2057*1abe55efSEd Tanous                     else
2058*1abe55efSEd Tanous                     {
2059e439f0f8SKowalski, Kamil                         messages::addMessageToErrorJson(
2060*1abe55efSEd Tanous                             res.jsonValue,
2061*1abe55efSEd Tanous                             messages::resourceNotFound("EthernetInterface",
2062e439f0f8SKowalski, Kamil                                                        rootInterfaceName));
2063e439f0f8SKowalski, Kamil                         res.result(boost::beast::http::status::not_found);
2064e439f0f8SKowalski, Kamil                         res.end();
2065e439f0f8SKowalski, Kamil                     }
2066*1abe55efSEd Tanous                 }
2067*1abe55efSEd Tanous                 else
2068*1abe55efSEd Tanous                 {
2069e439f0f8SKowalski, Kamil                     // No success, best what we can do is return INTERNALL ERROR
2070*1abe55efSEd Tanous                     res.result(
2071*1abe55efSEd Tanous                         boost::beast::http::status::internal_server_error);
2072e439f0f8SKowalski, Kamil                     res.end();
2073e439f0f8SKowalski, Kamil                 }
2074e439f0f8SKowalski, Kamil             });
2075e439f0f8SKowalski, Kamil     }
2076e439f0f8SKowalski, Kamil 
2077e439f0f8SKowalski, Kamil     // Ethernet Provider object
2078e439f0f8SKowalski, Kamil     // TODO(Pawel) consider move it to singleton
207955c7b7a2SEd Tanous     OnDemandEthernetProvider ethernetProvider;
2080e439f0f8SKowalski, Kamil     VlanNetworkInterface memberVlan;
2081e439f0f8SKowalski, Kamil };
2082e439f0f8SKowalski, Kamil 
20839391bb9cSRapkiewicz, Pawel } // namespace redfish
2084