xref: /openbmc/bmcweb/features/redfish/lib/ethernet.hpp (revision aa2e59c10280ca4819926905e77a076bdb72a03f)
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 
189391bb9cSRapkiewicz, Pawel #include "node.hpp"
199391bb9cSRapkiewicz, Pawel #include <boost/container/flat_map.hpp>
209391bb9cSRapkiewicz, Pawel 
219391bb9cSRapkiewicz, Pawel namespace redfish {
229391bb9cSRapkiewicz, Pawel 
239391bb9cSRapkiewicz, Pawel /**
249391bb9cSRapkiewicz, Pawel  * DBus types primitives for several generic DBus interfaces
259391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider move this to separate file into boost::dbus
269391bb9cSRapkiewicz, Pawel  */
27*aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map<
28*aa2e59c1SEd Tanous     std::string,
29*aa2e59c1SEd Tanous     sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t,
30*aa2e59c1SEd Tanous                                 int32_t, uint32_t, int64_t, uint64_t, double>>;
319391bb9cSRapkiewicz, Pawel 
329391bb9cSRapkiewicz, Pawel using GetManagedObjectsType = boost::container::flat_map<
33*aa2e59c1SEd Tanous     sdbusplus::message::object_path,
34*aa2e59c1SEd Tanous     boost::container::flat_map<
35*aa2e59c1SEd Tanous         std::string,
36*aa2e59c1SEd Tanous         boost::container::flat_map<
37*aa2e59c1SEd Tanous             std::string, sdbusplus::message::variant<
38*aa2e59c1SEd Tanous                              std::string, bool, uint8_t, int16_t, uint16_t,
39*aa2e59c1SEd Tanous                              int32_t, uint32_t, int64_t, uint64_t, double>>>>;
409391bb9cSRapkiewicz, Pawel 
419391bb9cSRapkiewicz, Pawel /**
429391bb9cSRapkiewicz, Pawel  * Structure for keeping IPv4 data required by Redfish
439391bb9cSRapkiewicz, Pawel  * TODO(Pawel) consider change everything to ptr, or to non-ptr values.
449391bb9cSRapkiewicz, Pawel  */
459391bb9cSRapkiewicz, Pawel struct IPv4AddressData {
469391bb9cSRapkiewicz, Pawel   const std::string *address;
479391bb9cSRapkiewicz, Pawel   const std::string *domain;
489391bb9cSRapkiewicz, Pawel   const std::string *gateway;
499391bb9cSRapkiewicz, Pawel   std::string netmask;
509391bb9cSRapkiewicz, Pawel   std::string origin;
519391bb9cSRapkiewicz, Pawel   bool global;
529391bb9cSRapkiewicz, Pawel };
539391bb9cSRapkiewicz, Pawel 
549391bb9cSRapkiewicz, Pawel /**
559391bb9cSRapkiewicz, Pawel  * Structure for keeping basic single Ethernet Interface information
569391bb9cSRapkiewicz, Pawel  * available from DBus
579391bb9cSRapkiewicz, Pawel  */
589391bb9cSRapkiewicz, Pawel struct EthernetInterfaceData {
599391bb9cSRapkiewicz, Pawel   const unsigned int *speed;
609391bb9cSRapkiewicz, Pawel   const bool *auto_neg;
619391bb9cSRapkiewicz, Pawel   const std::string *hostname;
629391bb9cSRapkiewicz, Pawel   const std::string *default_gateway;
639391bb9cSRapkiewicz, Pawel   const std::string *mac_address;
64c7070ac2SKowalski, Kamil   const unsigned int *vlan_id;
659391bb9cSRapkiewicz, Pawel };
669391bb9cSRapkiewicz, Pawel 
679391bb9cSRapkiewicz, Pawel /**
689391bb9cSRapkiewicz, Pawel  * OnDemandEthernetProvider
69274fad5aSGunnar Mills  * Ethernet provider class that retrieves data directly from dbus, before
70274fad5aSGunnar Mills  * setting it into JSON output. This does not cache any data.
719391bb9cSRapkiewicz, Pawel  *
729391bb9cSRapkiewicz, Pawel  * TODO(Pawel)
739391bb9cSRapkiewicz, Pawel  * This perhaps shall be different file, which has to be chosen on compile time
749391bb9cSRapkiewicz, Pawel  * depending on OEM needs
759391bb9cSRapkiewicz, Pawel  */
769391bb9cSRapkiewicz, Pawel class OnDemandEthernetProvider {
779391bb9cSRapkiewicz, Pawel  private:
789391bb9cSRapkiewicz, Pawel   // Consts that may have influence on EthernetProvider performance/memory usage
799391bb9cSRapkiewicz, Pawel   const size_t MAX_IPV4_ADDRESSES_PER_INTERFACE = 10;
809391bb9cSRapkiewicz, Pawel 
819391bb9cSRapkiewicz, Pawel   // Helper function that allows to extract GetAllPropertiesType from
829391bb9cSRapkiewicz, Pawel   // GetManagedObjectsType, based on object path, and interface name
839391bb9cSRapkiewicz, Pawel   const PropertiesMapType *extractInterfaceProperties(
84*aa2e59c1SEd Tanous       const sdbusplus::message::object_path &objpath,
85*aa2e59c1SEd Tanous       const std::string &interface, const GetManagedObjectsType &dbus_data) {
869391bb9cSRapkiewicz, Pawel     const auto &dbus_obj = dbus_data.find(objpath);
879391bb9cSRapkiewicz, Pawel     if (dbus_obj != dbus_data.end()) {
889391bb9cSRapkiewicz, Pawel       const auto &iface = dbus_obj->second.find(interface);
899391bb9cSRapkiewicz, Pawel       if (iface != dbus_obj->second.end()) {
909391bb9cSRapkiewicz, Pawel         return &iface->second;
919391bb9cSRapkiewicz, Pawel       }
929391bb9cSRapkiewicz, Pawel     }
939391bb9cSRapkiewicz, Pawel     return nullptr;
949391bb9cSRapkiewicz, Pawel   }
959391bb9cSRapkiewicz, Pawel 
969391bb9cSRapkiewicz, Pawel   // Helper Wrapper that does inline object_path conversion from string
97*aa2e59c1SEd Tanous   // into sdbusplus::message::object_path type
989391bb9cSRapkiewicz, Pawel   inline const PropertiesMapType *extractInterfaceProperties(
999391bb9cSRapkiewicz, Pawel       const std::string &objpath, const std::string &interface,
1009391bb9cSRapkiewicz, Pawel       const GetManagedObjectsType &dbus_data) {
101*aa2e59c1SEd Tanous     const auto &dbus_obj = sdbusplus::message::object_path{objpath};
1029391bb9cSRapkiewicz, Pawel     return extractInterfaceProperties(dbus_obj, interface, dbus_data);
1039391bb9cSRapkiewicz, Pawel   }
1049391bb9cSRapkiewicz, Pawel 
1059391bb9cSRapkiewicz, Pawel   // Helper function that allows to get pointer to the property from
1069391bb9cSRapkiewicz, Pawel   // GetAllPropertiesType native, or extracted by GetAllPropertiesType
1079391bb9cSRapkiewicz, Pawel   template <typename T>
108*aa2e59c1SEd Tanous   inline T const *const extractProperty(const PropertiesMapType &properties,
1099391bb9cSRapkiewicz, Pawel                                         const std::string &name) {
1109391bb9cSRapkiewicz, Pawel     const auto &property = properties.find(name);
1119391bb9cSRapkiewicz, Pawel     if (property != properties.end()) {
112*aa2e59c1SEd Tanous       return mapbox::get_ptr<const T>(property->second);
1139391bb9cSRapkiewicz, Pawel     }
1149391bb9cSRapkiewicz, Pawel     return nullptr;
1159391bb9cSRapkiewicz, Pawel   }
1169391bb9cSRapkiewicz, Pawel   // TODO(Pawel) Consider to move the above functions to dbus
1179391bb9cSRapkiewicz, Pawel   // generic_interfaces.hpp
1189391bb9cSRapkiewicz, Pawel 
1199391bb9cSRapkiewicz, Pawel   // Helper function that extracts data from several dbus objects and several
1209391bb9cSRapkiewicz, Pawel   // interfaces required by single ethernet interface instance
1219391bb9cSRapkiewicz, Pawel   void extractEthernetInterfaceData(const std::string &ethiface_id,
1229391bb9cSRapkiewicz, Pawel                                     const GetManagedObjectsType &dbus_data,
1239391bb9cSRapkiewicz, Pawel                                     EthernetInterfaceData &eth_data) {
1249391bb9cSRapkiewicz, Pawel     // Extract data that contains MAC Address
1259391bb9cSRapkiewicz, Pawel     const PropertiesMapType *mac_properties = extractInterfaceProperties(
1269391bb9cSRapkiewicz, Pawel         "/xyz/openbmc_project/network/" + ethiface_id,
1279391bb9cSRapkiewicz, Pawel         "xyz.openbmc_project.Network.MACAddress", dbus_data);
1289391bb9cSRapkiewicz, Pawel 
1299391bb9cSRapkiewicz, Pawel     if (mac_properties != nullptr) {
1309391bb9cSRapkiewicz, Pawel       eth_data.mac_address =
1319391bb9cSRapkiewicz, Pawel           extractProperty<std::string>(*mac_properties, "MACAddress");
1329391bb9cSRapkiewicz, Pawel     }
1339391bb9cSRapkiewicz, Pawel 
134c7070ac2SKowalski, Kamil     const PropertiesMapType *vlan_properties = extractInterfaceProperties(
135c7070ac2SKowalski, Kamil         "/xyz/openbmc_project/network/" + ethiface_id,
136c7070ac2SKowalski, Kamil         "xyz.openbmc_project.Network.VLAN", dbus_data);
137c7070ac2SKowalski, Kamil 
138c7070ac2SKowalski, Kamil     if (vlan_properties != nullptr) {
139c7070ac2SKowalski, Kamil       eth_data.vlan_id = extractProperty<unsigned int>(*vlan_properties, "Id");
140c7070ac2SKowalski, Kamil     }
141c7070ac2SKowalski, Kamil 
1429391bb9cSRapkiewicz, Pawel     // Extract data that contains link information (auto negotiation and speed)
1439391bb9cSRapkiewicz, Pawel     const PropertiesMapType *eth_properties = extractInterfaceProperties(
1449391bb9cSRapkiewicz, Pawel         "/xyz/openbmc_project/network/" + ethiface_id,
1459391bb9cSRapkiewicz, Pawel         "xyz.openbmc_project.Network.EthernetInterface", dbus_data);
1469391bb9cSRapkiewicz, Pawel 
1479391bb9cSRapkiewicz, Pawel     if (eth_properties != nullptr) {
1489391bb9cSRapkiewicz, Pawel       eth_data.auto_neg = extractProperty<bool>(*eth_properties, "AutoNeg");
1499391bb9cSRapkiewicz, Pawel       eth_data.speed = extractProperty<unsigned int>(*eth_properties, "Speed");
1509391bb9cSRapkiewicz, Pawel     }
1519391bb9cSRapkiewicz, Pawel 
1529391bb9cSRapkiewicz, Pawel     // Extract data that contains network config (HostName and DefaultGW)
1539391bb9cSRapkiewicz, Pawel     const PropertiesMapType *config_properties = extractInterfaceProperties(
1549391bb9cSRapkiewicz, Pawel         "/xyz/openbmc_project/network/config",
1559391bb9cSRapkiewicz, Pawel         "xyz.openbmc_project.Network.SystemConfiguration", dbus_data);
1569391bb9cSRapkiewicz, Pawel 
1579391bb9cSRapkiewicz, Pawel     if (config_properties != nullptr) {
1589391bb9cSRapkiewicz, Pawel       eth_data.hostname =
1599391bb9cSRapkiewicz, Pawel           extractProperty<std::string>(*config_properties, "HostName");
1609391bb9cSRapkiewicz, Pawel       eth_data.default_gateway =
1619391bb9cSRapkiewicz, Pawel           extractProperty<std::string>(*config_properties, "DefaultGateway");
1629391bb9cSRapkiewicz, Pawel     }
1639391bb9cSRapkiewicz, Pawel   }
1649391bb9cSRapkiewicz, Pawel 
1659391bb9cSRapkiewicz, Pawel   // Helper function that changes bits netmask notation (i.e. /24)
1669391bb9cSRapkiewicz, Pawel   // into full dot notation
1679391bb9cSRapkiewicz, Pawel   inline std::string getNetmask(unsigned int bits) {
1689391bb9cSRapkiewicz, Pawel     uint32_t value = 0xffffffff << (32 - bits);
1699391bb9cSRapkiewicz, Pawel     std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
1709391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 16) & 0xff) + "." +
1719391bb9cSRapkiewicz, Pawel                           std::to_string((value >> 8) & 0xff) + "." +
1729391bb9cSRapkiewicz, Pawel                           std::to_string(value & 0xff);
1739391bb9cSRapkiewicz, Pawel     return netmask;
1749391bb9cSRapkiewicz, Pawel   }
1759391bb9cSRapkiewicz, Pawel 
1769391bb9cSRapkiewicz, Pawel   // Helper function that extracts data for single ethernet ipv4 address
1779391bb9cSRapkiewicz, Pawel   void extractIPv4Data(const std::string &ethiface_id,
1789391bb9cSRapkiewicz, Pawel                        const GetManagedObjectsType &dbus_data,
1799391bb9cSRapkiewicz, Pawel                        std::vector<IPv4AddressData> &ipv4_config) {
1809391bb9cSRapkiewicz, Pawel     // Since there might be several IPv4 configurations aligned with
1819391bb9cSRapkiewicz, Pawel     // single ethernet interface, loop over all of them
1829391bb9cSRapkiewicz, Pawel     for (auto &objpath : dbus_data) {
183274fad5aSGunnar Mills       // Check if proper patter for object path appears
1849391bb9cSRapkiewicz, Pawel       if (boost::starts_with(
185*aa2e59c1SEd Tanous               static_cast<std::string>(objpath.first),
1869391bb9cSRapkiewicz, Pawel               "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/")) {
1879391bb9cSRapkiewicz, Pawel         // and get approrpiate interface
1889391bb9cSRapkiewicz, Pawel         const auto &interface =
1899391bb9cSRapkiewicz, Pawel             objpath.second.find("xyz.openbmc_project.Network.IP");
1909391bb9cSRapkiewicz, Pawel         if (interface != objpath.second.end()) {
1919391bb9cSRapkiewicz, Pawel           // Make a properties 'shortcut', to make everything more readable
1929391bb9cSRapkiewicz, Pawel           const PropertiesMapType &properties = interface->second;
1939391bb9cSRapkiewicz, Pawel           // Instance IPv4AddressData structure, and set as appropriate
1949391bb9cSRapkiewicz, Pawel           IPv4AddressData ipv4_address;
1959391bb9cSRapkiewicz, Pawel           // IPv4 address
1969391bb9cSRapkiewicz, Pawel           ipv4_address.address =
1979391bb9cSRapkiewicz, Pawel               extractProperty<std::string>(properties, "Address");
1989391bb9cSRapkiewicz, Pawel           // IPv4 gateway
1999391bb9cSRapkiewicz, Pawel           ipv4_address.gateway =
2009391bb9cSRapkiewicz, Pawel               extractProperty<std::string>(properties, "Gateway");
2019391bb9cSRapkiewicz, Pawel 
2029391bb9cSRapkiewicz, Pawel           // Origin is kind of DBus object so fetch pointer...
2039391bb9cSRapkiewicz, Pawel           const std::string *origin =
2049391bb9cSRapkiewicz, Pawel               extractProperty<std::string>(properties, "Origin");
2059391bb9cSRapkiewicz, Pawel           if (origin != nullptr) {
2069391bb9cSRapkiewicz, Pawel             // ... and get everything after last dot
2079391bb9cSRapkiewicz, Pawel             int last = origin->rfind(".");
2089391bb9cSRapkiewicz, Pawel             if (last != std::string::npos) {
2099391bb9cSRapkiewicz, Pawel               ipv4_address.origin = origin->substr(last + 1);
2109391bb9cSRapkiewicz, Pawel             }
2119391bb9cSRapkiewicz, Pawel           }
2129391bb9cSRapkiewicz, Pawel 
2139391bb9cSRapkiewicz, Pawel           // Netmask is presented as PrefixLength
2149391bb9cSRapkiewicz, Pawel           const auto *mask =
2159391bb9cSRapkiewicz, Pawel               extractProperty<uint8_t>(properties, "PrefixLength");
2169391bb9cSRapkiewicz, Pawel           if (mask != nullptr) {
2179391bb9cSRapkiewicz, Pawel             // convert it to the string
2189391bb9cSRapkiewicz, Pawel             ipv4_address.netmask = getNetmask(*mask);
2199391bb9cSRapkiewicz, Pawel           }
2209391bb9cSRapkiewicz, Pawel 
2219391bb9cSRapkiewicz, Pawel           // Attach IPv4 only if address is present
2229391bb9cSRapkiewicz, Pawel           if (ipv4_address.address != nullptr) {
223274fad5aSGunnar Mills             // Check if given address is local, or global
2249391bb9cSRapkiewicz, Pawel             if (boost::starts_with(*ipv4_address.address, "169.254")) {
2259391bb9cSRapkiewicz, Pawel               ipv4_address.global = false;
2269391bb9cSRapkiewicz, Pawel             } else {
2279391bb9cSRapkiewicz, Pawel               ipv4_address.global = true;
2289391bb9cSRapkiewicz, Pawel             }
2299391bb9cSRapkiewicz, Pawel             ipv4_config.emplace_back(std::move(ipv4_address));
2309391bb9cSRapkiewicz, Pawel           }
2319391bb9cSRapkiewicz, Pawel         }
2329391bb9cSRapkiewicz, Pawel       }
2339391bb9cSRapkiewicz, Pawel     }
2349391bb9cSRapkiewicz, Pawel   }
2359391bb9cSRapkiewicz, Pawel 
2369391bb9cSRapkiewicz, Pawel  public:
2379391bb9cSRapkiewicz, Pawel   /**
2389391bb9cSRapkiewicz, Pawel    * Function that retrieves all properties for given Ethernet Interface Object
2399391bb9cSRapkiewicz, Pawel    * from EntityManager Network Manager
2409391bb9cSRapkiewicz, Pawel    * @param ethiface_id a eth interface id to query on DBus
2419391bb9cSRapkiewicz, Pawel    * @param callback a function that shall be called to convert Dbus output into
2429391bb9cSRapkiewicz, Pawel    * JSON
2439391bb9cSRapkiewicz, Pawel    */
2449391bb9cSRapkiewicz, Pawel   template <typename CallbackFunc>
2459391bb9cSRapkiewicz, Pawel   void getEthernetIfaceData(const std::string &ethiface_id,
2469391bb9cSRapkiewicz, Pawel                             CallbackFunc &&callback) {
2479391bb9cSRapkiewicz, Pawel     crow::connections::system_bus->async_method_call(
2489391bb9cSRapkiewicz, Pawel         [
2499391bb9cSRapkiewicz, Pawel           this, ethiface_id{std::move(ethiface_id)},
2509391bb9cSRapkiewicz, Pawel           callback{std::move(callback)}
2519391bb9cSRapkiewicz, Pawel         ](const boost::system::error_code error_code,
252*aa2e59c1SEd Tanous           GetManagedObjectsType &resp) {
2539391bb9cSRapkiewicz, Pawel 
254c7070ac2SKowalski, Kamil           EthernetInterfaceData eth_data{};
2559391bb9cSRapkiewicz, Pawel           std::vector<IPv4AddressData> ipv4_data;
2569391bb9cSRapkiewicz, Pawel           ipv4_data.reserve(MAX_IPV4_ADDRESSES_PER_INTERFACE);
2579391bb9cSRapkiewicz, Pawel 
2589391bb9cSRapkiewicz, Pawel           if (error_code) {
2599391bb9cSRapkiewicz, Pawel             // Something wrong on DBus, the error_code is not important at this
2609391bb9cSRapkiewicz, Pawel             // moment, just return success=false, and empty output. Since size
2619391bb9cSRapkiewicz, Pawel             // of vector may vary depending on information from Network Manager,
2629391bb9cSRapkiewicz, Pawel             // and empty output could not be treated same way as error.
2639391bb9cSRapkiewicz, Pawel             callback(false, eth_data, ipv4_data);
2649391bb9cSRapkiewicz, Pawel             return;
2659391bb9cSRapkiewicz, Pawel           }
2669391bb9cSRapkiewicz, Pawel 
2679391bb9cSRapkiewicz, Pawel           extractEthernetInterfaceData(ethiface_id, resp, eth_data);
2689391bb9cSRapkiewicz, Pawel           extractIPv4Data(ethiface_id, resp, ipv4_data);
2699391bb9cSRapkiewicz, Pawel 
2709391bb9cSRapkiewicz, Pawel           // Fix global GW
2719391bb9cSRapkiewicz, Pawel           for (IPv4AddressData &ipv4 : ipv4_data) {
2729391bb9cSRapkiewicz, Pawel             if ((ipv4.global) &&
2739391bb9cSRapkiewicz, Pawel                 ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) {
2749391bb9cSRapkiewicz, Pawel               ipv4.gateway = eth_data.default_gateway;
2759391bb9cSRapkiewicz, Pawel             }
2769391bb9cSRapkiewicz, Pawel           }
2779391bb9cSRapkiewicz, Pawel 
278274fad5aSGunnar Mills           // Finally make a callback with useful data
2799391bb9cSRapkiewicz, Pawel           callback(true, eth_data, ipv4_data);
2809391bb9cSRapkiewicz, Pawel         },
281*aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
282*aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2839391bb9cSRapkiewicz, Pawel   };
2849391bb9cSRapkiewicz, Pawel 
2859391bb9cSRapkiewicz, Pawel   /**
2869391bb9cSRapkiewicz, Pawel    * Function that retrieves all Ethernet Interfaces available through Network
2879391bb9cSRapkiewicz, Pawel    * Manager
2889391bb9cSRapkiewicz, Pawel    * @param callback a function that shall be called to convert Dbus output into
2899391bb9cSRapkiewicz, Pawel    * JSON.
2909391bb9cSRapkiewicz, Pawel    */
2919391bb9cSRapkiewicz, Pawel   template <typename CallbackFunc>
2929391bb9cSRapkiewicz, Pawel   void getEthernetIfaceList(CallbackFunc &&callback) {
2939391bb9cSRapkiewicz, Pawel     crow::connections::system_bus->async_method_call(
2949391bb9cSRapkiewicz, Pawel         [ this, callback{std::move(callback)} ](
2959391bb9cSRapkiewicz, Pawel             const boost::system::error_code error_code,
296*aa2e59c1SEd Tanous             GetManagedObjectsType &resp) {
2979391bb9cSRapkiewicz, Pawel           // Callback requires vector<string> to retrieve all available ethernet
2989391bb9cSRapkiewicz, Pawel           // interfaces
2999391bb9cSRapkiewicz, Pawel           std::vector<std::string> iface_list;
3009391bb9cSRapkiewicz, Pawel           iface_list.reserve(resp.size());
3019391bb9cSRapkiewicz, Pawel           if (error_code) {
3029391bb9cSRapkiewicz, Pawel             // Something wrong on DBus, the error_code is not important at this
3039391bb9cSRapkiewicz, Pawel             // moment, just return success=false, and empty output. Since size
3049391bb9cSRapkiewicz, Pawel             // of vector may vary depending on information from Network Manager,
3059391bb9cSRapkiewicz, Pawel             // and empty output could not be treated same way as error.
3069391bb9cSRapkiewicz, Pawel             callback(false, iface_list);
3079391bb9cSRapkiewicz, Pawel             return;
3089391bb9cSRapkiewicz, Pawel           }
3099391bb9cSRapkiewicz, Pawel 
3109391bb9cSRapkiewicz, Pawel           // Iterate over all retrieved ObjectPaths.
3119391bb9cSRapkiewicz, Pawel           for (auto &objpath : resp) {
3129391bb9cSRapkiewicz, Pawel             // And all interfaces available for certain ObjectPath.
3139391bb9cSRapkiewicz, Pawel             for (auto &interface : objpath.second) {
3149391bb9cSRapkiewicz, Pawel               // If interface is xyz.openbmc_project.Network.EthernetInterface,
3159391bb9cSRapkiewicz, Pawel               // this is what we're looking for.
3169391bb9cSRapkiewicz, Pawel               if (interface.first ==
3179391bb9cSRapkiewicz, Pawel                   "xyz.openbmc_project.Network.EthernetInterface") {
318*aa2e59c1SEd Tanous                 // Cut out everyting until last "/", ...
319*aa2e59c1SEd Tanous                 const std::string iface_id =
320*aa2e59c1SEd Tanous                     static_cast<std::string>(objpath.first);
3219391bb9cSRapkiewicz, Pawel                 std::size_t last_pos = iface_id.rfind("/");
3229391bb9cSRapkiewicz, Pawel                 if (last_pos != std::string::npos) {
3239391bb9cSRapkiewicz, Pawel                   // and put it into output vector.
3249391bb9cSRapkiewicz, Pawel                   iface_list.emplace_back(iface_id.substr(last_pos + 1));
3259391bb9cSRapkiewicz, Pawel                 }
3269391bb9cSRapkiewicz, Pawel               }
3279391bb9cSRapkiewicz, Pawel             }
3289391bb9cSRapkiewicz, Pawel           }
329274fad5aSGunnar Mills           // Finally make a callback with useful data
3309391bb9cSRapkiewicz, Pawel           callback(true, iface_list);
3319391bb9cSRapkiewicz, Pawel         },
332*aa2e59c1SEd Tanous         "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
333*aa2e59c1SEd Tanous         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
3349391bb9cSRapkiewicz, Pawel   };
3359391bb9cSRapkiewicz, Pawel };
3369391bb9cSRapkiewicz, Pawel 
3379391bb9cSRapkiewicz, Pawel /**
3389391bb9cSRapkiewicz, Pawel  * EthernetCollection derived class for delivering Ethernet Collection Schema
3399391bb9cSRapkiewicz, Pawel  */
3409391bb9cSRapkiewicz, Pawel class EthernetCollection : public Node {
3419391bb9cSRapkiewicz, Pawel  public:
3429391bb9cSRapkiewicz, Pawel   template <typename CrowApp>
3439391bb9cSRapkiewicz, Pawel   // TODO(Pawel) Remove line from below, where we assume that there is only one
3449391bb9cSRapkiewicz, Pawel   // manager called openbmc This shall be generic, but requires to update
3459391bb9cSRapkiewicz, Pawel   // GetSubroutes method
3469391bb9cSRapkiewicz, Pawel   EthernetCollection(CrowApp &app)
3479391bb9cSRapkiewicz, Pawel       : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") {
3489391bb9cSRapkiewicz, Pawel     Node::json["@odata.type"] =
3499391bb9cSRapkiewicz, Pawel         "#EthernetInterfaceCollection.EthernetInterfaceCollection";
3509391bb9cSRapkiewicz, Pawel     Node::json["@odata.context"] =
3519391bb9cSRapkiewicz, Pawel         "/redfish/v1/"
3529391bb9cSRapkiewicz, Pawel         "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
3539391bb9cSRapkiewicz, Pawel     Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces";
3549391bb9cSRapkiewicz, Pawel     Node::json["Name"] = "Ethernet Network Interface Collection";
3559391bb9cSRapkiewicz, Pawel     Node::json["Description"] =
3569391bb9cSRapkiewicz, Pawel         "Collection of EthernetInterfaces for this Manager";
3579391bb9cSRapkiewicz, Pawel 
3589391bb9cSRapkiewicz, Pawel     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
3599391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::HEAD, {{"Login"}}},
3609391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}},
3619391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}},
3629391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}},
3639391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}};
3649391bb9cSRapkiewicz, Pawel   }
3659391bb9cSRapkiewicz, Pawel 
3669391bb9cSRapkiewicz, Pawel  private:
3679391bb9cSRapkiewicz, Pawel   /**
3689391bb9cSRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
3699391bb9cSRapkiewicz, Pawel    */
3709391bb9cSRapkiewicz, Pawel   void doGet(crow::response &res, const crow::request &req,
3719391bb9cSRapkiewicz, Pawel              const std::vector<std::string> &params) override {
3729391bb9cSRapkiewicz, Pawel     // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for
3739391bb9cSRapkiewicz, Pawel     // any Manager, not only hardcoded 'openbmc'.
3749391bb9cSRapkiewicz, Pawel     std::string manager_id = "openbmc";
3759391bb9cSRapkiewicz, Pawel 
3769391bb9cSRapkiewicz, Pawel     // Get eth interface list, and call the below callback for JSON preparation
3779391bb9cSRapkiewicz, Pawel     ethernet_provider.getEthernetIfaceList(
3789391bb9cSRapkiewicz, Pawel         [&, manager_id{std::move(manager_id)} ](
3799391bb9cSRapkiewicz, Pawel             const bool &success, const std::vector<std::string> &iface_list) {
3809391bb9cSRapkiewicz, Pawel           if (success) {
3819391bb9cSRapkiewicz, Pawel             nlohmann::json iface_array = nlohmann::json::array();
3829391bb9cSRapkiewicz, Pawel             for (const std::string &iface_item : iface_list) {
3839391bb9cSRapkiewicz, Pawel               iface_array.push_back(
3849391bb9cSRapkiewicz, Pawel                   {{"@odata.id", "/redfish/v1/Managers/" + manager_id +
3859391bb9cSRapkiewicz, Pawel                                      "/EthernetInterfaces/" + iface_item}});
3869391bb9cSRapkiewicz, Pawel             }
3879391bb9cSRapkiewicz, Pawel             Node::json["Members"] = iface_array;
3889391bb9cSRapkiewicz, Pawel             Node::json["Members@odata.count"] = iface_array.size();
3899391bb9cSRapkiewicz, Pawel             Node::json["@odata.id"] =
3909391bb9cSRapkiewicz, Pawel                 "/redfish/v1/Managers/" + manager_id + "/EthernetInterfaces";
3919391bb9cSRapkiewicz, Pawel             res.json_value = Node::json;
3929391bb9cSRapkiewicz, Pawel           } else {
3939391bb9cSRapkiewicz, Pawel             // No success, best what we can do is return INTERNALL ERROR
3949391bb9cSRapkiewicz, Pawel             res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
3959391bb9cSRapkiewicz, Pawel           }
3969391bb9cSRapkiewicz, Pawel           res.end();
3979391bb9cSRapkiewicz, Pawel         });
3989391bb9cSRapkiewicz, Pawel   }
3999391bb9cSRapkiewicz, Pawel 
4009391bb9cSRapkiewicz, Pawel   // Ethernet Provider object
4019391bb9cSRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
4029391bb9cSRapkiewicz, Pawel   OnDemandEthernetProvider ethernet_provider;
4039391bb9cSRapkiewicz, Pawel };
4049391bb9cSRapkiewicz, Pawel 
4059391bb9cSRapkiewicz, Pawel /**
4069391bb9cSRapkiewicz, Pawel  * EthernetInterface derived class for delivering Ethernet Schema
4079391bb9cSRapkiewicz, Pawel  */
4089391bb9cSRapkiewicz, Pawel class EthernetInterface : public Node {
4099391bb9cSRapkiewicz, Pawel  public:
4109391bb9cSRapkiewicz, Pawel   /*
4119391bb9cSRapkiewicz, Pawel    * Default Constructor
4129391bb9cSRapkiewicz, Pawel    */
4139391bb9cSRapkiewicz, Pawel   template <typename CrowApp>
4149391bb9cSRapkiewicz, Pawel   // TODO(Pawel) Remove line from below, where we assume that there is only one
4159391bb9cSRapkiewicz, Pawel   // manager called openbmc This shall be generic, but requires to update
4169391bb9cSRapkiewicz, Pawel   // GetSubroutes method
4179391bb9cSRapkiewicz, Pawel   EthernetInterface(CrowApp &app)
4189391bb9cSRapkiewicz, Pawel       : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/",
4199391bb9cSRapkiewicz, Pawel              std::string()) {
4209391bb9cSRapkiewicz, Pawel     Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface";
4219391bb9cSRapkiewicz, Pawel     Node::json["@odata.context"] =
4229391bb9cSRapkiewicz, Pawel         "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
4239391bb9cSRapkiewicz, Pawel     Node::json["Name"] = "Manager Ethernet Interface";
4249391bb9cSRapkiewicz, Pawel     Node::json["Description"] = "Management Network Interface";
4259391bb9cSRapkiewicz, Pawel 
4269391bb9cSRapkiewicz, Pawel     entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}},
4279391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::HEAD, {{"Login"}}},
4289391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}},
4299391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}},
4309391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}},
4319391bb9cSRapkiewicz, Pawel                         {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}};
4329391bb9cSRapkiewicz, Pawel   }
4339391bb9cSRapkiewicz, Pawel 
4349391bb9cSRapkiewicz, Pawel  private:
4359391bb9cSRapkiewicz, Pawel   /**
4369391bb9cSRapkiewicz, Pawel    * Functions triggers appropriate requests on DBus
4379391bb9cSRapkiewicz, Pawel    */
4389391bb9cSRapkiewicz, Pawel   void doGet(crow::response &res, const crow::request &req,
4399391bb9cSRapkiewicz, Pawel              const std::vector<std::string> &params) override {
4409391bb9cSRapkiewicz, Pawel     // TODO(Pawel) this shall be parametrized call (two params) to get
4419391bb9cSRapkiewicz, Pawel     // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
4429391bb9cSRapkiewicz, Pawel     // Check if there is required param, truly entering this shall be
4439391bb9cSRapkiewicz, Pawel     // impossible.
4449391bb9cSRapkiewicz, Pawel     if (params.size() != 1) {
4459391bb9cSRapkiewicz, Pawel       res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR);
4469391bb9cSRapkiewicz, Pawel       res.end();
4479391bb9cSRapkiewicz, Pawel       return;
4489391bb9cSRapkiewicz, Pawel     }
4499391bb9cSRapkiewicz, Pawel 
4509391bb9cSRapkiewicz, Pawel     const std::string &iface_id = params[0];
4519391bb9cSRapkiewicz, Pawel 
4529391bb9cSRapkiewicz, Pawel     // Get single eth interface data, and call the below callback for JSON
4539391bb9cSRapkiewicz, Pawel     // preparation
4549391bb9cSRapkiewicz, Pawel     ethernet_provider.getEthernetIfaceData(
4559391bb9cSRapkiewicz, Pawel         iface_id, [&, iface_id](const bool &success,
4569391bb9cSRapkiewicz, Pawel                                 const EthernetInterfaceData &eth_data,
4579391bb9cSRapkiewicz, Pawel                                 const std::vector<IPv4AddressData> &ipv4_data) {
4589391bb9cSRapkiewicz, Pawel           if (success) {
4599391bb9cSRapkiewicz, Pawel             // Copy JSON object to avoid race condition
4609391bb9cSRapkiewicz, Pawel             nlohmann::json json_response(Node::json);
4619391bb9cSRapkiewicz, Pawel 
4629391bb9cSRapkiewicz, Pawel             // Fill out obvious data...
4639391bb9cSRapkiewicz, Pawel             json_response["Id"] = iface_id;
4649391bb9cSRapkiewicz, Pawel             json_response["@odata.id"] =
4659391bb9cSRapkiewicz, Pawel                 "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + iface_id;
4669391bb9cSRapkiewicz, Pawel 
4679391bb9cSRapkiewicz, Pawel             // ... then the one from DBus, regarding eth iface...
4689391bb9cSRapkiewicz, Pawel             if (eth_data.speed != nullptr)
4699391bb9cSRapkiewicz, Pawel               json_response["SpeedMbps"] = *eth_data.speed;
4709391bb9cSRapkiewicz, Pawel 
4719391bb9cSRapkiewicz, Pawel             if (eth_data.mac_address != nullptr)
4729391bb9cSRapkiewicz, Pawel               json_response["MACAddress"] = *eth_data.mac_address;
4739391bb9cSRapkiewicz, Pawel 
4749391bb9cSRapkiewicz, Pawel             if (eth_data.hostname != nullptr)
4759391bb9cSRapkiewicz, Pawel               json_response["HostName"] = *eth_data.hostname;
4769391bb9cSRapkiewicz, Pawel 
477c7070ac2SKowalski, Kamil             if (eth_data.vlan_id != nullptr) {
478c7070ac2SKowalski, Kamil               json_response["VLAN"]["VLANEnable"] = true;
479c7070ac2SKowalski, Kamil               json_response["VLAN"]["VLANId"] = *eth_data.vlan_id;
480c7070ac2SKowalski, Kamil             }
481c7070ac2SKowalski, Kamil 
4829391bb9cSRapkiewicz, Pawel             // ... at last, check if there are IPv4 data and prepare appropriate
4839391bb9cSRapkiewicz, Pawel             // collection
4849391bb9cSRapkiewicz, Pawel             if (ipv4_data.size() > 0) {
4859391bb9cSRapkiewicz, Pawel               nlohmann::json ipv4_array = nlohmann::json::array();
4869391bb9cSRapkiewicz, Pawel               for (auto &ipv4_config : ipv4_data) {
4879391bb9cSRapkiewicz, Pawel                 nlohmann::json json_ipv4;
4889391bb9cSRapkiewicz, Pawel                 if (ipv4_config.address != nullptr) {
4899391bb9cSRapkiewicz, Pawel                   json_ipv4["Address"] = *ipv4_config.address;
4909391bb9cSRapkiewicz, Pawel                   if (ipv4_config.gateway != nullptr)
4919391bb9cSRapkiewicz, Pawel                     json_ipv4["Gateway"] = *ipv4_config.gateway;
4929391bb9cSRapkiewicz, Pawel 
4939391bb9cSRapkiewicz, Pawel                   json_ipv4["AddressOrigin"] = ipv4_config.origin;
4949391bb9cSRapkiewicz, Pawel                   json_ipv4["SubnetMask"] = ipv4_config.netmask;
4959391bb9cSRapkiewicz, Pawel 
4969391bb9cSRapkiewicz, Pawel                   ipv4_array.push_back(json_ipv4);
4979391bb9cSRapkiewicz, Pawel                 }
4989391bb9cSRapkiewicz, Pawel               }
4999391bb9cSRapkiewicz, Pawel               json_response["IPv4Addresses"] = ipv4_array;
5009391bb9cSRapkiewicz, Pawel             }
5019391bb9cSRapkiewicz, Pawel             res.json_value = std::move(json_response);
5029391bb9cSRapkiewicz, Pawel           } else {
5039391bb9cSRapkiewicz, Pawel             // ... otherwise return error
5049391bb9cSRapkiewicz, Pawel             // TODO(Pawel)consider distinguish between non existing object, and
5059391bb9cSRapkiewicz, Pawel             // other errors
5069391bb9cSRapkiewicz, Pawel             res.code = static_cast<int>(HttpRespCode::NOT_FOUND);
5079391bb9cSRapkiewicz, Pawel           }
5089391bb9cSRapkiewicz, Pawel           res.end();
5099391bb9cSRapkiewicz, Pawel         });
5109391bb9cSRapkiewicz, Pawel   }
5119391bb9cSRapkiewicz, Pawel 
5129391bb9cSRapkiewicz, Pawel   // Ethernet Provider object
5139391bb9cSRapkiewicz, Pawel   // TODO(Pawel) consider move it to singleton
5149391bb9cSRapkiewicz, Pawel   OnDemandEthernetProvider ethernet_provider;
5159391bb9cSRapkiewicz, Pawel };
5169391bb9cSRapkiewicz, Pawel 
5179391bb9cSRapkiewicz, Pawel }  // namespace redfish
518