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