19391bb9cSRapkiewicz, Pawel /* 29391bb9cSRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation 39391bb9cSRapkiewicz, Pawel // 49391bb9cSRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License"); 59391bb9cSRapkiewicz, Pawel // you may not use this file except in compliance with the License. 69391bb9cSRapkiewicz, Pawel // You may obtain a copy of the License at 79391bb9cSRapkiewicz, Pawel // 89391bb9cSRapkiewicz, Pawel // http://www.apache.org/licenses/LICENSE-2.0 99391bb9cSRapkiewicz, Pawel // 109391bb9cSRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software 119391bb9cSRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS, 129391bb9cSRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139391bb9cSRapkiewicz, Pawel // See the License for the specific language governing permissions and 149391bb9cSRapkiewicz, Pawel // limitations under the License. 159391bb9cSRapkiewicz, Pawel */ 169391bb9cSRapkiewicz, Pawel #pragma once 179391bb9cSRapkiewicz, Pawel 18*179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 19588c3f0dSKowalski, Kamil #include <error_messages.hpp> 20*179db1d7SKowalski, Kamil #include <node.hpp> 21588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 229391bb9cSRapkiewicz, Pawel #include <boost/container/flat_map.hpp> 239391bb9cSRapkiewicz, Pawel 249391bb9cSRapkiewicz, Pawel namespace redfish { 259391bb9cSRapkiewicz, Pawel 269391bb9cSRapkiewicz, Pawel /** 279391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 289391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 299391bb9cSRapkiewicz, Pawel */ 30aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 31aa2e59c1SEd Tanous std::string, 32aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 33aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 349391bb9cSRapkiewicz, Pawel 359391bb9cSRapkiewicz, Pawel using GetManagedObjectsType = boost::container::flat_map< 36aa2e59c1SEd Tanous sdbusplus::message::object_path, 37aa2e59c1SEd Tanous boost::container::flat_map< 38aa2e59c1SEd Tanous std::string, 39aa2e59c1SEd Tanous boost::container::flat_map< 40aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 41aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 42aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>>>; 439391bb9cSRapkiewicz, Pawel 449391bb9cSRapkiewicz, Pawel /** 459391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 469391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider change everything to ptr, or to non-ptr values. 479391bb9cSRapkiewicz, Pawel */ 489391bb9cSRapkiewicz, Pawel struct IPv4AddressData { 49*179db1d7SKowalski, Kamil std::string id; 509391bb9cSRapkiewicz, Pawel const std::string *address; 519391bb9cSRapkiewicz, Pawel const std::string *domain; 529391bb9cSRapkiewicz, Pawel const std::string *gateway; 539391bb9cSRapkiewicz, Pawel std::string netmask; 549391bb9cSRapkiewicz, Pawel std::string origin; 559391bb9cSRapkiewicz, Pawel bool global; 56*179db1d7SKowalski, Kamil /** 57*179db1d7SKowalski, Kamil * @brief Operator< to enable sorting 58*179db1d7SKowalski, Kamil * 59*179db1d7SKowalski, Kamil * @param[in] obj Object to compare with 60*179db1d7SKowalski, Kamil * 61*179db1d7SKowalski, Kamil * @return This object id < supplied object id 62*179db1d7SKowalski, Kamil */ 63*179db1d7SKowalski, Kamil bool operator<(const IPv4AddressData &obj) const { return (id < obj.id); } 649391bb9cSRapkiewicz, Pawel }; 659391bb9cSRapkiewicz, Pawel 669391bb9cSRapkiewicz, Pawel /** 679391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 689391bb9cSRapkiewicz, Pawel * available from DBus 699391bb9cSRapkiewicz, Pawel */ 709391bb9cSRapkiewicz, Pawel struct EthernetInterfaceData { 719391bb9cSRapkiewicz, Pawel const unsigned int *speed; 729391bb9cSRapkiewicz, Pawel const bool *auto_neg; 739391bb9cSRapkiewicz, Pawel const std::string *hostname; 749391bb9cSRapkiewicz, Pawel const std::string *default_gateway; 759391bb9cSRapkiewicz, Pawel const std::string *mac_address; 76c7070ac2SKowalski, Kamil const unsigned int *vlan_id; 779391bb9cSRapkiewicz, Pawel }; 789391bb9cSRapkiewicz, Pawel 799391bb9cSRapkiewicz, Pawel /** 809391bb9cSRapkiewicz, Pawel * OnDemandEthernetProvider 81274fad5aSGunnar Mills * Ethernet provider class that retrieves data directly from dbus, before 82274fad5aSGunnar Mills * setting it into JSON output. This does not cache any data. 839391bb9cSRapkiewicz, Pawel * 849391bb9cSRapkiewicz, Pawel * TODO(Pawel) 859391bb9cSRapkiewicz, Pawel * This perhaps shall be different file, which has to be chosen on compile time 869391bb9cSRapkiewicz, Pawel * depending on OEM needs 879391bb9cSRapkiewicz, Pawel */ 889391bb9cSRapkiewicz, Pawel class OnDemandEthernetProvider { 899391bb9cSRapkiewicz, Pawel private: 909391bb9cSRapkiewicz, Pawel // Consts that may have influence on EthernetProvider performance/memory usage 919391bb9cSRapkiewicz, Pawel const size_t MAX_IPV4_ADDRESSES_PER_INTERFACE = 10; 929391bb9cSRapkiewicz, Pawel 939391bb9cSRapkiewicz, Pawel // Helper function that allows to extract GetAllPropertiesType from 949391bb9cSRapkiewicz, Pawel // GetManagedObjectsType, based on object path, and interface name 959391bb9cSRapkiewicz, Pawel const PropertiesMapType *extractInterfaceProperties( 96aa2e59c1SEd Tanous const sdbusplus::message::object_path &objpath, 97aa2e59c1SEd Tanous const std::string &interface, const GetManagedObjectsType &dbus_data) { 989391bb9cSRapkiewicz, Pawel const auto &dbus_obj = dbus_data.find(objpath); 999391bb9cSRapkiewicz, Pawel if (dbus_obj != dbus_data.end()) { 1009391bb9cSRapkiewicz, Pawel const auto &iface = dbus_obj->second.find(interface); 1019391bb9cSRapkiewicz, Pawel if (iface != dbus_obj->second.end()) { 1029391bb9cSRapkiewicz, Pawel return &iface->second; 1039391bb9cSRapkiewicz, Pawel } 1049391bb9cSRapkiewicz, Pawel } 1059391bb9cSRapkiewicz, Pawel return nullptr; 1069391bb9cSRapkiewicz, Pawel } 1079391bb9cSRapkiewicz, Pawel 1089391bb9cSRapkiewicz, Pawel // Helper Wrapper that does inline object_path conversion from string 109aa2e59c1SEd Tanous // into sdbusplus::message::object_path type 1109391bb9cSRapkiewicz, Pawel inline const PropertiesMapType *extractInterfaceProperties( 1119391bb9cSRapkiewicz, Pawel const std::string &objpath, const std::string &interface, 1129391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data) { 113aa2e59c1SEd Tanous const auto &dbus_obj = sdbusplus::message::object_path{objpath}; 1149391bb9cSRapkiewicz, Pawel return extractInterfaceProperties(dbus_obj, interface, dbus_data); 1159391bb9cSRapkiewicz, Pawel } 1169391bb9cSRapkiewicz, Pawel 1179391bb9cSRapkiewicz, Pawel // Helper function that allows to get pointer to the property from 1189391bb9cSRapkiewicz, Pawel // GetAllPropertiesType native, or extracted by GetAllPropertiesType 1199391bb9cSRapkiewicz, Pawel template <typename T> 120aa2e59c1SEd Tanous inline T const *const extractProperty(const PropertiesMapType &properties, 1219391bb9cSRapkiewicz, Pawel const std::string &name) { 1229391bb9cSRapkiewicz, Pawel const auto &property = properties.find(name); 1239391bb9cSRapkiewicz, Pawel if (property != properties.end()) { 124aa2e59c1SEd Tanous return mapbox::get_ptr<const T>(property->second); 1259391bb9cSRapkiewicz, Pawel } 1269391bb9cSRapkiewicz, Pawel return nullptr; 1279391bb9cSRapkiewicz, Pawel } 1289391bb9cSRapkiewicz, Pawel // TODO(Pawel) Consider to move the above functions to dbus 1299391bb9cSRapkiewicz, Pawel // generic_interfaces.hpp 1309391bb9cSRapkiewicz, Pawel 1319391bb9cSRapkiewicz, Pawel // Helper function that extracts data from several dbus objects and several 1329391bb9cSRapkiewicz, Pawel // interfaces required by single ethernet interface instance 1339391bb9cSRapkiewicz, Pawel void extractEthernetInterfaceData(const std::string ðiface_id, 1349391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 1359391bb9cSRapkiewicz, Pawel EthernetInterfaceData ð_data) { 1369391bb9cSRapkiewicz, Pawel // Extract data that contains MAC Address 1379391bb9cSRapkiewicz, Pawel const PropertiesMapType *mac_properties = extractInterfaceProperties( 1389391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/" + ethiface_id, 1399391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.MACAddress", dbus_data); 1409391bb9cSRapkiewicz, Pawel 1419391bb9cSRapkiewicz, Pawel if (mac_properties != nullptr) { 1429391bb9cSRapkiewicz, Pawel eth_data.mac_address = 1439391bb9cSRapkiewicz, Pawel extractProperty<std::string>(*mac_properties, "MACAddress"); 1449391bb9cSRapkiewicz, Pawel } 1459391bb9cSRapkiewicz, Pawel 146c7070ac2SKowalski, Kamil const PropertiesMapType *vlan_properties = extractInterfaceProperties( 147c7070ac2SKowalski, Kamil "/xyz/openbmc_project/network/" + ethiface_id, 148c7070ac2SKowalski, Kamil "xyz.openbmc_project.Network.VLAN", dbus_data); 149c7070ac2SKowalski, Kamil 150c7070ac2SKowalski, Kamil if (vlan_properties != nullptr) { 151c7070ac2SKowalski, Kamil eth_data.vlan_id = extractProperty<unsigned int>(*vlan_properties, "Id"); 152c7070ac2SKowalski, Kamil } 153c7070ac2SKowalski, Kamil 1549391bb9cSRapkiewicz, Pawel // Extract data that contains link information (auto negotiation and speed) 1559391bb9cSRapkiewicz, Pawel const PropertiesMapType *eth_properties = extractInterfaceProperties( 1569391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/" + ethiface_id, 1579391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface", dbus_data); 1589391bb9cSRapkiewicz, Pawel 1599391bb9cSRapkiewicz, Pawel if (eth_properties != nullptr) { 1609391bb9cSRapkiewicz, Pawel eth_data.auto_neg = extractProperty<bool>(*eth_properties, "AutoNeg"); 1619391bb9cSRapkiewicz, Pawel eth_data.speed = extractProperty<unsigned int>(*eth_properties, "Speed"); 1629391bb9cSRapkiewicz, Pawel } 1639391bb9cSRapkiewicz, Pawel 1649391bb9cSRapkiewicz, Pawel // Extract data that contains network config (HostName and DefaultGW) 1659391bb9cSRapkiewicz, Pawel const PropertiesMapType *config_properties = extractInterfaceProperties( 1669391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/config", 1679391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.SystemConfiguration", dbus_data); 1689391bb9cSRapkiewicz, Pawel 1699391bb9cSRapkiewicz, Pawel if (config_properties != nullptr) { 1709391bb9cSRapkiewicz, Pawel eth_data.hostname = 1719391bb9cSRapkiewicz, Pawel extractProperty<std::string>(*config_properties, "HostName"); 1729391bb9cSRapkiewicz, Pawel eth_data.default_gateway = 1739391bb9cSRapkiewicz, Pawel extractProperty<std::string>(*config_properties, "DefaultGateway"); 1749391bb9cSRapkiewicz, Pawel } 1759391bb9cSRapkiewicz, Pawel } 1769391bb9cSRapkiewicz, Pawel 1779391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 1789391bb9cSRapkiewicz, Pawel // into full dot notation 1799391bb9cSRapkiewicz, Pawel inline std::string getNetmask(unsigned int bits) { 1809391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 1819391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 1829391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 1839391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 1849391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 1859391bb9cSRapkiewicz, Pawel return netmask; 1869391bb9cSRapkiewicz, Pawel } 1879391bb9cSRapkiewicz, Pawel 1889391bb9cSRapkiewicz, Pawel // Helper function that extracts data for single ethernet ipv4 address 1899391bb9cSRapkiewicz, Pawel void extractIPv4Data(const std::string ðiface_id, 1909391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 1919391bb9cSRapkiewicz, Pawel std::vector<IPv4AddressData> &ipv4_config) { 192*179db1d7SKowalski, Kamil const std::string pathStart = 193*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 194*179db1d7SKowalski, Kamil 1959391bb9cSRapkiewicz, Pawel // Since there might be several IPv4 configurations aligned with 1969391bb9cSRapkiewicz, Pawel // single ethernet interface, loop over all of them 1979391bb9cSRapkiewicz, Pawel for (auto &objpath : dbus_data) { 198274fad5aSGunnar Mills // Check if proper patter for object path appears 1999391bb9cSRapkiewicz, Pawel if (boost::starts_with( 200daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first), 2019391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/")) { 2029391bb9cSRapkiewicz, Pawel // and get approrpiate interface 2039391bb9cSRapkiewicz, Pawel const auto &interface = 2049391bb9cSRapkiewicz, Pawel objpath.second.find("xyz.openbmc_project.Network.IP"); 2059391bb9cSRapkiewicz, Pawel if (interface != objpath.second.end()) { 2069391bb9cSRapkiewicz, Pawel // Make a properties 'shortcut', to make everything more readable 2079391bb9cSRapkiewicz, Pawel const PropertiesMapType &properties = interface->second; 2089391bb9cSRapkiewicz, Pawel // Instance IPv4AddressData structure, and set as appropriate 2099391bb9cSRapkiewicz, Pawel IPv4AddressData ipv4_address; 210*179db1d7SKowalski, Kamil 211*179db1d7SKowalski, Kamil ipv4_address.id = static_cast<const std::string &>(objpath.first) 212*179db1d7SKowalski, Kamil .substr(pathStart.size()); 213*179db1d7SKowalski, Kamil 2149391bb9cSRapkiewicz, Pawel // IPv4 address 2159391bb9cSRapkiewicz, Pawel ipv4_address.address = 2169391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Address"); 2179391bb9cSRapkiewicz, Pawel // IPv4 gateway 2189391bb9cSRapkiewicz, Pawel ipv4_address.gateway = 2199391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Gateway"); 2209391bb9cSRapkiewicz, Pawel 2219391bb9cSRapkiewicz, Pawel // Origin is kind of DBus object so fetch pointer... 2229391bb9cSRapkiewicz, Pawel const std::string *origin = 2239391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Origin"); 2249391bb9cSRapkiewicz, Pawel if (origin != nullptr) { 225*179db1d7SKowalski, Kamil ipv4_address.origin = 226*179db1d7SKowalski, Kamil translateAddressOriginBetweenDBusAndRedfish(origin, true, true); 2279391bb9cSRapkiewicz, Pawel } 2289391bb9cSRapkiewicz, Pawel 2299391bb9cSRapkiewicz, Pawel // Netmask is presented as PrefixLength 2309391bb9cSRapkiewicz, Pawel const auto *mask = 2319391bb9cSRapkiewicz, Pawel extractProperty<uint8_t>(properties, "PrefixLength"); 2329391bb9cSRapkiewicz, Pawel if (mask != nullptr) { 2339391bb9cSRapkiewicz, Pawel // convert it to the string 2349391bb9cSRapkiewicz, Pawel ipv4_address.netmask = getNetmask(*mask); 2359391bb9cSRapkiewicz, Pawel } 2369391bb9cSRapkiewicz, Pawel 2379391bb9cSRapkiewicz, Pawel // Attach IPv4 only if address is present 2389391bb9cSRapkiewicz, Pawel if (ipv4_address.address != nullptr) { 239274fad5aSGunnar Mills // Check if given address is local, or global 2409391bb9cSRapkiewicz, Pawel if (boost::starts_with(*ipv4_address.address, "169.254")) { 2419391bb9cSRapkiewicz, Pawel ipv4_address.global = false; 2429391bb9cSRapkiewicz, Pawel } else { 2439391bb9cSRapkiewicz, Pawel ipv4_address.global = true; 2449391bb9cSRapkiewicz, Pawel } 2459391bb9cSRapkiewicz, Pawel ipv4_config.emplace_back(std::move(ipv4_address)); 2469391bb9cSRapkiewicz, Pawel } 2479391bb9cSRapkiewicz, Pawel } 2489391bb9cSRapkiewicz, Pawel } 2499391bb9cSRapkiewicz, Pawel } 250*179db1d7SKowalski, Kamil 251*179db1d7SKowalski, Kamil /** 252*179db1d7SKowalski, Kamil * We have to sort this vector and ensure that order of IPv4 addresses 253*179db1d7SKowalski, Kamil * is consistent between GETs to allow modification and deletion in PATCHes 254*179db1d7SKowalski, Kamil */ 255*179db1d7SKowalski, Kamil std::sort(ipv4_config.begin(), ipv4_config.end()); 2569391bb9cSRapkiewicz, Pawel } 2579391bb9cSRapkiewicz, Pawel 258*179db1d7SKowalski, Kamil static const constexpr int ipV4AddressSectionsCount = 4; 259*179db1d7SKowalski, Kamil 2609391bb9cSRapkiewicz, Pawel public: 2619391bb9cSRapkiewicz, Pawel /** 262588c3f0dSKowalski, Kamil * @brief Creates VLAN for given interface with given Id through D-Bus 263588c3f0dSKowalski, Kamil * 264588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of interface for which VLAN will be created 265588c3f0dSKowalski, Kamil * @param[in] inputVlanId ID of the new VLAN 266588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 267588c3f0dSKowalski, Kamil * 268588c3f0dSKowalski, Kamil * @return None. 269588c3f0dSKowalski, Kamil */ 270588c3f0dSKowalski, Kamil template <typename CallbackFunc> 271588c3f0dSKowalski, Kamil void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId, 272588c3f0dSKowalski, Kamil CallbackFunc &&callback) { 273588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 274588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 275588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId, 276588c3f0dSKowalski, Kamil static_cast<uint32_t>(inputVlanId)); 277588c3f0dSKowalski, Kamil }; 278588c3f0dSKowalski, Kamil 279588c3f0dSKowalski, Kamil /** 280588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 281588c3f0dSKowalski, Kamil * 282588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 283588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 284588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 285588c3f0dSKowalski, Kamil * 286588c3f0dSKowalski, Kamil * @return None. 287588c3f0dSKowalski, Kamil */ 288588c3f0dSKowalski, Kamil template <typename CallbackFunc> 289588c3f0dSKowalski, Kamil void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 290588c3f0dSKowalski, Kamil CallbackFunc &&callback) { 291588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 292588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 293588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 294588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 295588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 296588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 297588c3f0dSKowalski, Kamil }; 298588c3f0dSKowalski, Kamil 299588c3f0dSKowalski, Kamil /** 300*179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 301*179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 302*179db1d7SKowalski, Kamil * bit count for Subnet Mask. 303*179db1d7SKowalski, Kamil * 304*179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 305*179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 306*179db1d7SKowalski, Kamil * 307*179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 308*179db1d7SKowalski, Kamil */ 309*179db1d7SKowalski, Kamil bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 310*179db1d7SKowalski, Kamil uint8_t *bits = nullptr) { 311*179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 312*179db1d7SKowalski, Kamil 313*179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 314*179db1d7SKowalski, Kamil 315*179db1d7SKowalski, Kamil if (bytesInMask.size() != ipV4AddressSectionsCount) { 316*179db1d7SKowalski, Kamil return false; 317*179db1d7SKowalski, Kamil } 318*179db1d7SKowalski, Kamil 319*179db1d7SKowalski, Kamil if (bits != nullptr) { 320*179db1d7SKowalski, Kamil *bits = 0; 321*179db1d7SKowalski, Kamil } 322*179db1d7SKowalski, Kamil 323*179db1d7SKowalski, Kamil char *endPtr; 324*179db1d7SKowalski, Kamil long previousValue = 255; 325*179db1d7SKowalski, Kamil bool firstZeroInByteHit; 326*179db1d7SKowalski, Kamil for (uint8_t byteIdx = 0; byteIdx < ipV4AddressSectionsCount; byteIdx++) { 327*179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 328*179db1d7SKowalski, Kamil long value = std::strtol(bytesInMask[byteIdx].c_str(), &endPtr, 10); 329*179db1d7SKowalski, Kamil 330*179db1d7SKowalski, Kamil // endPtr should point to the end of the string, otherwise given string 331*179db1d7SKowalski, Kamil // is not 100% number 332*179db1d7SKowalski, Kamil if (*endPtr != '\0') { 333*179db1d7SKowalski, Kamil return false; 334*179db1d7SKowalski, Kamil } 335*179db1d7SKowalski, Kamil 336*179db1d7SKowalski, Kamil // Value should be contained in byte 337*179db1d7SKowalski, Kamil if (value < 0 || value > 255) { 338*179db1d7SKowalski, Kamil return false; 339*179db1d7SKowalski, Kamil } 340*179db1d7SKowalski, Kamil 341*179db1d7SKowalski, Kamil if (bits != nullptr) { 342*179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 343*179db1d7SKowalski, Kamil if (previousValue != 255 && value != 0) { 344*179db1d7SKowalski, Kamil return false; 345*179db1d7SKowalski, Kamil } 346*179db1d7SKowalski, Kamil 347*179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 348*179db1d7SKowalski, Kamil firstZeroInByteHit = false; 349*179db1d7SKowalski, Kamil 350*179db1d7SKowalski, Kamil // Count bits 351*179db1d7SKowalski, Kamil for (int bitIdx = 7; bitIdx >= 0; bitIdx--) { 352*179db1d7SKowalski, Kamil if (value & (1 << bitIdx)) { 353*179db1d7SKowalski, Kamil if (firstZeroInByteHit) { 354*179db1d7SKowalski, Kamil // Continuity not preserved 355*179db1d7SKowalski, Kamil return false; 356*179db1d7SKowalski, Kamil } else { 357*179db1d7SKowalski, Kamil (*bits)++; 358*179db1d7SKowalski, Kamil } 359*179db1d7SKowalski, Kamil } else { 360*179db1d7SKowalski, Kamil firstZeroInByteHit = true; 361*179db1d7SKowalski, Kamil } 362*179db1d7SKowalski, Kamil } 363*179db1d7SKowalski, Kamil } 364*179db1d7SKowalski, Kamil 365*179db1d7SKowalski, Kamil previousValue = value; 366*179db1d7SKowalski, Kamil } 367*179db1d7SKowalski, Kamil 368*179db1d7SKowalski, Kamil return true; 369*179db1d7SKowalski, Kamil } 370*179db1d7SKowalski, Kamil 371*179db1d7SKowalski, Kamil /** 372*179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 373*179db1d7SKowalski, Kamil * 374*179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 375*179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 376*179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 377*179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 378*179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 379*179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 380*179db1d7SKowalski, Kamil * 381*179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 382*179db1d7SKowalski, Kamil * otherwise 383*179db1d7SKowalski, Kamil */ 384*179db1d7SKowalski, Kamil void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx, 385*179db1d7SKowalski, Kamil const std::string &ipHash, 386*179db1d7SKowalski, Kamil const std::string &name, 387*179db1d7SKowalski, Kamil const std::string &newValue, 388*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 389*179db1d7SKowalski, Kamil auto callback = [ 390*179db1d7SKowalski, Kamil asyncResp, ipIdx{std::move(ipIdx)}, name{std::move(name)}, 391*179db1d7SKowalski, Kamil newValue{std::move(newValue)} 392*179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 393*179db1d7SKowalski, Kamil if (ec) { 394*179db1d7SKowalski, Kamil messages::addMessageToJson( 395*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 396*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 397*179db1d7SKowalski, Kamil } else { 398*179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx][name] = newValue; 399*179db1d7SKowalski, Kamil } 400*179db1d7SKowalski, Kamil }; 401*179db1d7SKowalski, Kamil 402*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 403*179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 404*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 405*179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 406*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 407*179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 408*179db1d7SKowalski, Kamil }; 409*179db1d7SKowalski, Kamil 410*179db1d7SKowalski, Kamil /** 411*179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 412*179db1d7SKowalski, Kamil * 413*179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 414*179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 415*179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 416*179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 417*179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 418*179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 419*179db1d7SKowalski, Kamil * 420*179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 421*179db1d7SKowalski, Kamil * otherwise 422*179db1d7SKowalski, Kamil */ 423*179db1d7SKowalski, Kamil void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 424*179db1d7SKowalski, Kamil const std::string &ipHash, const std::string &newValue, 425*179db1d7SKowalski, Kamil const std::string &newValueDbus, 426*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 427*179db1d7SKowalski, Kamil auto callback = 428*179db1d7SKowalski, Kamil [ asyncResp, ipIdx{std::move(ipIdx)}, 429*179db1d7SKowalski, Kamil newValue{std::move(newValue)} ](const boost::system::error_code ec) { 430*179db1d7SKowalski, Kamil if (ec) { 431*179db1d7SKowalski, Kamil messages::addMessageToJson( 432*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 433*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin"); 434*179db1d7SKowalski, Kamil } else { 435*179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx]["AddressOrigin"] = 436*179db1d7SKowalski, Kamil newValue; 437*179db1d7SKowalski, Kamil } 438*179db1d7SKowalski, Kamil }; 439*179db1d7SKowalski, Kamil 440*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 441*179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 442*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 443*179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 444*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 445*179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 446*179db1d7SKowalski, Kamil }; 447*179db1d7SKowalski, Kamil 448*179db1d7SKowalski, Kamil /** 449*179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 450*179db1d7SKowalski, Kamil * 451*179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 452*179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 453*179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 454*179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 455*179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 456*179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 457*179db1d7SKowalski, Kamil * 458*179db1d7SKowalski, Kamil * @return None 459*179db1d7SKowalski, Kamil */ 460*179db1d7SKowalski, Kamil void changeIPv4SubnetMaskProperty( 461*179db1d7SKowalski, Kamil const std::string &ifaceId, int ipIdx, const std::string &ipHash, 462*179db1d7SKowalski, Kamil const std::string &newValueStr, uint8_t &newValue, 463*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 464*179db1d7SKowalski, Kamil auto callback = [ 465*179db1d7SKowalski, Kamil asyncResp, ipIdx{std::move(ipIdx)}, newValueStr{std::move(newValueStr)} 466*179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 467*179db1d7SKowalski, Kamil if (ec) { 468*179db1d7SKowalski, Kamil messages::addMessageToJson( 469*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 470*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 471*179db1d7SKowalski, Kamil } else { 472*179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx]["SubnetMask"] = 473*179db1d7SKowalski, Kamil newValueStr; 474*179db1d7SKowalski, Kamil } 475*179db1d7SKowalski, Kamil }; 476*179db1d7SKowalski, Kamil 477*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 478*179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 479*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 480*179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 481*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 482*179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 483*179db1d7SKowalski, Kamil }; 484*179db1d7SKowalski, Kamil 485*179db1d7SKowalski, Kamil /** 486588c3f0dSKowalski, Kamil * @brief Disables VLAN with given ifaceId 487588c3f0dSKowalski, Kamil * 488588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be disabled 489588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 490588c3f0dSKowalski, Kamil * 491588c3f0dSKowalski, Kamil * @return None. 492588c3f0dSKowalski, Kamil */ 493588c3f0dSKowalski, Kamil template <typename CallbackFunc> 494588c3f0dSKowalski, Kamil void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) { 495588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 496588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 497588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 498588c3f0dSKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 499588c3f0dSKowalski, Kamil }; 500588c3f0dSKowalski, Kamil 501588c3f0dSKowalski, Kamil /** 502588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 503588c3f0dSKowalski, Kamil * 504588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 505588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 506588c3f0dSKowalski, Kamil * 507588c3f0dSKowalski, Kamil * @return None. 508588c3f0dSKowalski, Kamil */ 509588c3f0dSKowalski, Kamil template <typename CallbackFunc> 510588c3f0dSKowalski, Kamil void setHostName(const std::string &newHostname, CallbackFunc &&callback) { 511588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 512588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 513588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 514588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 515588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 516588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 517588c3f0dSKowalski, Kamil }; 518588c3f0dSKowalski, Kamil 519588c3f0dSKowalski, Kamil /** 520*179db1d7SKowalski, Kamil * @brief Deletes given IPv4 521*179db1d7SKowalski, Kamil * 522*179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 523*179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be deleted 524*179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 525*179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 526*179db1d7SKowalski, Kamil * 527*179db1d7SKowalski, Kamil * @return None 528*179db1d7SKowalski, Kamil */ 529*179db1d7SKowalski, Kamil void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 530*179db1d7SKowalski, Kamil unsigned int ipIdx, 531*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 532*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 533*179db1d7SKowalski, Kamil [ ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} ]( 534*179db1d7SKowalski, Kamil const boost::system::error_code ec) { 535*179db1d7SKowalski, Kamil if (ec) { 536*179db1d7SKowalski, Kamil messages::addMessageToJson( 537*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 538*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 539*179db1d7SKowalski, Kamil } else { 540*179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx] = nullptr; 541*179db1d7SKowalski, Kamil } 542*179db1d7SKowalski, Kamil }, 543*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 544*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 545*179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 546*179db1d7SKowalski, Kamil } 547*179db1d7SKowalski, Kamil 548*179db1d7SKowalski, Kamil /** 549*179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 550*179db1d7SKowalski, Kamil * 551*179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 552*179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be deleted 553*179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 554*179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 555*179db1d7SKowalski, Kamil * 556*179db1d7SKowalski, Kamil * @return None 557*179db1d7SKowalski, Kamil */ 558*179db1d7SKowalski, Kamil void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 559*179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 560*179db1d7SKowalski, Kamil const std::string &address, 561*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 562*179db1d7SKowalski, Kamil auto createIpHandler = [ 563*179db1d7SKowalski, Kamil ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} 564*179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 565*179db1d7SKowalski, Kamil if (ec) { 566*179db1d7SKowalski, Kamil messages::addMessageToJson( 567*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 568*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 569*179db1d7SKowalski, Kamil } 570*179db1d7SKowalski, Kamil }; 571*179db1d7SKowalski, Kamil 572*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 573*179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 574*179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 575*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 576*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 577*179db1d7SKowalski, Kamil gateway); 578*179db1d7SKowalski, Kamil } 579*179db1d7SKowalski, Kamil 580*179db1d7SKowalski, Kamil /** 581*179db1d7SKowalski, Kamil * @brief Translates Address Origin value from D-Bus to Redfish format and 582*179db1d7SKowalski, Kamil * vice-versa 583*179db1d7SKowalski, Kamil * 584*179db1d7SKowalski, Kamil * @param[in] inputOrigin Input value that should be translated 585*179db1d7SKowalski, Kamil * @param[in] isIPv4 True for IPv4 origins, False for IPv6 586*179db1d7SKowalski, Kamil * @param[in] isFromDBus True for DBus->Redfish conversion, false for reverse 587*179db1d7SKowalski, Kamil * 588*179db1d7SKowalski, Kamil * @return Empty string in case of failure, translated value otherwise 589*179db1d7SKowalski, Kamil */ 590*179db1d7SKowalski, Kamil std::string translateAddressOriginBetweenDBusAndRedfish( 591*179db1d7SKowalski, Kamil const std::string *inputOrigin, bool isIPv4, bool isFromDBus) { 592*179db1d7SKowalski, Kamil // Invalid pointer 593*179db1d7SKowalski, Kamil if (inputOrigin == nullptr) { 594*179db1d7SKowalski, Kamil return ""; 595*179db1d7SKowalski, Kamil } 596*179db1d7SKowalski, Kamil 597*179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv4OnlyIdx = 1; 598*179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv6OnlyIdx = 3; 599*179db1d7SKowalski, Kamil 600*179db1d7SKowalski, Kamil std::array<std::pair<const char *, const char *>, 6> translationTable{ 601*179db1d7SKowalski, Kamil {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"}, 602*179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"}, 603*179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 604*179db1d7SKowalski, Kamil "IPv4LinkLocal"}, 605*179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"}, 606*179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 607*179db1d7SKowalski, Kamil "LinkLocal"}, 608*179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}}; 609*179db1d7SKowalski, Kamil 610*179db1d7SKowalski, Kamil for (unsigned int i = 0; i < translationTable.size(); i++) { 611*179db1d7SKowalski, Kamil // Skip unrelated 612*179db1d7SKowalski, Kamil if (isIPv4 && i >= firstIPv6OnlyIdx) break; 613*179db1d7SKowalski, Kamil if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) continue; 614*179db1d7SKowalski, Kamil 615*179db1d7SKowalski, Kamil // When translating D-Bus to Redfish compare input to first element 616*179db1d7SKowalski, Kamil if (isFromDBus && translationTable[i].first == *inputOrigin) 617*179db1d7SKowalski, Kamil return translationTable[i].second; 618*179db1d7SKowalski, Kamil 619*179db1d7SKowalski, Kamil // When translating Redfish to D-Bus compare input to second element 620*179db1d7SKowalski, Kamil if (!isFromDBus && translationTable[i].second == *inputOrigin) 621*179db1d7SKowalski, Kamil return translationTable[i].first; 622*179db1d7SKowalski, Kamil } 623*179db1d7SKowalski, Kamil 624*179db1d7SKowalski, Kamil // If we are still here, that means that value has not been found 625*179db1d7SKowalski, Kamil return ""; 626*179db1d7SKowalski, Kamil } 627*179db1d7SKowalski, Kamil 628*179db1d7SKowalski, Kamil /** 629*179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 630*179db1d7SKowalski, Kamil * Object 631*179db1d7SKowalski, Kamil * from EntityManager Network Manager 632*179db1d7SKowalski, Kamil * @param ethiface_id a eth interface id to query on DBus 633*179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 634*179db1d7SKowalski, Kamil * into JSON 635*179db1d7SKowalski, Kamil */ 636*179db1d7SKowalski, Kamil template <typename CallbackFunc> 637*179db1d7SKowalski, Kamil void getEthernetIfaceData(const std::string ðiface_id, 638*179db1d7SKowalski, Kamil CallbackFunc &&callback) { 639*179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 640*179db1d7SKowalski, Kamil [ 641*179db1d7SKowalski, Kamil this, ethiface_id{std::move(ethiface_id)}, 642*179db1d7SKowalski, Kamil callback{std::move(callback)} 643*179db1d7SKowalski, Kamil ](const boost::system::error_code error_code, 644*179db1d7SKowalski, Kamil const GetManagedObjectsType &resp) { 645*179db1d7SKowalski, Kamil 646*179db1d7SKowalski, Kamil EthernetInterfaceData eth_data{}; 647*179db1d7SKowalski, Kamil std::vector<IPv4AddressData> ipv4_data; 648*179db1d7SKowalski, Kamil ipv4_data.reserve(MAX_IPV4_ADDRESSES_PER_INTERFACE); 649*179db1d7SKowalski, Kamil 650*179db1d7SKowalski, Kamil if (error_code) { 651*179db1d7SKowalski, Kamil // Something wrong on DBus, the error_code is not important at 652*179db1d7SKowalski, Kamil // this moment, just return success=false, and empty output. Since 653*179db1d7SKowalski, Kamil // size of vector may vary depending on information from Network 654*179db1d7SKowalski, Kamil // Manager, and empty output could not be treated same way as 655*179db1d7SKowalski, Kamil // error. 656*179db1d7SKowalski, Kamil callback(false, eth_data, ipv4_data); 657*179db1d7SKowalski, Kamil return; 658*179db1d7SKowalski, Kamil } 659*179db1d7SKowalski, Kamil 660*179db1d7SKowalski, Kamil extractEthernetInterfaceData(ethiface_id, resp, eth_data); 661*179db1d7SKowalski, Kamil extractIPv4Data(ethiface_id, resp, ipv4_data); 662*179db1d7SKowalski, Kamil 663*179db1d7SKowalski, Kamil // Fix global GW 664*179db1d7SKowalski, Kamil for (IPv4AddressData &ipv4 : ipv4_data) { 665*179db1d7SKowalski, Kamil if ((ipv4.global) && 666*179db1d7SKowalski, Kamil ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) { 667*179db1d7SKowalski, Kamil ipv4.gateway = eth_data.default_gateway; 668*179db1d7SKowalski, Kamil } 669*179db1d7SKowalski, Kamil } 670*179db1d7SKowalski, Kamil 671*179db1d7SKowalski, Kamil // Finally make a callback with usefull data 672*179db1d7SKowalski, Kamil callback(true, eth_data, ipv4_data); 673*179db1d7SKowalski, Kamil }, 674*179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 675*179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 676*179db1d7SKowalski, Kamil }; 677*179db1d7SKowalski, Kamil 678*179db1d7SKowalski, Kamil /** 6799391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6809391bb9cSRapkiewicz, Pawel * Manager 6819391bb9cSRapkiewicz, Pawel * @param callback a function that shall be called to convert Dbus output into 6829391bb9cSRapkiewicz, Pawel * JSON. 6839391bb9cSRapkiewicz, Pawel */ 6849391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 6859391bb9cSRapkiewicz, Pawel void getEthernetIfaceList(CallbackFunc &&callback) { 6869391bb9cSRapkiewicz, Pawel crow::connections::system_bus->async_method_call( 6879391bb9cSRapkiewicz, Pawel [ this, callback{std::move(callback)} ]( 6889391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 689aa2e59c1SEd Tanous GetManagedObjectsType &resp) { 6909391bb9cSRapkiewicz, Pawel // Callback requires vector<string> to retrieve all available ethernet 6919391bb9cSRapkiewicz, Pawel // interfaces 6929391bb9cSRapkiewicz, Pawel std::vector<std::string> iface_list; 6939391bb9cSRapkiewicz, Pawel iface_list.reserve(resp.size()); 6949391bb9cSRapkiewicz, Pawel if (error_code) { 6959391bb9cSRapkiewicz, Pawel // Something wrong on DBus, the error_code is not important at this 6969391bb9cSRapkiewicz, Pawel // moment, just return success=false, and empty output. Since size 6979391bb9cSRapkiewicz, Pawel // of vector may vary depending on information from Network Manager, 6989391bb9cSRapkiewicz, Pawel // and empty output could not be treated same way as error. 6999391bb9cSRapkiewicz, Pawel callback(false, iface_list); 7009391bb9cSRapkiewicz, Pawel return; 7019391bb9cSRapkiewicz, Pawel } 7029391bb9cSRapkiewicz, Pawel 7039391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7049391bb9cSRapkiewicz, Pawel for (auto &objpath : resp) { 7059391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7069391bb9cSRapkiewicz, Pawel for (auto &interface : objpath.second) { 7079391bb9cSRapkiewicz, Pawel // If interface is xyz.openbmc_project.Network.EthernetInterface, 7089391bb9cSRapkiewicz, Pawel // this is what we're looking for. 7099391bb9cSRapkiewicz, Pawel if (interface.first == 7109391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface") { 711aa2e59c1SEd Tanous // Cut out everyting until last "/", ... 712daf36e2eSEd Tanous const std::string &iface_id = 713daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first); 7149391bb9cSRapkiewicz, Pawel std::size_t last_pos = iface_id.rfind("/"); 7159391bb9cSRapkiewicz, Pawel if (last_pos != std::string::npos) { 7169391bb9cSRapkiewicz, Pawel // and put it into output vector. 7179391bb9cSRapkiewicz, Pawel iface_list.emplace_back(iface_id.substr(last_pos + 1)); 7189391bb9cSRapkiewicz, Pawel } 7199391bb9cSRapkiewicz, Pawel } 7209391bb9cSRapkiewicz, Pawel } 7219391bb9cSRapkiewicz, Pawel } 722274fad5aSGunnar Mills // Finally make a callback with useful data 7239391bb9cSRapkiewicz, Pawel callback(true, iface_list); 7249391bb9cSRapkiewicz, Pawel }, 725aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 726aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7279391bb9cSRapkiewicz, Pawel }; 7289391bb9cSRapkiewicz, Pawel }; 7299391bb9cSRapkiewicz, Pawel 7309391bb9cSRapkiewicz, Pawel /** 7319391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7329391bb9cSRapkiewicz, Pawel */ 7339391bb9cSRapkiewicz, Pawel class EthernetCollection : public Node { 7349391bb9cSRapkiewicz, Pawel public: 7359391bb9cSRapkiewicz, Pawel template <typename CrowApp> 7369391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 7379391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 7389391bb9cSRapkiewicz, Pawel // GetSubroutes method 7399391bb9cSRapkiewicz, Pawel EthernetCollection(CrowApp &app) 7409391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") { 7419391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7429391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7439391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7449391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7459391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7469391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces"; 7479391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7489391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7499391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7509391bb9cSRapkiewicz, Pawel 751588c3f0dSKowalski, Kamil entityPrivileges = { 752588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 753e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 754e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 755e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 756e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 757e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7589391bb9cSRapkiewicz, Pawel } 7599391bb9cSRapkiewicz, Pawel 7609391bb9cSRapkiewicz, Pawel private: 7619391bb9cSRapkiewicz, Pawel /** 7629391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7639391bb9cSRapkiewicz, Pawel */ 7649391bb9cSRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 7659391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 7669391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 7679391bb9cSRapkiewicz, Pawel // any Manager, not only hardcoded 'openbmc'. 7689391bb9cSRapkiewicz, Pawel std::string manager_id = "openbmc"; 7699391bb9cSRapkiewicz, Pawel 7709391bb9cSRapkiewicz, Pawel // Get eth interface list, and call the below callback for JSON preparation 7719391bb9cSRapkiewicz, Pawel ethernet_provider.getEthernetIfaceList( 7729391bb9cSRapkiewicz, Pawel [&, manager_id{std::move(manager_id)} ]( 7739391bb9cSRapkiewicz, Pawel const bool &success, const std::vector<std::string> &iface_list) { 7749391bb9cSRapkiewicz, Pawel if (success) { 7759391bb9cSRapkiewicz, Pawel nlohmann::json iface_array = nlohmann::json::array(); 7769391bb9cSRapkiewicz, Pawel for (const std::string &iface_item : iface_list) { 7779391bb9cSRapkiewicz, Pawel iface_array.push_back( 7789391bb9cSRapkiewicz, Pawel {{"@odata.id", "/redfish/v1/Managers/" + manager_id + 7799391bb9cSRapkiewicz, Pawel "/EthernetInterfaces/" + iface_item}}); 7809391bb9cSRapkiewicz, Pawel } 7819391bb9cSRapkiewicz, Pawel Node::json["Members"] = iface_array; 7829391bb9cSRapkiewicz, Pawel Node::json["Members@odata.count"] = iface_array.size(); 7839391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = 7849391bb9cSRapkiewicz, Pawel "/redfish/v1/Managers/" + manager_id + "/EthernetInterfaces"; 7859391bb9cSRapkiewicz, Pawel res.json_value = Node::json; 7869391bb9cSRapkiewicz, Pawel } else { 7879391bb9cSRapkiewicz, Pawel // No success, best what we can do is return INTERNALL ERROR 788e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 7899391bb9cSRapkiewicz, Pawel } 7909391bb9cSRapkiewicz, Pawel res.end(); 7919391bb9cSRapkiewicz, Pawel }); 7929391bb9cSRapkiewicz, Pawel } 7939391bb9cSRapkiewicz, Pawel 7949391bb9cSRapkiewicz, Pawel // Ethernet Provider object 7959391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 7969391bb9cSRapkiewicz, Pawel OnDemandEthernetProvider ethernet_provider; 7979391bb9cSRapkiewicz, Pawel }; 7989391bb9cSRapkiewicz, Pawel 7999391bb9cSRapkiewicz, Pawel /** 8009391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8019391bb9cSRapkiewicz, Pawel */ 8029391bb9cSRapkiewicz, Pawel class EthernetInterface : public Node { 8039391bb9cSRapkiewicz, Pawel public: 8049391bb9cSRapkiewicz, Pawel /* 8059391bb9cSRapkiewicz, Pawel * Default Constructor 8069391bb9cSRapkiewicz, Pawel */ 8079391bb9cSRapkiewicz, Pawel template <typename CrowApp> 8089391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 8099391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 8109391bb9cSRapkiewicz, Pawel // GetSubroutes method 8119391bb9cSRapkiewicz, Pawel EthernetInterface(CrowApp &app) 8129391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/", 8139391bb9cSRapkiewicz, Pawel std::string()) { 8149391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface"; 8159391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8169391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8179391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8189391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8199391bb9cSRapkiewicz, Pawel 820588c3f0dSKowalski, Kamil entityPrivileges = { 821588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 822e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 823e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 824e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 825e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 826e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8279391bb9cSRapkiewicz, Pawel } 8289391bb9cSRapkiewicz, Pawel 8299391bb9cSRapkiewicz, Pawel private: 830588c3f0dSKowalski, Kamil void handleVlanPatch(const std::string &ifaceId, const nlohmann::json &input, 831588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 832588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 833588c3f0dSKowalski, Kamil if (!input.is_object()) { 834588c3f0dSKowalski, Kamil messages::addMessageToJson( 835588c3f0dSKowalski, Kamil asyncResp->res.json_value, 836588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "VLAN"), "/VLAN"); 837588c3f0dSKowalski, Kamil return; 838588c3f0dSKowalski, Kamil } 839588c3f0dSKowalski, Kamil 840588c3f0dSKowalski, Kamil bool inputVlanEnabled; 841588c3f0dSKowalski, Kamil uint64_t inputVlanId; 842588c3f0dSKowalski, Kamil json_util::Result inputVlanEnabledState = json_util::getBool( 843588c3f0dSKowalski, Kamil "VLANEnable", input, inputVlanEnabled, 844588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 845588c3f0dSKowalski, Kamil asyncResp->res.json_value, std::string("/VLAN/VLANEnable")); 846588c3f0dSKowalski, Kamil json_util::Result inputVlanIdState = json_util::getUnsigned( 847588c3f0dSKowalski, Kamil "VLANId", input, inputVlanId, 848588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 849588c3f0dSKowalski, Kamil asyncResp->res.json_value, std::string("/VLAN/VLANId")); 850588c3f0dSKowalski, Kamil bool inputInvalid = false; 851588c3f0dSKowalski, Kamil 852588c3f0dSKowalski, Kamil // Do not proceed if fields in VLAN object were of wrong type 853588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::WRONG_TYPE || 854588c3f0dSKowalski, Kamil inputVlanIdState == json_util::Result::WRONG_TYPE) { 855588c3f0dSKowalski, Kamil return; 856588c3f0dSKowalski, Kamil } 857588c3f0dSKowalski, Kamil 858588c3f0dSKowalski, Kamil // Verify input 859588c3f0dSKowalski, Kamil if (eth_data.vlan_id == nullptr) { 860588c3f0dSKowalski, Kamil // VLAN is currently disabled. User can only create/enable it. Change of 861588c3f0dSKowalski, Kamil // VLANId is prohibited, and disable request (VLANEnabled == false) will 862588c3f0dSKowalski, Kamil // not have any effect. 863588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::SUCCESS && 864588c3f0dSKowalski, Kamil inputVlanEnabled == true) { 865588c3f0dSKowalski, Kamil // Creation requested, user should also provide ID for new VLAN 866588c3f0dSKowalski, Kamil if (inputVlanIdState != json_util::Result::SUCCESS) { 867588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 868588c3f0dSKowalski, Kamil messages::propertyMissing("VLANId"), 869588c3f0dSKowalski, Kamil "/VLAN"); 870588c3f0dSKowalski, Kamil inputInvalid = true; 871588c3f0dSKowalski, Kamil } 872588c3f0dSKowalski, Kamil } else if (inputVlanIdState == json_util::Result::SUCCESS) { 873588c3f0dSKowalski, Kamil // VLAN is disabled, but user requested modification. This is not valid. 874588c3f0dSKowalski, Kamil messages::addMessageToJson( 875588c3f0dSKowalski, Kamil asyncResp->res.json_value, 876588c3f0dSKowalski, Kamil messages::actionParameterNotSupported("VLANId", "change VLAN Id"), 877588c3f0dSKowalski, Kamil "/VLAN"); 878588c3f0dSKowalski, Kamil 879588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 880588c3f0dSKowalski, Kamil messages::propertyMissing("VLANEnable"), 881588c3f0dSKowalski, Kamil "/VLAN"); 882588c3f0dSKowalski, Kamil 883588c3f0dSKowalski, Kamil inputInvalid = true; 884588c3f0dSKowalski, Kamil } 885588c3f0dSKowalski, Kamil } else { 886588c3f0dSKowalski, Kamil // Load actual data into field values if they were not provided 887588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::NOT_EXIST) { 888588c3f0dSKowalski, Kamil inputVlanEnabled = true; 889588c3f0dSKowalski, Kamil } 890588c3f0dSKowalski, Kamil 891588c3f0dSKowalski, Kamil if (inputVlanIdState == json_util::Result::NOT_EXIST) { 892588c3f0dSKowalski, Kamil inputVlanId = *eth_data.vlan_id; 893588c3f0dSKowalski, Kamil } 894588c3f0dSKowalski, Kamil } 895588c3f0dSKowalski, Kamil 896588c3f0dSKowalski, Kamil // Do not proceed if input has not been valid 897588c3f0dSKowalski, Kamil if (inputInvalid) { 898588c3f0dSKowalski, Kamil return; 899588c3f0dSKowalski, Kamil } 900588c3f0dSKowalski, Kamil 901588c3f0dSKowalski, Kamil auto vlanEnabledAfterOperation = 902588c3f0dSKowalski, Kamil [asyncResp](const boost::system::error_code ec) { 903588c3f0dSKowalski, Kamil if (ec) { 904588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 905588c3f0dSKowalski, Kamil messages::internalError(), "/VLAN"); 906588c3f0dSKowalski, Kamil } else { 907588c3f0dSKowalski, Kamil asyncResp->res.json_value["VLAN"]["VLANEnable"] = true; 908588c3f0dSKowalski, Kamil } 909588c3f0dSKowalski, Kamil }; 910588c3f0dSKowalski, Kamil 911588c3f0dSKowalski, Kamil if (eth_data.vlan_id == nullptr) { 912588c3f0dSKowalski, Kamil if (inputVlanEnabled == true) { 913588c3f0dSKowalski, Kamil ethernet_provider.createVlan(ifaceId, inputVlanId, 914588c3f0dSKowalski, Kamil std::move(vlanEnabledAfterOperation)); 915588c3f0dSKowalski, Kamil asyncResp->res.json_value["VLAN"]["VLANId"] = inputVlanId; 916588c3f0dSKowalski, Kamil } 917588c3f0dSKowalski, Kamil } else { 918588c3f0dSKowalski, Kamil // VLAN is configured on the interface 919588c3f0dSKowalski, Kamil if (inputVlanEnabled == true && inputVlanId != *eth_data.vlan_id) { 920588c3f0dSKowalski, Kamil // Change VLAN Id 921588c3f0dSKowalski, Kamil asyncResp->res.json_value["VLAN"]["VLANId"] = inputVlanId; 922588c3f0dSKowalski, Kamil ethernet_provider.changeVlanId(ifaceId, 923588c3f0dSKowalski, Kamil static_cast<uint32_t>(inputVlanId), 924588c3f0dSKowalski, Kamil std::move(vlanEnabledAfterOperation)); 925588c3f0dSKowalski, Kamil } else if (inputVlanEnabled == false) { 926588c3f0dSKowalski, Kamil // Disable VLAN 927588c3f0dSKowalski, Kamil ethernet_provider.disableVlan( 928588c3f0dSKowalski, Kamil ifaceId, [asyncResp](const boost::system::error_code ec) { 929588c3f0dSKowalski, Kamil if (ec) { 930588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 931588c3f0dSKowalski, Kamil messages::internalError(), "/VLAN"); 932588c3f0dSKowalski, Kamil } else { 933588c3f0dSKowalski, Kamil asyncResp->res.json_value["VLAN"]["VLANEnable"] = false; 934588c3f0dSKowalski, Kamil } 935588c3f0dSKowalski, Kamil }); 936588c3f0dSKowalski, Kamil } 937588c3f0dSKowalski, Kamil } 938588c3f0dSKowalski, Kamil } 939588c3f0dSKowalski, Kamil 940588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 941588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 942588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 943588c3f0dSKowalski, Kamil if (input.is_string()) { 944588c3f0dSKowalski, Kamil std::string newHostname = input.get<std::string>(); 945588c3f0dSKowalski, Kamil 946588c3f0dSKowalski, Kamil if (eth_data.hostname == nullptr || newHostname != *eth_data.hostname) { 947588c3f0dSKowalski, Kamil // Change hostname 948588c3f0dSKowalski, Kamil ethernet_provider.setHostName( 949588c3f0dSKowalski, Kamil newHostname, 950588c3f0dSKowalski, Kamil [asyncResp, newHostname](const boost::system::error_code ec) { 951588c3f0dSKowalski, Kamil if (ec) { 952588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 953588c3f0dSKowalski, Kamil messages::internalError(), 954588c3f0dSKowalski, Kamil "/HostName"); 955588c3f0dSKowalski, Kamil } else { 956588c3f0dSKowalski, Kamil asyncResp->res.json_value["HostName"] = newHostname; 957588c3f0dSKowalski, Kamil } 958588c3f0dSKowalski, Kamil }); 959588c3f0dSKowalski, Kamil } 960588c3f0dSKowalski, Kamil } else { 961588c3f0dSKowalski, Kamil messages::addMessageToJson( 962588c3f0dSKowalski, Kamil asyncResp->res.json_value, 963588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "HostName"), 964588c3f0dSKowalski, Kamil "/HostName"); 965588c3f0dSKowalski, Kamil } 966588c3f0dSKowalski, Kamil } 967588c3f0dSKowalski, Kamil 968*179db1d7SKowalski, Kamil void handleIPv4Patch(const std::string &ifaceId, const nlohmann::json &input, 969*179db1d7SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data, 970*179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 971*179db1d7SKowalski, Kamil if (!input.is_array()) { 972*179db1d7SKowalski, Kamil messages::addMessageToJson( 973*179db1d7SKowalski, Kamil asyncResp->res.json_value, 974*179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 975*179db1d7SKowalski, Kamil "/IPv4Addresses"); 976*179db1d7SKowalski, Kamil return; 977*179db1d7SKowalski, Kamil } 978*179db1d7SKowalski, Kamil 979*179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 980*179db1d7SKowalski, Kamil if (input.size() < ipv4_data.size()) { 981*179db1d7SKowalski, Kamil // TODO(kkowalsk) This should be a message indicating that not enough 982*179db1d7SKowalski, Kamil // data has been provided 983*179db1d7SKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 984*179db1d7SKowalski, Kamil messages::internalError(), "/IPv4Addresses"); 985*179db1d7SKowalski, Kamil return; 986*179db1d7SKowalski, Kamil } 987*179db1d7SKowalski, Kamil 988*179db1d7SKowalski, Kamil json_util::Result addressFieldState; 989*179db1d7SKowalski, Kamil json_util::Result subnetMaskFieldState; 990*179db1d7SKowalski, Kamil json_util::Result addressOriginFieldState; 991*179db1d7SKowalski, Kamil json_util::Result gatewayFieldState; 992*179db1d7SKowalski, Kamil const std::string *addressFieldValue; 993*179db1d7SKowalski, Kamil const std::string *subnetMaskFieldValue; 994*179db1d7SKowalski, Kamil const std::string *addressOriginFieldValue = nullptr; 995*179db1d7SKowalski, Kamil const std::string *gatewayFieldValue; 996*179db1d7SKowalski, Kamil uint8_t subnetMaskAsPrefixLength; 997*179db1d7SKowalski, Kamil std::string addressOriginInDBusFormat; 998*179db1d7SKowalski, Kamil 999*179db1d7SKowalski, Kamil bool errorDetected = false; 1000*179db1d7SKowalski, Kamil for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) { 1001*179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 1002*179db1d7SKowalski, Kamil if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) { 1003*179db1d7SKowalski, Kamil // Invalid object type 1004*179db1d7SKowalski, Kamil messages::addMessageToJson( 1005*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1006*179db1d7SKowalski, Kamil messages::propertyValueTypeError(input[entryIdx].dump(), 1007*179db1d7SKowalski, Kamil "IPv4Address"), 1008*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx)); 1009*179db1d7SKowalski, Kamil 1010*179db1d7SKowalski, Kamil continue; 1011*179db1d7SKowalski, Kamil } 1012*179db1d7SKowalski, Kamil 1013*179db1d7SKowalski, Kamil // Try to load fields 1014*179db1d7SKowalski, Kamil addressFieldState = json_util::getString( 1015*179db1d7SKowalski, Kamil "Address", input[entryIdx], addressFieldValue, 1016*179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1017*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1018*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1019*179db1d7SKowalski, Kamil subnetMaskFieldState = json_util::getString( 1020*179db1d7SKowalski, Kamil "SubnetMask", input[entryIdx], subnetMaskFieldValue, 1021*179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1022*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1023*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1024*179db1d7SKowalski, Kamil addressOriginFieldState = json_util::getString( 1025*179db1d7SKowalski, Kamil "AddressOrigin", input[entryIdx], addressOriginFieldValue, 1026*179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1027*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1028*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1029*179db1d7SKowalski, Kamil gatewayFieldState = json_util::getString( 1030*179db1d7SKowalski, Kamil "Gateway", input[entryIdx], gatewayFieldValue, 1031*179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1032*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1033*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1034*179db1d7SKowalski, Kamil 1035*179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::WRONG_TYPE || 1036*179db1d7SKowalski, Kamil subnetMaskFieldState == json_util::Result::WRONG_TYPE || 1037*179db1d7SKowalski, Kamil addressOriginFieldState == json_util::Result::WRONG_TYPE || 1038*179db1d7SKowalski, Kamil gatewayFieldState == json_util::Result::WRONG_TYPE) { 1039*179db1d7SKowalski, Kamil return; 1040*179db1d7SKowalski, Kamil } 1041*179db1d7SKowalski, Kamil 1042*179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1043*179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount(*addressFieldValue)) { 1044*179db1d7SKowalski, Kamil errorDetected = true; 1045*179db1d7SKowalski, Kamil messages::addMessageToJson( 1046*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1047*179db1d7SKowalski, Kamil messages::propertyValueFormatError(*addressFieldValue, "Address"), 1048*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1049*179db1d7SKowalski, Kamil } 1050*179db1d7SKowalski, Kamil 1051*179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1052*179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount( 1053*179db1d7SKowalski, Kamil *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) { 1054*179db1d7SKowalski, Kamil errorDetected = true; 1055*179db1d7SKowalski, Kamil messages::addMessageToJson( 1056*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1057*179db1d7SKowalski, Kamil messages::propertyValueFormatError(*subnetMaskFieldValue, 1058*179db1d7SKowalski, Kamil "SubnetMask"), 1059*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1060*179db1d7SKowalski, Kamil } 1061*179db1d7SKowalski, Kamil 1062*179db1d7SKowalski, Kamil // Get Address origin in proper format 1063*179db1d7SKowalski, Kamil addressOriginInDBusFormat = 1064*179db1d7SKowalski, Kamil ethernet_provider.translateAddressOriginBetweenDBusAndRedfish( 1065*179db1d7SKowalski, Kamil addressOriginFieldValue, true, false); 1066*179db1d7SKowalski, Kamil 1067*179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1068*179db1d7SKowalski, Kamil addressOriginInDBusFormat.empty()) { 1069*179db1d7SKowalski, Kamil errorDetected = true; 1070*179db1d7SKowalski, Kamil messages::addMessageToJson( 1071*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1072*179db1d7SKowalski, Kamil messages::propertyValueNotInList(*addressOriginFieldValue, 1073*179db1d7SKowalski, Kamil "AddressOrigin"), 1074*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1075*179db1d7SKowalski, Kamil } 1076*179db1d7SKowalski, Kamil 1077*179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1078*179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount(*gatewayFieldValue)) { 1079*179db1d7SKowalski, Kamil errorDetected = true; 1080*179db1d7SKowalski, Kamil messages::addMessageToJson( 1081*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1082*179db1d7SKowalski, Kamil messages::propertyValueFormatError(*gatewayFieldValue, "Gateway"), 1083*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1084*179db1d7SKowalski, Kamil } 1085*179db1d7SKowalski, Kamil 1086*179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1087*179db1d7SKowalski, Kamil // end loop 1088*179db1d7SKowalski, Kamil if (errorDetected) { 1089*179db1d7SKowalski, Kamil errorDetected = false; 1090*179db1d7SKowalski, Kamil continue; 1091*179db1d7SKowalski, Kamil } 1092*179db1d7SKowalski, Kamil 1093*179db1d7SKowalski, Kamil if (entryIdx >= ipv4_data.size()) { 1094*179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][entryIdx] = input[entryIdx]; 1095*179db1d7SKowalski, Kamil 1096*179db1d7SKowalski, Kamil // Verify that all field were provided 1097*179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::NOT_EXIST) { 1098*179db1d7SKowalski, Kamil errorDetected = true; 1099*179db1d7SKowalski, Kamil messages::addMessageToJson( 1100*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::propertyMissing("Address"), 1101*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1102*179db1d7SKowalski, Kamil } 1103*179db1d7SKowalski, Kamil 1104*179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::NOT_EXIST) { 1105*179db1d7SKowalski, Kamil errorDetected = true; 1106*179db1d7SKowalski, Kamil messages::addMessageToJson( 1107*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1108*179db1d7SKowalski, Kamil messages::propertyMissing("SubnetMask"), 1109*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1110*179db1d7SKowalski, Kamil } 1111*179db1d7SKowalski, Kamil 1112*179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::NOT_EXIST) { 1113*179db1d7SKowalski, Kamil errorDetected = true; 1114*179db1d7SKowalski, Kamil messages::addMessageToJson( 1115*179db1d7SKowalski, Kamil asyncResp->res.json_value, 1116*179db1d7SKowalski, Kamil messages::propertyMissing("AddressOrigin"), 1117*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1118*179db1d7SKowalski, Kamil } 1119*179db1d7SKowalski, Kamil 1120*179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::NOT_EXIST) { 1121*179db1d7SKowalski, Kamil errorDetected = true; 1122*179db1d7SKowalski, Kamil messages::addMessageToJson( 1123*179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::propertyMissing("Gateway"), 1124*179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1125*179db1d7SKowalski, Kamil } 1126*179db1d7SKowalski, Kamil 1127*179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1128*179db1d7SKowalski, Kamil // end loop 1129*179db1d7SKowalski, Kamil if (errorDetected) { 1130*179db1d7SKowalski, Kamil errorDetected = false; 1131*179db1d7SKowalski, Kamil continue; 1132*179db1d7SKowalski, Kamil } 1133*179db1d7SKowalski, Kamil 1134*179db1d7SKowalski, Kamil // Create IPv4 with provided data 1135*179db1d7SKowalski, Kamil ethernet_provider.createIPv4( 1136*179db1d7SKowalski, Kamil ifaceId, entryIdx, subnetMaskAsPrefixLength, *gatewayFieldValue, 1137*179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1138*179db1d7SKowalski, Kamil } else { 1139*179db1d7SKowalski, Kamil // Existing object that should be modified/deleted/remain unchanged 1140*179db1d7SKowalski, Kamil if (input[entryIdx].is_null()) { 1141*179db1d7SKowalski, Kamil // Object should be deleted 1142*179db1d7SKowalski, Kamil ethernet_provider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, 1143*179db1d7SKowalski, Kamil entryIdx, asyncResp); 1144*179db1d7SKowalski, Kamil } else if (input[entryIdx].is_object()) { 1145*179db1d7SKowalski, Kamil if (input[entryIdx].size() == 0) { 1146*179db1d7SKowalski, Kamil // Object shall remain unchanged 1147*179db1d7SKowalski, Kamil continue; 1148*179db1d7SKowalski, Kamil } 1149*179db1d7SKowalski, Kamil 1150*179db1d7SKowalski, Kamil // Apply changes 1151*179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1152*179db1d7SKowalski, Kamil ipv4_data[entryIdx].address != nullptr && 1153*179db1d7SKowalski, Kamil *ipv4_data[entryIdx].address != *addressFieldValue) { 1154*179db1d7SKowalski, Kamil ethernet_provider.changeIPv4AddressProperty( 1155*179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Address", 1156*179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1157*179db1d7SKowalski, Kamil } 1158*179db1d7SKowalski, Kamil 1159*179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1160*179db1d7SKowalski, Kamil ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) { 1161*179db1d7SKowalski, Kamil ethernet_provider.changeIPv4SubnetMaskProperty( 1162*179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1163*179db1d7SKowalski, Kamil *subnetMaskFieldValue, subnetMaskAsPrefixLength, asyncResp); 1164*179db1d7SKowalski, Kamil } 1165*179db1d7SKowalski, Kamil 1166*179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1167*179db1d7SKowalski, Kamil ipv4_data[entryIdx].origin != *addressFieldValue) { 1168*179db1d7SKowalski, Kamil ethernet_provider.changeIPv4Origin( 1169*179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1170*179db1d7SKowalski, Kamil *addressOriginFieldValue, addressOriginInDBusFormat, asyncResp); 1171*179db1d7SKowalski, Kamil } 1172*179db1d7SKowalski, Kamil 1173*179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1174*179db1d7SKowalski, Kamil ipv4_data[entryIdx].gateway != nullptr && 1175*179db1d7SKowalski, Kamil *ipv4_data[entryIdx].gateway != *gatewayFieldValue) { 1176*179db1d7SKowalski, Kamil ethernet_provider.changeIPv4AddressProperty( 1177*179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Gateway", 1178*179db1d7SKowalski, Kamil *gatewayFieldValue, asyncResp); 1179*179db1d7SKowalski, Kamil } 1180*179db1d7SKowalski, Kamil } 1181*179db1d7SKowalski, Kamil } 1182*179db1d7SKowalski, Kamil } 1183*179db1d7SKowalski, Kamil } 1184*179db1d7SKowalski, Kamil 1185588c3f0dSKowalski, Kamil nlohmann::json parseInterfaceData( 1186588c3f0dSKowalski, Kamil const std::string &iface_id, const EthernetInterfaceData ð_data, 1187588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1188588c3f0dSKowalski, Kamil // Copy JSON object to avoid race condition 1189588c3f0dSKowalski, Kamil nlohmann::json json_response(Node::json); 1190588c3f0dSKowalski, Kamil 1191588c3f0dSKowalski, Kamil // Fill out obvious data... 1192588c3f0dSKowalski, Kamil json_response["Id"] = iface_id; 1193588c3f0dSKowalski, Kamil json_response["@odata.id"] = 1194588c3f0dSKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + iface_id; 1195588c3f0dSKowalski, Kamil 1196588c3f0dSKowalski, Kamil // ... then the one from DBus, regarding eth iface... 1197588c3f0dSKowalski, Kamil if (eth_data.speed != nullptr) json_response["SpeedMbps"] = *eth_data.speed; 1198588c3f0dSKowalski, Kamil 1199588c3f0dSKowalski, Kamil if (eth_data.mac_address != nullptr) 1200588c3f0dSKowalski, Kamil json_response["MACAddress"] = *eth_data.mac_address; 1201588c3f0dSKowalski, Kamil 1202588c3f0dSKowalski, Kamil if (eth_data.hostname != nullptr) 1203588c3f0dSKowalski, Kamil json_response["HostName"] = *eth_data.hostname; 1204588c3f0dSKowalski, Kamil 1205588c3f0dSKowalski, Kamil if (eth_data.vlan_id != nullptr) { 1206588c3f0dSKowalski, Kamil nlohmann::json &vlanObj = json_response["VLAN"]; 1207588c3f0dSKowalski, Kamil vlanObj["VLANEnable"] = true; 1208588c3f0dSKowalski, Kamil vlanObj["VLANId"] = *eth_data.vlan_id; 1209588c3f0dSKowalski, Kamil } 1210588c3f0dSKowalski, Kamil 1211588c3f0dSKowalski, Kamil // ... at last, check if there are IPv4 data and prepare appropriate 1212588c3f0dSKowalski, Kamil // collection 1213588c3f0dSKowalski, Kamil if (ipv4_data.size() > 0) { 1214588c3f0dSKowalski, Kamil nlohmann::json ipv4_array = nlohmann::json::array(); 1215588c3f0dSKowalski, Kamil for (auto &ipv4_config : ipv4_data) { 1216588c3f0dSKowalski, Kamil nlohmann::json json_ipv4; 1217588c3f0dSKowalski, Kamil if (ipv4_config.address != nullptr) { 1218588c3f0dSKowalski, Kamil json_ipv4["Address"] = *ipv4_config.address; 1219588c3f0dSKowalski, Kamil if (ipv4_config.gateway != nullptr) 1220588c3f0dSKowalski, Kamil json_ipv4["Gateway"] = *ipv4_config.gateway; 1221588c3f0dSKowalski, Kamil 1222588c3f0dSKowalski, Kamil json_ipv4["AddressOrigin"] = ipv4_config.origin; 1223588c3f0dSKowalski, Kamil json_ipv4["SubnetMask"] = ipv4_config.netmask; 1224588c3f0dSKowalski, Kamil 1225588c3f0dSKowalski, Kamil ipv4_array.push_back(std::move(json_ipv4)); 1226588c3f0dSKowalski, Kamil } 1227588c3f0dSKowalski, Kamil } 1228588c3f0dSKowalski, Kamil json_response["IPv4Addresses"] = std::move(ipv4_array); 1229588c3f0dSKowalski, Kamil } 1230588c3f0dSKowalski, Kamil 1231588c3f0dSKowalski, Kamil return json_response; 1232588c3f0dSKowalski, Kamil } 1233588c3f0dSKowalski, Kamil 12349391bb9cSRapkiewicz, Pawel /** 12359391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12369391bb9cSRapkiewicz, Pawel */ 12379391bb9cSRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 12389391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 12399391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call (two params) to get 12409391bb9cSRapkiewicz, Pawel // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 12419391bb9cSRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 12429391bb9cSRapkiewicz, Pawel // impossible. 12439391bb9cSRapkiewicz, Pawel if (params.size() != 1) { 1244e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 12459391bb9cSRapkiewicz, Pawel res.end(); 12469391bb9cSRapkiewicz, Pawel return; 12479391bb9cSRapkiewicz, Pawel } 12489391bb9cSRapkiewicz, Pawel 12499391bb9cSRapkiewicz, Pawel const std::string &iface_id = params[0]; 12509391bb9cSRapkiewicz, Pawel 12519391bb9cSRapkiewicz, Pawel // Get single eth interface data, and call the below callback for JSON 12529391bb9cSRapkiewicz, Pawel // preparation 12539391bb9cSRapkiewicz, Pawel ethernet_provider.getEthernetIfaceData( 12549391bb9cSRapkiewicz, Pawel iface_id, [&, iface_id](const bool &success, 12559391bb9cSRapkiewicz, Pawel const EthernetInterfaceData ð_data, 12569391bb9cSRapkiewicz, Pawel const std::vector<IPv4AddressData> &ipv4_data) { 12579391bb9cSRapkiewicz, Pawel if (success) { 1258588c3f0dSKowalski, Kamil res.json_value = parseInterfaceData(iface_id, eth_data, ipv4_data); 12599391bb9cSRapkiewicz, Pawel } else { 12609391bb9cSRapkiewicz, Pawel // ... otherwise return error 12619391bb9cSRapkiewicz, Pawel // TODO(Pawel)consider distinguish between non existing object, and 12629391bb9cSRapkiewicz, Pawel // other errors 1263e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 12649391bb9cSRapkiewicz, Pawel } 12659391bb9cSRapkiewicz, Pawel res.end(); 12669391bb9cSRapkiewicz, Pawel }); 12679391bb9cSRapkiewicz, Pawel } 12689391bb9cSRapkiewicz, Pawel 1269588c3f0dSKowalski, Kamil void doPatch(crow::response &res, const crow::request &req, 1270588c3f0dSKowalski, Kamil const std::vector<std::string> ¶ms) override { 1271588c3f0dSKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1272588c3f0dSKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1273588c3f0dSKowalski, Kamil // Check if there is required param, truly entering this shall be 1274588c3f0dSKowalski, Kamil // impossible. 1275588c3f0dSKowalski, Kamil if (params.size() != 1) { 1276588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1277588c3f0dSKowalski, Kamil res.end(); 1278588c3f0dSKowalski, Kamil return; 1279588c3f0dSKowalski, Kamil } 1280588c3f0dSKowalski, Kamil 1281588c3f0dSKowalski, Kamil const std::string &iface_id = params[0]; 1282588c3f0dSKowalski, Kamil 1283*179db1d7SKowalski, Kamil nlohmann::json patchReq; 1284588c3f0dSKowalski, Kamil 1285*179db1d7SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1286588c3f0dSKowalski, Kamil return; 1287588c3f0dSKowalski, Kamil } 1288588c3f0dSKowalski, Kamil 1289588c3f0dSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1290588c3f0dSKowalski, Kamil // preparation 1291588c3f0dSKowalski, Kamil ethernet_provider.getEthernetIfaceData( 1292588c3f0dSKowalski, Kamil iface_id, 1293588c3f0dSKowalski, Kamil [&, iface_id, patchReq = std::move(patchReq) ]( 1294588c3f0dSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1295588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1296588c3f0dSKowalski, Kamil if (!success) { 1297588c3f0dSKowalski, Kamil // ... otherwise return error 1298588c3f0dSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1299588c3f0dSKowalski, Kamil // other errors 1300588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1301588c3f0dSKowalski, Kamil res.end(); 1302588c3f0dSKowalski, Kamil 1303588c3f0dSKowalski, Kamil return; 1304588c3f0dSKowalski, Kamil } 1305588c3f0dSKowalski, Kamil 1306588c3f0dSKowalski, Kamil res.json_value = parseInterfaceData(iface_id, eth_data, ipv4_data); 1307588c3f0dSKowalski, Kamil 1308588c3f0dSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1309588c3f0dSKowalski, Kamil std::make_shared<AsyncResp>(res); 1310588c3f0dSKowalski, Kamil 1311588c3f0dSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1312588c3f0dSKowalski, Kamil ++propertyIt) { 1313588c3f0dSKowalski, Kamil if (propertyIt.key() == "VLAN") { 1314588c3f0dSKowalski, Kamil handleVlanPatch(iface_id, propertyIt.value(), eth_data, 1315588c3f0dSKowalski, Kamil asyncResp); 1316588c3f0dSKowalski, Kamil } else if (propertyIt.key() == "HostName") { 1317588c3f0dSKowalski, Kamil handleHostnamePatch(propertyIt.value(), eth_data, asyncResp); 1318*179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv4Addresses") { 1319*179db1d7SKowalski, Kamil handleIPv4Patch(iface_id, propertyIt.value(), ipv4_data, 1320*179db1d7SKowalski, Kamil asyncResp); 1321*179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv6Addresses") { 1322*179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1323*179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 1324*179db1d7SKowalski, Kamil res.json_value, 1325*179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1326588c3f0dSKowalski, Kamil } else { 1327588c3f0dSKowalski, Kamil auto fieldInJsonIt = res.json_value.find(propertyIt.key()); 1328588c3f0dSKowalski, Kamil 1329588c3f0dSKowalski, Kamil if (fieldInJsonIt == res.json_value.end()) { 1330588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1331588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1332588c3f0dSKowalski, Kamil res.json_value, 1333588c3f0dSKowalski, Kamil messages::propertyUnknown(propertyIt.key())); 1334588c3f0dSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1335588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1336588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1337588c3f0dSKowalski, Kamil res.json_value, 1338588c3f0dSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1339588c3f0dSKowalski, Kamil } 1340588c3f0dSKowalski, Kamil } 1341588c3f0dSKowalski, Kamil } 1342588c3f0dSKowalski, Kamil }); 1343588c3f0dSKowalski, Kamil } 1344588c3f0dSKowalski, Kamil 13459391bb9cSRapkiewicz, Pawel // Ethernet Provider object 13469391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 13479391bb9cSRapkiewicz, Pawel OnDemandEthernetProvider ethernet_provider; 13489391bb9cSRapkiewicz, Pawel }; 13499391bb9cSRapkiewicz, Pawel 13509391bb9cSRapkiewicz, Pawel } // namespace redfish 1351