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 */ 27aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 28aa2e59c1SEd Tanous std::string, 29aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 30aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 319391bb9cSRapkiewicz, Pawel 329391bb9cSRapkiewicz, Pawel using GetManagedObjectsType = boost::container::flat_map< 33aa2e59c1SEd Tanous sdbusplus::message::object_path, 34aa2e59c1SEd Tanous boost::container::flat_map< 35aa2e59c1SEd Tanous std::string, 36aa2e59c1SEd Tanous boost::container::flat_map< 37aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 38aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 39aa2e59c1SEd 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( 84aa2e59c1SEd Tanous const sdbusplus::message::object_path &objpath, 85aa2e59c1SEd 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 97aa2e59c1SEd 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) { 101aa2e59c1SEd 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> 108aa2e59c1SEd 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()) { 112aa2e59c1SEd 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 ðiface_id, 1229391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 1239391bb9cSRapkiewicz, Pawel EthernetInterfaceData ð_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 ðiface_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( 185daf36e2eSEd Tanous static_cast<const 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 ðiface_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, 252aa2e59c1SEd 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 }, 281aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 282aa2e59c1SEd 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, 296aa2e59c1SEd 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") { 318aa2e59c1SEd Tanous // Cut out everyting until last "/", ... 319daf36e2eSEd Tanous const std::string& iface_id = 320daf36e2eSEd Tanous static_cast<const 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 }, 332aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 333aa2e59c1SEd 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 358*e0d918bcSEd Tanous entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}, 359*e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 360*e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 361*e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 362*e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 363*e0d918bcSEd Tanous {boost::beast::http::verb::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> ¶ms) 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 394*e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_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 426*e0d918bcSEd Tanous entityPrivileges = {{boost::beast::http::verb::get, {{"Login"}}}, 427*e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 428*e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 429*e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 430*e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 431*e0d918bcSEd Tanous {boost::beast::http::verb::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> ¶ms) 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) { 445*e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_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 ð_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 506*e0d918bcSEd Tanous res.result(boost::beast::http::status::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