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 18179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 19588c3f0dSKowalski, Kamil #include <error_messages.hpp> 20179db1d7SKowalski, 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 { 49179db1d7SKowalski, 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; 56179db1d7SKowalski, Kamil /** 57179db1d7SKowalski, Kamil * @brief Operator< to enable sorting 58179db1d7SKowalski, Kamil * 59179db1d7SKowalski, Kamil * @param[in] obj Object to compare with 60179db1d7SKowalski, Kamil * 61179db1d7SKowalski, Kamil * @return This object id < supplied object id 62179db1d7SKowalski, Kamil */ 63179db1d7SKowalski, 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) { 192179db1d7SKowalski, Kamil const std::string pathStart = 193179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 194179db1d7SKowalski, 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; 210179db1d7SKowalski, Kamil 211179db1d7SKowalski, Kamil ipv4_address.id = static_cast<const std::string &>(objpath.first) 212179db1d7SKowalski, Kamil .substr(pathStart.size()); 213179db1d7SKowalski, 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) { 225179db1d7SKowalski, Kamil ipv4_address.origin = 226179db1d7SKowalski, 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 } 250179db1d7SKowalski, Kamil 251179db1d7SKowalski, Kamil /** 252179db1d7SKowalski, Kamil * We have to sort this vector and ensure that order of IPv4 addresses 253179db1d7SKowalski, Kamil * is consistent between GETs to allow modification and deletion in PATCHes 254179db1d7SKowalski, Kamil */ 255179db1d7SKowalski, Kamil std::sort(ipv4_config.begin(), ipv4_config.end()); 2569391bb9cSRapkiewicz, Pawel } 2579391bb9cSRapkiewicz, Pawel 258179db1d7SKowalski, Kamil static const constexpr int ipV4AddressSectionsCount = 4; 259179db1d7SKowalski, 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> 289e439f0f8SKowalski, Kamil static void changeVlanId(const std::string &ifaceId, 290e439f0f8SKowalski, Kamil const uint32_t &inputVlanId, 291588c3f0dSKowalski, Kamil CallbackFunc &&callback) { 292588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 293588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 294588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 295588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 296588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 297588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 298588c3f0dSKowalski, Kamil }; 299588c3f0dSKowalski, Kamil 300588c3f0dSKowalski, Kamil /** 301179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 302179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 303179db1d7SKowalski, Kamil * bit count for Subnet Mask. 304179db1d7SKowalski, Kamil * 305179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 306179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 307179db1d7SKowalski, Kamil * 308179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 309179db1d7SKowalski, Kamil */ 310179db1d7SKowalski, Kamil bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 311179db1d7SKowalski, Kamil uint8_t *bits = nullptr) { 312179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 313179db1d7SKowalski, Kamil 314179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 315179db1d7SKowalski, Kamil 316179db1d7SKowalski, Kamil if (bytesInMask.size() != ipV4AddressSectionsCount) { 317179db1d7SKowalski, Kamil return false; 318179db1d7SKowalski, Kamil } 319179db1d7SKowalski, Kamil 320179db1d7SKowalski, Kamil if (bits != nullptr) { 321179db1d7SKowalski, Kamil *bits = 0; 322179db1d7SKowalski, Kamil } 323179db1d7SKowalski, Kamil 324179db1d7SKowalski, Kamil char *endPtr; 325179db1d7SKowalski, Kamil long previousValue = 255; 326179db1d7SKowalski, Kamil bool firstZeroInByteHit; 327*1db9ca37SKowalski, Kamil for (const std::string &byte : bytesInMask) { 328*1db9ca37SKowalski, Kamil if (byte.empty()) { 329*1db9ca37SKowalski, Kamil return false; 330*1db9ca37SKowalski, Kamil } 331*1db9ca37SKowalski, Kamil 332179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 333*1db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 334179db1d7SKowalski, Kamil 335179db1d7SKowalski, Kamil // endPtr should point to the end of the string, otherwise given string 336179db1d7SKowalski, Kamil // is not 100% number 337179db1d7SKowalski, Kamil if (*endPtr != '\0') { 338179db1d7SKowalski, Kamil return false; 339179db1d7SKowalski, Kamil } 340179db1d7SKowalski, Kamil 341179db1d7SKowalski, Kamil // Value should be contained in byte 342179db1d7SKowalski, Kamil if (value < 0 || value > 255) { 343179db1d7SKowalski, Kamil return false; 344179db1d7SKowalski, Kamil } 345179db1d7SKowalski, Kamil 346179db1d7SKowalski, Kamil if (bits != nullptr) { 347179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 348179db1d7SKowalski, Kamil if (previousValue != 255 && value != 0) { 349179db1d7SKowalski, Kamil return false; 350179db1d7SKowalski, Kamil } 351179db1d7SKowalski, Kamil 352179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 353179db1d7SKowalski, Kamil firstZeroInByteHit = false; 354179db1d7SKowalski, Kamil 355179db1d7SKowalski, Kamil // Count bits 356179db1d7SKowalski, Kamil for (int bitIdx = 7; bitIdx >= 0; bitIdx--) { 357179db1d7SKowalski, Kamil if (value & (1 << bitIdx)) { 358179db1d7SKowalski, Kamil if (firstZeroInByteHit) { 359179db1d7SKowalski, Kamil // Continuity not preserved 360179db1d7SKowalski, Kamil return false; 361179db1d7SKowalski, Kamil } else { 362179db1d7SKowalski, Kamil (*bits)++; 363179db1d7SKowalski, Kamil } 364179db1d7SKowalski, Kamil } else { 365179db1d7SKowalski, Kamil firstZeroInByteHit = true; 366179db1d7SKowalski, Kamil } 367179db1d7SKowalski, Kamil } 368179db1d7SKowalski, Kamil } 369179db1d7SKowalski, Kamil 370179db1d7SKowalski, Kamil previousValue = value; 371179db1d7SKowalski, Kamil } 372179db1d7SKowalski, Kamil 373179db1d7SKowalski, Kamil return true; 374179db1d7SKowalski, Kamil } 375179db1d7SKowalski, Kamil 376179db1d7SKowalski, Kamil /** 377179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 378179db1d7SKowalski, Kamil * 379179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 380179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 381179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 382179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 383179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 384179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 385179db1d7SKowalski, Kamil * 386179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 387179db1d7SKowalski, Kamil * otherwise 388179db1d7SKowalski, Kamil */ 389179db1d7SKowalski, Kamil void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx, 390179db1d7SKowalski, Kamil const std::string &ipHash, 391179db1d7SKowalski, Kamil const std::string &name, 392179db1d7SKowalski, Kamil const std::string &newValue, 393179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 394179db1d7SKowalski, Kamil auto callback = [ 395179db1d7SKowalski, Kamil asyncResp, ipIdx{std::move(ipIdx)}, name{std::move(name)}, 396179db1d7SKowalski, Kamil newValue{std::move(newValue)} 397179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 398179db1d7SKowalski, Kamil if (ec) { 399179db1d7SKowalski, Kamil messages::addMessageToJson( 400179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 401179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 402179db1d7SKowalski, Kamil } else { 403179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx][name] = newValue; 404179db1d7SKowalski, Kamil } 405179db1d7SKowalski, Kamil }; 406179db1d7SKowalski, Kamil 407179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 408179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 409179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 410179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 411179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 412179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 413179db1d7SKowalski, Kamil }; 414179db1d7SKowalski, Kamil 415179db1d7SKowalski, Kamil /** 416179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 417179db1d7SKowalski, Kamil * 418179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 419179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 420179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 421179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 422179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 423179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 424179db1d7SKowalski, Kamil * 425179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 426179db1d7SKowalski, Kamil * otherwise 427179db1d7SKowalski, Kamil */ 428179db1d7SKowalski, Kamil void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 429179db1d7SKowalski, Kamil const std::string &ipHash, const std::string &newValue, 430179db1d7SKowalski, Kamil const std::string &newValueDbus, 431179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 432179db1d7SKowalski, Kamil auto callback = 433179db1d7SKowalski, Kamil [ asyncResp, ipIdx{std::move(ipIdx)}, 434179db1d7SKowalski, Kamil newValue{std::move(newValue)} ](const boost::system::error_code ec) { 435179db1d7SKowalski, Kamil if (ec) { 436179db1d7SKowalski, Kamil messages::addMessageToJson( 437179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 438179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin"); 439179db1d7SKowalski, Kamil } else { 440179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx]["AddressOrigin"] = 441179db1d7SKowalski, Kamil newValue; 442179db1d7SKowalski, Kamil } 443179db1d7SKowalski, Kamil }; 444179db1d7SKowalski, Kamil 445179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 446179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 447179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 448179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 449179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 450179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 451179db1d7SKowalski, Kamil }; 452179db1d7SKowalski, Kamil 453179db1d7SKowalski, Kamil /** 454179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 455179db1d7SKowalski, Kamil * 456179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 457179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be modified 458179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 459179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 460179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 461179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 462179db1d7SKowalski, Kamil * 463179db1d7SKowalski, Kamil * @return None 464179db1d7SKowalski, Kamil */ 465179db1d7SKowalski, Kamil void changeIPv4SubnetMaskProperty( 466179db1d7SKowalski, Kamil const std::string &ifaceId, int ipIdx, const std::string &ipHash, 467179db1d7SKowalski, Kamil const std::string &newValueStr, uint8_t &newValue, 468179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 469179db1d7SKowalski, Kamil auto callback = [ 470179db1d7SKowalski, Kamil asyncResp, ipIdx{std::move(ipIdx)}, newValueStr{std::move(newValueStr)} 471179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 472179db1d7SKowalski, Kamil if (ec) { 473179db1d7SKowalski, Kamil messages::addMessageToJson( 474179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 475179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 476179db1d7SKowalski, Kamil } else { 477179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx]["SubnetMask"] = 478179db1d7SKowalski, Kamil newValueStr; 479179db1d7SKowalski, Kamil } 480179db1d7SKowalski, Kamil }; 481179db1d7SKowalski, Kamil 482179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 483179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 484179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 485179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 486179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 487179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 488179db1d7SKowalski, Kamil }; 489179db1d7SKowalski, Kamil 490179db1d7SKowalski, Kamil /** 491588c3f0dSKowalski, Kamil * @brief Disables VLAN with given ifaceId 492588c3f0dSKowalski, Kamil * 493588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be disabled 494588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 495588c3f0dSKowalski, Kamil * 496588c3f0dSKowalski, Kamil * @return None. 497588c3f0dSKowalski, Kamil */ 498588c3f0dSKowalski, Kamil template <typename CallbackFunc> 499e439f0f8SKowalski, Kamil static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) { 500588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 501588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 502588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 503588c3f0dSKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 504588c3f0dSKowalski, Kamil }; 505588c3f0dSKowalski, Kamil 506588c3f0dSKowalski, Kamil /** 507588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 508588c3f0dSKowalski, Kamil * 509588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 510588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 511588c3f0dSKowalski, Kamil * 512588c3f0dSKowalski, Kamil * @return None. 513588c3f0dSKowalski, Kamil */ 514588c3f0dSKowalski, Kamil template <typename CallbackFunc> 515588c3f0dSKowalski, Kamil void setHostName(const std::string &newHostname, CallbackFunc &&callback) { 516588c3f0dSKowalski, Kamil crow::connections::system_bus->async_method_call( 517588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 518588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 519588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 520588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 521588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 522588c3f0dSKowalski, Kamil }; 523588c3f0dSKowalski, Kamil 524588c3f0dSKowalski, Kamil /** 525179db1d7SKowalski, Kamil * @brief Deletes given IPv4 526179db1d7SKowalski, Kamil * 527179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 528179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be deleted 529179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 530179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 531179db1d7SKowalski, Kamil * 532179db1d7SKowalski, Kamil * @return None 533179db1d7SKowalski, Kamil */ 534179db1d7SKowalski, Kamil void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 535179db1d7SKowalski, Kamil unsigned int ipIdx, 536179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 537179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 538179db1d7SKowalski, Kamil [ ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} ]( 539179db1d7SKowalski, Kamil const boost::system::error_code ec) { 540179db1d7SKowalski, Kamil if (ec) { 541179db1d7SKowalski, Kamil messages::addMessageToJson( 542179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 543179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 544179db1d7SKowalski, Kamil } else { 545179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][ipIdx] = nullptr; 546179db1d7SKowalski, Kamil } 547179db1d7SKowalski, Kamil }, 548179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 549179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 550179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 551179db1d7SKowalski, Kamil } 552179db1d7SKowalski, Kamil 553179db1d7SKowalski, Kamil /** 554179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 555179db1d7SKowalski, Kamil * 556179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 557179db1d7SKowalski, Kamil * @param[in] ipIdx Index of IP in input array that should be deleted 558179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 559179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 560179db1d7SKowalski, Kamil * 561179db1d7SKowalski, Kamil * @return None 562179db1d7SKowalski, Kamil */ 563179db1d7SKowalski, Kamil void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 564179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 565179db1d7SKowalski, Kamil const std::string &address, 566179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 567179db1d7SKowalski, Kamil auto createIpHandler = [ 568179db1d7SKowalski, Kamil ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} 569179db1d7SKowalski, Kamil ](const boost::system::error_code ec) { 570179db1d7SKowalski, Kamil if (ec) { 571179db1d7SKowalski, Kamil messages::addMessageToJson( 572179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::internalError(), 573179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 574179db1d7SKowalski, Kamil } 575179db1d7SKowalski, Kamil }; 576179db1d7SKowalski, Kamil 577179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 578179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 579179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 580179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 581179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 582179db1d7SKowalski, Kamil gateway); 583179db1d7SKowalski, Kamil } 584179db1d7SKowalski, Kamil 585179db1d7SKowalski, Kamil /** 586179db1d7SKowalski, Kamil * @brief Translates Address Origin value from D-Bus to Redfish format and 587179db1d7SKowalski, Kamil * vice-versa 588179db1d7SKowalski, Kamil * 589179db1d7SKowalski, Kamil * @param[in] inputOrigin Input value that should be translated 590179db1d7SKowalski, Kamil * @param[in] isIPv4 True for IPv4 origins, False for IPv6 591179db1d7SKowalski, Kamil * @param[in] isFromDBus True for DBus->Redfish conversion, false for reverse 592179db1d7SKowalski, Kamil * 593179db1d7SKowalski, Kamil * @return Empty string in case of failure, translated value otherwise 594179db1d7SKowalski, Kamil */ 595179db1d7SKowalski, Kamil std::string translateAddressOriginBetweenDBusAndRedfish( 596179db1d7SKowalski, Kamil const std::string *inputOrigin, bool isIPv4, bool isFromDBus) { 597179db1d7SKowalski, Kamil // Invalid pointer 598179db1d7SKowalski, Kamil if (inputOrigin == nullptr) { 599179db1d7SKowalski, Kamil return ""; 600179db1d7SKowalski, Kamil } 601179db1d7SKowalski, Kamil 602179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv4OnlyIdx = 1; 603179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv6OnlyIdx = 3; 604179db1d7SKowalski, Kamil 605179db1d7SKowalski, Kamil std::array<std::pair<const char *, const char *>, 6> translationTable{ 606179db1d7SKowalski, Kamil {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"}, 607179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"}, 608179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 609179db1d7SKowalski, Kamil "IPv4LinkLocal"}, 610179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"}, 611179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 612179db1d7SKowalski, Kamil "LinkLocal"}, 613179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}}; 614179db1d7SKowalski, Kamil 615179db1d7SKowalski, Kamil for (unsigned int i = 0; i < translationTable.size(); i++) { 616179db1d7SKowalski, Kamil // Skip unrelated 617179db1d7SKowalski, Kamil if (isIPv4 && i >= firstIPv6OnlyIdx) break; 618179db1d7SKowalski, Kamil if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) continue; 619179db1d7SKowalski, Kamil 620179db1d7SKowalski, Kamil // When translating D-Bus to Redfish compare input to first element 621179db1d7SKowalski, Kamil if (isFromDBus && translationTable[i].first == *inputOrigin) 622179db1d7SKowalski, Kamil return translationTable[i].second; 623179db1d7SKowalski, Kamil 624179db1d7SKowalski, Kamil // When translating Redfish to D-Bus compare input to second element 625179db1d7SKowalski, Kamil if (!isFromDBus && translationTable[i].second == *inputOrigin) 626179db1d7SKowalski, Kamil return translationTable[i].first; 627179db1d7SKowalski, Kamil } 628179db1d7SKowalski, Kamil 629179db1d7SKowalski, Kamil // If we are still here, that means that value has not been found 630179db1d7SKowalski, Kamil return ""; 631179db1d7SKowalski, Kamil } 632179db1d7SKowalski, Kamil 633179db1d7SKowalski, Kamil /** 634179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 635179db1d7SKowalski, Kamil * Object 636179db1d7SKowalski, Kamil * from EntityManager Network Manager 637179db1d7SKowalski, Kamil * @param ethiface_id a eth interface id to query on DBus 638179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 639179db1d7SKowalski, Kamil * into JSON 640179db1d7SKowalski, Kamil */ 641179db1d7SKowalski, Kamil template <typename CallbackFunc> 642179db1d7SKowalski, Kamil void getEthernetIfaceData(const std::string ðiface_id, 643179db1d7SKowalski, Kamil CallbackFunc &&callback) { 644179db1d7SKowalski, Kamil crow::connections::system_bus->async_method_call( 645179db1d7SKowalski, Kamil [ 646179db1d7SKowalski, Kamil this, ethiface_id{std::move(ethiface_id)}, 647179db1d7SKowalski, Kamil callback{std::move(callback)} 648179db1d7SKowalski, Kamil ](const boost::system::error_code error_code, 649179db1d7SKowalski, Kamil const GetManagedObjectsType &resp) { 650179db1d7SKowalski, Kamil 651179db1d7SKowalski, Kamil EthernetInterfaceData eth_data{}; 652179db1d7SKowalski, Kamil std::vector<IPv4AddressData> ipv4_data; 653179db1d7SKowalski, Kamil ipv4_data.reserve(MAX_IPV4_ADDRESSES_PER_INTERFACE); 654179db1d7SKowalski, Kamil 655179db1d7SKowalski, Kamil if (error_code) { 656179db1d7SKowalski, Kamil // Something wrong on DBus, the error_code is not important at 657179db1d7SKowalski, Kamil // this moment, just return success=false, and empty output. Since 658179db1d7SKowalski, Kamil // size of vector may vary depending on information from Network 659179db1d7SKowalski, Kamil // Manager, and empty output could not be treated same way as 660179db1d7SKowalski, Kamil // error. 661179db1d7SKowalski, Kamil callback(false, eth_data, ipv4_data); 662179db1d7SKowalski, Kamil return; 663179db1d7SKowalski, Kamil } 664179db1d7SKowalski, Kamil 665179db1d7SKowalski, Kamil extractEthernetInterfaceData(ethiface_id, resp, eth_data); 666179db1d7SKowalski, Kamil extractIPv4Data(ethiface_id, resp, ipv4_data); 667179db1d7SKowalski, Kamil 668179db1d7SKowalski, Kamil // Fix global GW 669179db1d7SKowalski, Kamil for (IPv4AddressData &ipv4 : ipv4_data) { 670179db1d7SKowalski, Kamil if ((ipv4.global) && 671179db1d7SKowalski, Kamil ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) { 672179db1d7SKowalski, Kamil ipv4.gateway = eth_data.default_gateway; 673179db1d7SKowalski, Kamil } 674179db1d7SKowalski, Kamil } 675179db1d7SKowalski, Kamil 676179db1d7SKowalski, Kamil // Finally make a callback with usefull data 677179db1d7SKowalski, Kamil callback(true, eth_data, ipv4_data); 678179db1d7SKowalski, Kamil }, 679179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 680179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 681179db1d7SKowalski, Kamil }; 682179db1d7SKowalski, Kamil 683179db1d7SKowalski, Kamil /** 6849391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6859391bb9cSRapkiewicz, Pawel * Manager 6869391bb9cSRapkiewicz, Pawel * @param callback a function that shall be called to convert Dbus output into 6879391bb9cSRapkiewicz, Pawel * JSON. 6889391bb9cSRapkiewicz, Pawel */ 6899391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 6909391bb9cSRapkiewicz, Pawel void getEthernetIfaceList(CallbackFunc &&callback) { 6919391bb9cSRapkiewicz, Pawel crow::connections::system_bus->async_method_call( 6929391bb9cSRapkiewicz, Pawel [ this, callback{std::move(callback)} ]( 6939391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 694aa2e59c1SEd Tanous GetManagedObjectsType &resp) { 6959391bb9cSRapkiewicz, Pawel // Callback requires vector<string> to retrieve all available ethernet 6969391bb9cSRapkiewicz, Pawel // interfaces 6979391bb9cSRapkiewicz, Pawel std::vector<std::string> iface_list; 6989391bb9cSRapkiewicz, Pawel iface_list.reserve(resp.size()); 6999391bb9cSRapkiewicz, Pawel if (error_code) { 7009391bb9cSRapkiewicz, Pawel // Something wrong on DBus, the error_code is not important at this 7019391bb9cSRapkiewicz, Pawel // moment, just return success=false, and empty output. Since size 7029391bb9cSRapkiewicz, Pawel // of vector may vary depending on information from Network Manager, 7039391bb9cSRapkiewicz, Pawel // and empty output could not be treated same way as error. 7049391bb9cSRapkiewicz, Pawel callback(false, iface_list); 7059391bb9cSRapkiewicz, Pawel return; 7069391bb9cSRapkiewicz, Pawel } 7079391bb9cSRapkiewicz, Pawel 7089391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7099391bb9cSRapkiewicz, Pawel for (auto &objpath : resp) { 7109391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7119391bb9cSRapkiewicz, Pawel for (auto &interface : objpath.second) { 7129391bb9cSRapkiewicz, Pawel // If interface is xyz.openbmc_project.Network.EthernetInterface, 7139391bb9cSRapkiewicz, Pawel // this is what we're looking for. 7149391bb9cSRapkiewicz, Pawel if (interface.first == 7159391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface") { 716aa2e59c1SEd Tanous // Cut out everyting until last "/", ... 717daf36e2eSEd Tanous const std::string &iface_id = 718daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first); 7199391bb9cSRapkiewicz, Pawel std::size_t last_pos = iface_id.rfind("/"); 7209391bb9cSRapkiewicz, Pawel if (last_pos != std::string::npos) { 7219391bb9cSRapkiewicz, Pawel // and put it into output vector. 7229391bb9cSRapkiewicz, Pawel iface_list.emplace_back(iface_id.substr(last_pos + 1)); 7239391bb9cSRapkiewicz, Pawel } 7249391bb9cSRapkiewicz, Pawel } 7259391bb9cSRapkiewicz, Pawel } 7269391bb9cSRapkiewicz, Pawel } 727274fad5aSGunnar Mills // Finally make a callback with useful data 7289391bb9cSRapkiewicz, Pawel callback(true, iface_list); 7299391bb9cSRapkiewicz, Pawel }, 730aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 731aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7329391bb9cSRapkiewicz, Pawel }; 7339391bb9cSRapkiewicz, Pawel }; 7349391bb9cSRapkiewicz, Pawel 7359391bb9cSRapkiewicz, Pawel /** 7369391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7379391bb9cSRapkiewicz, Pawel */ 7389391bb9cSRapkiewicz, Pawel class EthernetCollection : public Node { 7399391bb9cSRapkiewicz, Pawel public: 7409391bb9cSRapkiewicz, Pawel template <typename CrowApp> 7419391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 7429391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 7439391bb9cSRapkiewicz, Pawel // GetSubroutes method 7449391bb9cSRapkiewicz, Pawel EthernetCollection(CrowApp &app) 7459391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") { 7469391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7479391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7489391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7499391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7509391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7519391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces"; 7529391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7539391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7549391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7559391bb9cSRapkiewicz, Pawel 756588c3f0dSKowalski, Kamil entityPrivileges = { 757588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 758e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 759e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 760e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 761e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 762e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7639391bb9cSRapkiewicz, Pawel } 7649391bb9cSRapkiewicz, Pawel 7659391bb9cSRapkiewicz, Pawel private: 7669391bb9cSRapkiewicz, Pawel /** 7679391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7689391bb9cSRapkiewicz, Pawel */ 7699391bb9cSRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 7709391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 7719391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 7729391bb9cSRapkiewicz, Pawel // any Manager, not only hardcoded 'openbmc'. 7739391bb9cSRapkiewicz, Pawel std::string manager_id = "openbmc"; 7749391bb9cSRapkiewicz, Pawel 7759391bb9cSRapkiewicz, Pawel // Get eth interface list, and call the below callback for JSON preparation 7769391bb9cSRapkiewicz, Pawel ethernet_provider.getEthernetIfaceList( 7779391bb9cSRapkiewicz, Pawel [&, manager_id{std::move(manager_id)} ]( 7789391bb9cSRapkiewicz, Pawel const bool &success, const std::vector<std::string> &iface_list) { 7799391bb9cSRapkiewicz, Pawel if (success) { 7809391bb9cSRapkiewicz, Pawel nlohmann::json iface_array = nlohmann::json::array(); 7819391bb9cSRapkiewicz, Pawel for (const std::string &iface_item : iface_list) { 7829391bb9cSRapkiewicz, Pawel iface_array.push_back( 7839391bb9cSRapkiewicz, Pawel {{"@odata.id", "/redfish/v1/Managers/" + manager_id + 7849391bb9cSRapkiewicz, Pawel "/EthernetInterfaces/" + iface_item}}); 7859391bb9cSRapkiewicz, Pawel } 7869391bb9cSRapkiewicz, Pawel Node::json["Members"] = iface_array; 7879391bb9cSRapkiewicz, Pawel Node::json["Members@odata.count"] = iface_array.size(); 7889391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = 7899391bb9cSRapkiewicz, Pawel "/redfish/v1/Managers/" + manager_id + "/EthernetInterfaces"; 7909391bb9cSRapkiewicz, Pawel res.json_value = Node::json; 7919391bb9cSRapkiewicz, Pawel } else { 7929391bb9cSRapkiewicz, Pawel // No success, best what we can do is return INTERNALL ERROR 793e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 7949391bb9cSRapkiewicz, Pawel } 7959391bb9cSRapkiewicz, Pawel res.end(); 7969391bb9cSRapkiewicz, Pawel }); 7979391bb9cSRapkiewicz, Pawel } 7989391bb9cSRapkiewicz, Pawel 7999391bb9cSRapkiewicz, Pawel // Ethernet Provider object 8009391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 8019391bb9cSRapkiewicz, Pawel OnDemandEthernetProvider ethernet_provider; 8029391bb9cSRapkiewicz, Pawel }; 8039391bb9cSRapkiewicz, Pawel 8049391bb9cSRapkiewicz, Pawel /** 8059391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8069391bb9cSRapkiewicz, Pawel */ 8079391bb9cSRapkiewicz, Pawel class EthernetInterface : public Node { 8089391bb9cSRapkiewicz, Pawel public: 8099391bb9cSRapkiewicz, Pawel /* 8109391bb9cSRapkiewicz, Pawel * Default Constructor 8119391bb9cSRapkiewicz, Pawel */ 8129391bb9cSRapkiewicz, Pawel template <typename CrowApp> 8139391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 8149391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 8159391bb9cSRapkiewicz, Pawel // GetSubroutes method 8169391bb9cSRapkiewicz, Pawel EthernetInterface(CrowApp &app) 8179391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/", 8189391bb9cSRapkiewicz, Pawel std::string()) { 8199391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface"; 8209391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8219391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8229391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8239391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8249391bb9cSRapkiewicz, Pawel 825588c3f0dSKowalski, Kamil entityPrivileges = { 826588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 827e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 828e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 829e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 830e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 831e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8329391bb9cSRapkiewicz, Pawel } 8339391bb9cSRapkiewicz, Pawel 834e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 835e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 836e439f0f8SKowalski, Kamil const nlohmann::json &input, 837588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 838e439f0f8SKowalski, Kamil const std::string &pathPrefix, 839588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 840588c3f0dSKowalski, Kamil if (!input.is_object()) { 841588c3f0dSKowalski, Kamil messages::addMessageToJson( 842588c3f0dSKowalski, Kamil asyncResp->res.json_value, 843e439f0f8SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "VLAN"), pathPrefix); 844588c3f0dSKowalski, Kamil return; 845588c3f0dSKowalski, Kamil } 846588c3f0dSKowalski, Kamil 847e439f0f8SKowalski, Kamil const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix; 848e439f0f8SKowalski, Kamil nlohmann::json ¶msJson = 849e439f0f8SKowalski, Kamil (pathPrefix == "/") 850e439f0f8SKowalski, Kamil ? asyncResp->res.json_value 851e439f0f8SKowalski, Kamil : asyncResp->res.json_value[nlohmann::json_pointer<nlohmann::json>( 852e439f0f8SKowalski, Kamil pathPrefix)]; 853588c3f0dSKowalski, Kamil bool inputVlanEnabled; 854588c3f0dSKowalski, Kamil uint64_t inputVlanId; 855e439f0f8SKowalski, Kamil 856588c3f0dSKowalski, Kamil json_util::Result inputVlanEnabledState = json_util::getBool( 857588c3f0dSKowalski, Kamil "VLANEnable", input, inputVlanEnabled, 858588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 859e439f0f8SKowalski, Kamil asyncResp->res.json_value, std::string(pathStart + "/VLANEnable")); 860588c3f0dSKowalski, Kamil json_util::Result inputVlanIdState = json_util::getUnsigned( 861588c3f0dSKowalski, Kamil "VLANId", input, inputVlanId, 862588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 863e439f0f8SKowalski, Kamil asyncResp->res.json_value, std::string(pathStart + "/VLANId")); 864588c3f0dSKowalski, Kamil bool inputInvalid = false; 865588c3f0dSKowalski, Kamil 866588c3f0dSKowalski, Kamil // Do not proceed if fields in VLAN object were of wrong type 867588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::WRONG_TYPE || 868588c3f0dSKowalski, Kamil inputVlanIdState == json_util::Result::WRONG_TYPE) { 869588c3f0dSKowalski, Kamil return; 870588c3f0dSKowalski, Kamil } 871588c3f0dSKowalski, Kamil 872588c3f0dSKowalski, Kamil // Verify input 873588c3f0dSKowalski, Kamil if (eth_data.vlan_id == nullptr) { 874e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 875e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 876588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 877588c3f0dSKowalski, Kamil messages::propertyMissing("VLANEnable"), 878e439f0f8SKowalski, Kamil pathPrefix); 879588c3f0dSKowalski, Kamil 880588c3f0dSKowalski, Kamil inputInvalid = true; 881588c3f0dSKowalski, Kamil } else { 882588c3f0dSKowalski, Kamil // Load actual data into field values if they were not provided 883588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::NOT_EXIST) { 884588c3f0dSKowalski, Kamil inputVlanEnabled = true; 885588c3f0dSKowalski, Kamil } 886588c3f0dSKowalski, Kamil 887588c3f0dSKowalski, Kamil if (inputVlanIdState == json_util::Result::NOT_EXIST) { 888588c3f0dSKowalski, Kamil inputVlanId = *eth_data.vlan_id; 889588c3f0dSKowalski, Kamil } 890588c3f0dSKowalski, Kamil } 891588c3f0dSKowalski, Kamil 892588c3f0dSKowalski, Kamil // Do not proceed if input has not been valid 893588c3f0dSKowalski, Kamil if (inputInvalid) { 894588c3f0dSKowalski, Kamil return; 895588c3f0dSKowalski, Kamil } 896588c3f0dSKowalski, Kamil 897588c3f0dSKowalski, Kamil // VLAN is configured on the interface 898588c3f0dSKowalski, Kamil if (inputVlanEnabled == true && inputVlanId != *eth_data.vlan_id) { 899588c3f0dSKowalski, Kamil // Change VLAN Id 900e439f0f8SKowalski, Kamil paramsJson["VLANId"] = inputVlanId; 901e439f0f8SKowalski, Kamil OnDemandEthernetProvider::changeVlanId( 902e439f0f8SKowalski, Kamil ifaceId, static_cast<uint32_t>(inputVlanId), 903e439f0f8SKowalski, Kamil [&, asyncResp, pathPrefx{std::move(pathPrefix)} ]( 904e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 905588c3f0dSKowalski, Kamil if (ec) { 906588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 907e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 908588c3f0dSKowalski, Kamil } else { 909e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = true; 910e439f0f8SKowalski, Kamil } 911e439f0f8SKowalski, Kamil }); 912e439f0f8SKowalski, Kamil } else if (inputVlanEnabled == false) { 913e439f0f8SKowalski, Kamil // Disable VLAN 914e439f0f8SKowalski, Kamil OnDemandEthernetProvider::disableVlan( 915e439f0f8SKowalski, Kamil ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)} ]( 916e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 917e439f0f8SKowalski, Kamil if (ec) { 918e439f0f8SKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 919e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 920e439f0f8SKowalski, Kamil } else { 921e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = false; 922588c3f0dSKowalski, Kamil } 923588c3f0dSKowalski, Kamil }); 924588c3f0dSKowalski, Kamil } 925588c3f0dSKowalski, Kamil } 926588c3f0dSKowalski, Kamil 927e439f0f8SKowalski, Kamil private: 928588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 929588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 930588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 931588c3f0dSKowalski, Kamil if (input.is_string()) { 932588c3f0dSKowalski, Kamil std::string newHostname = input.get<std::string>(); 933588c3f0dSKowalski, Kamil 934588c3f0dSKowalski, Kamil if (eth_data.hostname == nullptr || newHostname != *eth_data.hostname) { 935588c3f0dSKowalski, Kamil // Change hostname 936588c3f0dSKowalski, Kamil ethernet_provider.setHostName( 937588c3f0dSKowalski, Kamil newHostname, 938588c3f0dSKowalski, Kamil [asyncResp, newHostname](const boost::system::error_code ec) { 939588c3f0dSKowalski, Kamil if (ec) { 940588c3f0dSKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 941588c3f0dSKowalski, Kamil messages::internalError(), 942588c3f0dSKowalski, Kamil "/HostName"); 943588c3f0dSKowalski, Kamil } else { 944588c3f0dSKowalski, Kamil asyncResp->res.json_value["HostName"] = newHostname; 945588c3f0dSKowalski, Kamil } 946588c3f0dSKowalski, Kamil }); 947588c3f0dSKowalski, Kamil } 948588c3f0dSKowalski, Kamil } else { 949588c3f0dSKowalski, Kamil messages::addMessageToJson( 950588c3f0dSKowalski, Kamil asyncResp->res.json_value, 951588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "HostName"), 952588c3f0dSKowalski, Kamil "/HostName"); 953588c3f0dSKowalski, Kamil } 954588c3f0dSKowalski, Kamil } 955588c3f0dSKowalski, Kamil 956179db1d7SKowalski, Kamil void handleIPv4Patch(const std::string &ifaceId, const nlohmann::json &input, 957179db1d7SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data, 958179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 959179db1d7SKowalski, Kamil if (!input.is_array()) { 960179db1d7SKowalski, Kamil messages::addMessageToJson( 961179db1d7SKowalski, Kamil asyncResp->res.json_value, 962179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 963179db1d7SKowalski, Kamil "/IPv4Addresses"); 964179db1d7SKowalski, Kamil return; 965179db1d7SKowalski, Kamil } 966179db1d7SKowalski, Kamil 967179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 968179db1d7SKowalski, Kamil if (input.size() < ipv4_data.size()) { 969179db1d7SKowalski, Kamil // TODO(kkowalsk) This should be a message indicating that not enough 970179db1d7SKowalski, Kamil // data has been provided 971179db1d7SKowalski, Kamil messages::addMessageToJson(asyncResp->res.json_value, 972179db1d7SKowalski, Kamil messages::internalError(), "/IPv4Addresses"); 973179db1d7SKowalski, Kamil return; 974179db1d7SKowalski, Kamil } 975179db1d7SKowalski, Kamil 976179db1d7SKowalski, Kamil json_util::Result addressFieldState; 977179db1d7SKowalski, Kamil json_util::Result subnetMaskFieldState; 978179db1d7SKowalski, Kamil json_util::Result addressOriginFieldState; 979179db1d7SKowalski, Kamil json_util::Result gatewayFieldState; 980179db1d7SKowalski, Kamil const std::string *addressFieldValue; 981179db1d7SKowalski, Kamil const std::string *subnetMaskFieldValue; 982179db1d7SKowalski, Kamil const std::string *addressOriginFieldValue = nullptr; 983179db1d7SKowalski, Kamil const std::string *gatewayFieldValue; 984179db1d7SKowalski, Kamil uint8_t subnetMaskAsPrefixLength; 985179db1d7SKowalski, Kamil std::string addressOriginInDBusFormat; 986179db1d7SKowalski, Kamil 987179db1d7SKowalski, Kamil bool errorDetected = false; 988179db1d7SKowalski, Kamil for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) { 989179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 990179db1d7SKowalski, Kamil if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) { 991179db1d7SKowalski, Kamil // Invalid object type 992179db1d7SKowalski, Kamil messages::addMessageToJson( 993179db1d7SKowalski, Kamil asyncResp->res.json_value, 994179db1d7SKowalski, Kamil messages::propertyValueTypeError(input[entryIdx].dump(), 995179db1d7SKowalski, Kamil "IPv4Address"), 996179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx)); 997179db1d7SKowalski, Kamil 998179db1d7SKowalski, Kamil continue; 999179db1d7SKowalski, Kamil } 1000179db1d7SKowalski, Kamil 1001179db1d7SKowalski, Kamil // Try to load fields 1002179db1d7SKowalski, Kamil addressFieldState = json_util::getString( 1003179db1d7SKowalski, Kamil "Address", input[entryIdx], addressFieldValue, 1004179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1005179db1d7SKowalski, Kamil asyncResp->res.json_value, 1006179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1007179db1d7SKowalski, Kamil subnetMaskFieldState = json_util::getString( 1008179db1d7SKowalski, Kamil "SubnetMask", input[entryIdx], subnetMaskFieldValue, 1009179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1010179db1d7SKowalski, Kamil asyncResp->res.json_value, 1011179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1012179db1d7SKowalski, Kamil addressOriginFieldState = json_util::getString( 1013179db1d7SKowalski, Kamil "AddressOrigin", input[entryIdx], addressOriginFieldValue, 1014179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1015179db1d7SKowalski, Kamil asyncResp->res.json_value, 1016179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1017179db1d7SKowalski, Kamil gatewayFieldState = json_util::getString( 1018179db1d7SKowalski, Kamil "Gateway", input[entryIdx], gatewayFieldValue, 1019179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1020179db1d7SKowalski, Kamil asyncResp->res.json_value, 1021179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1022179db1d7SKowalski, Kamil 1023179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::WRONG_TYPE || 1024179db1d7SKowalski, Kamil subnetMaskFieldState == json_util::Result::WRONG_TYPE || 1025179db1d7SKowalski, Kamil addressOriginFieldState == json_util::Result::WRONG_TYPE || 1026179db1d7SKowalski, Kamil gatewayFieldState == json_util::Result::WRONG_TYPE) { 1027179db1d7SKowalski, Kamil return; 1028179db1d7SKowalski, Kamil } 1029179db1d7SKowalski, Kamil 1030179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1031179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount(*addressFieldValue)) { 1032179db1d7SKowalski, Kamil errorDetected = true; 1033179db1d7SKowalski, Kamil messages::addMessageToJson( 1034179db1d7SKowalski, Kamil asyncResp->res.json_value, 1035179db1d7SKowalski, Kamil messages::propertyValueFormatError(*addressFieldValue, "Address"), 1036179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1037179db1d7SKowalski, Kamil } 1038179db1d7SKowalski, Kamil 1039179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1040179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount( 1041179db1d7SKowalski, Kamil *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) { 1042179db1d7SKowalski, Kamil errorDetected = true; 1043179db1d7SKowalski, Kamil messages::addMessageToJson( 1044179db1d7SKowalski, Kamil asyncResp->res.json_value, 1045179db1d7SKowalski, Kamil messages::propertyValueFormatError(*subnetMaskFieldValue, 1046179db1d7SKowalski, Kamil "SubnetMask"), 1047179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1048179db1d7SKowalski, Kamil } 1049179db1d7SKowalski, Kamil 1050179db1d7SKowalski, Kamil // Get Address origin in proper format 1051179db1d7SKowalski, Kamil addressOriginInDBusFormat = 1052179db1d7SKowalski, Kamil ethernet_provider.translateAddressOriginBetweenDBusAndRedfish( 1053179db1d7SKowalski, Kamil addressOriginFieldValue, true, false); 1054179db1d7SKowalski, Kamil 1055179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1056179db1d7SKowalski, Kamil addressOriginInDBusFormat.empty()) { 1057179db1d7SKowalski, Kamil errorDetected = true; 1058179db1d7SKowalski, Kamil messages::addMessageToJson( 1059179db1d7SKowalski, Kamil asyncResp->res.json_value, 1060179db1d7SKowalski, Kamil messages::propertyValueNotInList(*addressOriginFieldValue, 1061179db1d7SKowalski, Kamil "AddressOrigin"), 1062179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1063179db1d7SKowalski, Kamil } 1064179db1d7SKowalski, Kamil 1065179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1066179db1d7SKowalski, Kamil !ethernet_provider.ipv4VerifyIpAndGetBitcount(*gatewayFieldValue)) { 1067179db1d7SKowalski, Kamil errorDetected = true; 1068179db1d7SKowalski, Kamil messages::addMessageToJson( 1069179db1d7SKowalski, Kamil asyncResp->res.json_value, 1070179db1d7SKowalski, Kamil messages::propertyValueFormatError(*gatewayFieldValue, "Gateway"), 1071179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1072179db1d7SKowalski, Kamil } 1073179db1d7SKowalski, Kamil 1074179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1075179db1d7SKowalski, Kamil // end loop 1076179db1d7SKowalski, Kamil if (errorDetected) { 1077179db1d7SKowalski, Kamil errorDetected = false; 1078179db1d7SKowalski, Kamil continue; 1079179db1d7SKowalski, Kamil } 1080179db1d7SKowalski, Kamil 1081179db1d7SKowalski, Kamil if (entryIdx >= ipv4_data.size()) { 1082179db1d7SKowalski, Kamil asyncResp->res.json_value["IPv4Addresses"][entryIdx] = input[entryIdx]; 1083179db1d7SKowalski, Kamil 1084179db1d7SKowalski, Kamil // Verify that all field were provided 1085179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::NOT_EXIST) { 1086179db1d7SKowalski, Kamil errorDetected = true; 1087179db1d7SKowalski, Kamil messages::addMessageToJson( 1088179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::propertyMissing("Address"), 1089179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1090179db1d7SKowalski, Kamil } 1091179db1d7SKowalski, Kamil 1092179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::NOT_EXIST) { 1093179db1d7SKowalski, Kamil errorDetected = true; 1094179db1d7SKowalski, Kamil messages::addMessageToJson( 1095179db1d7SKowalski, Kamil asyncResp->res.json_value, 1096179db1d7SKowalski, Kamil messages::propertyMissing("SubnetMask"), 1097179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1098179db1d7SKowalski, Kamil } 1099179db1d7SKowalski, Kamil 1100179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::NOT_EXIST) { 1101179db1d7SKowalski, Kamil errorDetected = true; 1102179db1d7SKowalski, Kamil messages::addMessageToJson( 1103179db1d7SKowalski, Kamil asyncResp->res.json_value, 1104179db1d7SKowalski, Kamil messages::propertyMissing("AddressOrigin"), 1105179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1106179db1d7SKowalski, Kamil } 1107179db1d7SKowalski, Kamil 1108179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::NOT_EXIST) { 1109179db1d7SKowalski, Kamil errorDetected = true; 1110179db1d7SKowalski, Kamil messages::addMessageToJson( 1111179db1d7SKowalski, Kamil asyncResp->res.json_value, messages::propertyMissing("Gateway"), 1112179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1113179db1d7SKowalski, Kamil } 1114179db1d7SKowalski, Kamil 1115179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1116179db1d7SKowalski, Kamil // end loop 1117179db1d7SKowalski, Kamil if (errorDetected) { 1118179db1d7SKowalski, Kamil errorDetected = false; 1119179db1d7SKowalski, Kamil continue; 1120179db1d7SKowalski, Kamil } 1121179db1d7SKowalski, Kamil 1122179db1d7SKowalski, Kamil // Create IPv4 with provided data 1123179db1d7SKowalski, Kamil ethernet_provider.createIPv4( 1124179db1d7SKowalski, Kamil ifaceId, entryIdx, subnetMaskAsPrefixLength, *gatewayFieldValue, 1125179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1126179db1d7SKowalski, Kamil } else { 1127179db1d7SKowalski, Kamil // Existing object that should be modified/deleted/remain unchanged 1128179db1d7SKowalski, Kamil if (input[entryIdx].is_null()) { 1129179db1d7SKowalski, Kamil // Object should be deleted 1130179db1d7SKowalski, Kamil ethernet_provider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, 1131179db1d7SKowalski, Kamil entryIdx, asyncResp); 1132179db1d7SKowalski, Kamil } else if (input[entryIdx].is_object()) { 1133179db1d7SKowalski, Kamil if (input[entryIdx].size() == 0) { 1134179db1d7SKowalski, Kamil // Object shall remain unchanged 1135179db1d7SKowalski, Kamil continue; 1136179db1d7SKowalski, Kamil } 1137179db1d7SKowalski, Kamil 1138179db1d7SKowalski, Kamil // Apply changes 1139179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1140179db1d7SKowalski, Kamil ipv4_data[entryIdx].address != nullptr && 1141179db1d7SKowalski, Kamil *ipv4_data[entryIdx].address != *addressFieldValue) { 1142179db1d7SKowalski, Kamil ethernet_provider.changeIPv4AddressProperty( 1143179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Address", 1144179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1145179db1d7SKowalski, Kamil } 1146179db1d7SKowalski, Kamil 1147179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1148179db1d7SKowalski, Kamil ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) { 1149179db1d7SKowalski, Kamil ethernet_provider.changeIPv4SubnetMaskProperty( 1150179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1151179db1d7SKowalski, Kamil *subnetMaskFieldValue, subnetMaskAsPrefixLength, asyncResp); 1152179db1d7SKowalski, Kamil } 1153179db1d7SKowalski, Kamil 1154179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1155179db1d7SKowalski, Kamil ipv4_data[entryIdx].origin != *addressFieldValue) { 1156179db1d7SKowalski, Kamil ethernet_provider.changeIPv4Origin( 1157179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1158179db1d7SKowalski, Kamil *addressOriginFieldValue, addressOriginInDBusFormat, asyncResp); 1159179db1d7SKowalski, Kamil } 1160179db1d7SKowalski, Kamil 1161179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1162179db1d7SKowalski, Kamil ipv4_data[entryIdx].gateway != nullptr && 1163179db1d7SKowalski, Kamil *ipv4_data[entryIdx].gateway != *gatewayFieldValue) { 1164179db1d7SKowalski, Kamil ethernet_provider.changeIPv4AddressProperty( 1165179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Gateway", 1166179db1d7SKowalski, Kamil *gatewayFieldValue, asyncResp); 1167179db1d7SKowalski, Kamil } 1168179db1d7SKowalski, Kamil } 1169179db1d7SKowalski, Kamil } 1170179db1d7SKowalski, Kamil } 1171179db1d7SKowalski, Kamil } 1172179db1d7SKowalski, Kamil 1173588c3f0dSKowalski, Kamil nlohmann::json parseInterfaceData( 1174588c3f0dSKowalski, Kamil const std::string &iface_id, const EthernetInterfaceData ð_data, 1175588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1176588c3f0dSKowalski, Kamil // Copy JSON object to avoid race condition 1177588c3f0dSKowalski, Kamil nlohmann::json json_response(Node::json); 1178588c3f0dSKowalski, Kamil 1179588c3f0dSKowalski, Kamil // Fill out obvious data... 1180588c3f0dSKowalski, Kamil json_response["Id"] = iface_id; 1181588c3f0dSKowalski, Kamil json_response["@odata.id"] = 1182588c3f0dSKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + iface_id; 1183588c3f0dSKowalski, Kamil 1184588c3f0dSKowalski, Kamil // ... then the one from DBus, regarding eth iface... 1185588c3f0dSKowalski, Kamil if (eth_data.speed != nullptr) json_response["SpeedMbps"] = *eth_data.speed; 1186588c3f0dSKowalski, Kamil 1187588c3f0dSKowalski, Kamil if (eth_data.mac_address != nullptr) 1188588c3f0dSKowalski, Kamil json_response["MACAddress"] = *eth_data.mac_address; 1189588c3f0dSKowalski, Kamil 1190588c3f0dSKowalski, Kamil if (eth_data.hostname != nullptr) 1191588c3f0dSKowalski, Kamil json_response["HostName"] = *eth_data.hostname; 1192588c3f0dSKowalski, Kamil 1193588c3f0dSKowalski, Kamil if (eth_data.vlan_id != nullptr) { 1194588c3f0dSKowalski, Kamil nlohmann::json &vlanObj = json_response["VLAN"]; 1195588c3f0dSKowalski, Kamil vlanObj["VLANEnable"] = true; 1196588c3f0dSKowalski, Kamil vlanObj["VLANId"] = *eth_data.vlan_id; 1197588c3f0dSKowalski, Kamil } 1198588c3f0dSKowalski, Kamil 1199588c3f0dSKowalski, Kamil // ... at last, check if there are IPv4 data and prepare appropriate 1200588c3f0dSKowalski, Kamil // collection 1201588c3f0dSKowalski, Kamil if (ipv4_data.size() > 0) { 1202588c3f0dSKowalski, Kamil nlohmann::json ipv4_array = nlohmann::json::array(); 1203588c3f0dSKowalski, Kamil for (auto &ipv4_config : ipv4_data) { 1204588c3f0dSKowalski, Kamil nlohmann::json json_ipv4; 1205588c3f0dSKowalski, Kamil if (ipv4_config.address != nullptr) { 1206588c3f0dSKowalski, Kamil json_ipv4["Address"] = *ipv4_config.address; 1207588c3f0dSKowalski, Kamil if (ipv4_config.gateway != nullptr) 1208588c3f0dSKowalski, Kamil json_ipv4["Gateway"] = *ipv4_config.gateway; 1209588c3f0dSKowalski, Kamil 1210588c3f0dSKowalski, Kamil json_ipv4["AddressOrigin"] = ipv4_config.origin; 1211588c3f0dSKowalski, Kamil json_ipv4["SubnetMask"] = ipv4_config.netmask; 1212588c3f0dSKowalski, Kamil 1213588c3f0dSKowalski, Kamil ipv4_array.push_back(std::move(json_ipv4)); 1214588c3f0dSKowalski, Kamil } 1215588c3f0dSKowalski, Kamil } 1216588c3f0dSKowalski, Kamil json_response["IPv4Addresses"] = std::move(ipv4_array); 1217588c3f0dSKowalski, Kamil } 1218588c3f0dSKowalski, Kamil 1219588c3f0dSKowalski, Kamil return json_response; 1220588c3f0dSKowalski, Kamil } 1221588c3f0dSKowalski, Kamil 12229391bb9cSRapkiewicz, Pawel /** 12239391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12249391bb9cSRapkiewicz, Pawel */ 12259391bb9cSRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 12269391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 12279391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call (two params) to get 12289391bb9cSRapkiewicz, Pawel // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 12299391bb9cSRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 12309391bb9cSRapkiewicz, Pawel // impossible. 12319391bb9cSRapkiewicz, Pawel if (params.size() != 1) { 1232e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 12339391bb9cSRapkiewicz, Pawel res.end(); 12349391bb9cSRapkiewicz, Pawel return; 12359391bb9cSRapkiewicz, Pawel } 12369391bb9cSRapkiewicz, Pawel 12379391bb9cSRapkiewicz, Pawel const std::string &iface_id = params[0]; 12389391bb9cSRapkiewicz, Pawel 12399391bb9cSRapkiewicz, Pawel // Get single eth interface data, and call the below callback for JSON 12409391bb9cSRapkiewicz, Pawel // preparation 12419391bb9cSRapkiewicz, Pawel ethernet_provider.getEthernetIfaceData( 12429391bb9cSRapkiewicz, Pawel iface_id, [&, iface_id](const bool &success, 12439391bb9cSRapkiewicz, Pawel const EthernetInterfaceData ð_data, 12449391bb9cSRapkiewicz, Pawel const std::vector<IPv4AddressData> &ipv4_data) { 12459391bb9cSRapkiewicz, Pawel if (success) { 1246588c3f0dSKowalski, Kamil res.json_value = parseInterfaceData(iface_id, eth_data, ipv4_data); 12479391bb9cSRapkiewicz, Pawel } else { 12489391bb9cSRapkiewicz, Pawel // ... otherwise return error 12499391bb9cSRapkiewicz, Pawel // TODO(Pawel)consider distinguish between non existing object, and 12509391bb9cSRapkiewicz, Pawel // other errors 1251e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1252e439f0f8SKowalski, Kamil res.json_value, 1253e439f0f8SKowalski, Kamil messages::resourceNotFound("EthernetInterface", iface_id)); 1254e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 12559391bb9cSRapkiewicz, Pawel } 12569391bb9cSRapkiewicz, Pawel res.end(); 12579391bb9cSRapkiewicz, Pawel }); 12589391bb9cSRapkiewicz, Pawel } 12599391bb9cSRapkiewicz, Pawel 1260588c3f0dSKowalski, Kamil void doPatch(crow::response &res, const crow::request &req, 1261588c3f0dSKowalski, Kamil const std::vector<std::string> ¶ms) override { 1262588c3f0dSKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1263588c3f0dSKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1264588c3f0dSKowalski, Kamil // Check if there is required param, truly entering this shall be 1265588c3f0dSKowalski, Kamil // impossible. 1266588c3f0dSKowalski, Kamil if (params.size() != 1) { 1267588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1268588c3f0dSKowalski, Kamil res.end(); 1269588c3f0dSKowalski, Kamil return; 1270588c3f0dSKowalski, Kamil } 1271588c3f0dSKowalski, Kamil 1272588c3f0dSKowalski, Kamil const std::string &iface_id = params[0]; 1273588c3f0dSKowalski, Kamil 1274179db1d7SKowalski, Kamil nlohmann::json patchReq; 1275588c3f0dSKowalski, Kamil 1276179db1d7SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1277588c3f0dSKowalski, Kamil return; 1278588c3f0dSKowalski, Kamil } 1279588c3f0dSKowalski, Kamil 1280588c3f0dSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1281588c3f0dSKowalski, Kamil // preparation 1282588c3f0dSKowalski, Kamil ethernet_provider.getEthernetIfaceData( 1283588c3f0dSKowalski, Kamil iface_id, 1284588c3f0dSKowalski, Kamil [&, iface_id, patchReq = std::move(patchReq) ]( 1285588c3f0dSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1286588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1287588c3f0dSKowalski, Kamil if (!success) { 1288588c3f0dSKowalski, Kamil // ... otherwise return error 1289588c3f0dSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1290588c3f0dSKowalski, Kamil // other errors 1291588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1292588c3f0dSKowalski, Kamil res.end(); 1293588c3f0dSKowalski, Kamil 1294588c3f0dSKowalski, Kamil return; 1295588c3f0dSKowalski, Kamil } 1296588c3f0dSKowalski, Kamil 1297588c3f0dSKowalski, Kamil res.json_value = parseInterfaceData(iface_id, eth_data, ipv4_data); 1298588c3f0dSKowalski, Kamil 1299588c3f0dSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1300588c3f0dSKowalski, Kamil std::make_shared<AsyncResp>(res); 1301588c3f0dSKowalski, Kamil 1302588c3f0dSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1303588c3f0dSKowalski, Kamil ++propertyIt) { 1304588c3f0dSKowalski, Kamil if (propertyIt.key() == "VLAN") { 1305e439f0f8SKowalski, Kamil handleVlanPatch(iface_id, propertyIt.value(), eth_data, "/VLAN", 1306588c3f0dSKowalski, Kamil asyncResp); 1307588c3f0dSKowalski, Kamil } else if (propertyIt.key() == "HostName") { 1308588c3f0dSKowalski, Kamil handleHostnamePatch(propertyIt.value(), eth_data, asyncResp); 1309179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv4Addresses") { 1310179db1d7SKowalski, Kamil handleIPv4Patch(iface_id, propertyIt.value(), ipv4_data, 1311179db1d7SKowalski, Kamil asyncResp); 1312179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv6Addresses") { 1313179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1314179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 1315179db1d7SKowalski, Kamil res.json_value, 1316179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1317588c3f0dSKowalski, Kamil } else { 1318588c3f0dSKowalski, Kamil auto fieldInJsonIt = res.json_value.find(propertyIt.key()); 1319588c3f0dSKowalski, Kamil 1320588c3f0dSKowalski, Kamil if (fieldInJsonIt == res.json_value.end()) { 1321588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1322588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1323588c3f0dSKowalski, Kamil res.json_value, 1324588c3f0dSKowalski, Kamil messages::propertyUnknown(propertyIt.key())); 1325588c3f0dSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1326588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1327588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1328588c3f0dSKowalski, Kamil res.json_value, 1329588c3f0dSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1330588c3f0dSKowalski, Kamil } 1331588c3f0dSKowalski, Kamil } 1332588c3f0dSKowalski, Kamil } 1333588c3f0dSKowalski, Kamil }); 1334588c3f0dSKowalski, Kamil } 1335588c3f0dSKowalski, Kamil 13369391bb9cSRapkiewicz, Pawel // Ethernet Provider object 13379391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 13389391bb9cSRapkiewicz, Pawel OnDemandEthernetProvider ethernet_provider; 13399391bb9cSRapkiewicz, Pawel }; 13409391bb9cSRapkiewicz, Pawel 1341e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection; 1342e439f0f8SKowalski, Kamil 1343e439f0f8SKowalski, Kamil /** 1344e439f0f8SKowalski, Kamil * VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema 1345e439f0f8SKowalski, Kamil */ 1346e439f0f8SKowalski, Kamil class VlanNetworkInterface : public Node { 1347e439f0f8SKowalski, Kamil public: 1348e439f0f8SKowalski, Kamil /* 1349e439f0f8SKowalski, Kamil * Default Constructor 1350e439f0f8SKowalski, Kamil */ 1351e439f0f8SKowalski, Kamil template <typename CrowApp> 1352e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1353e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1354e439f0f8SKowalski, Kamil // GetSubroutes method 1355e439f0f8SKowalski, Kamil VlanNetworkInterface(CrowApp &app) 1356e439f0f8SKowalski, Kamil : Node(app, 1357e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/" 1358e439f0f8SKowalski, Kamil "<str>", 1359e439f0f8SKowalski, Kamil std::string(), std::string()) { 1360e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1361e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1362e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1363e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1364e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1365e439f0f8SKowalski, Kamil 1366e439f0f8SKowalski, Kamil entityPrivileges = { 1367e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1368e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1369e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1370e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1371e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1372e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1373e439f0f8SKowalski, Kamil } 1374e439f0f8SKowalski, Kamil 1375e439f0f8SKowalski, Kamil private: 1376e439f0f8SKowalski, Kamil nlohmann::json parseInterfaceData( 1377e439f0f8SKowalski, Kamil const std::string &parent_iface_id, const std::string &iface_id, 1378e439f0f8SKowalski, Kamil const EthernetInterfaceData ð_data, 1379e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1380e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 1381e439f0f8SKowalski, Kamil nlohmann::json json_response(Node::json); 1382e439f0f8SKowalski, Kamil 1383e439f0f8SKowalski, Kamil // Fill out obvious data... 1384e439f0f8SKowalski, Kamil json_response["Id"] = iface_id; 1385e439f0f8SKowalski, Kamil json_response["@odata.id"] = 1386e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + parent_iface_id + 1387e439f0f8SKowalski, Kamil "/VLANs/" + iface_id; 1388e439f0f8SKowalski, Kamil 1389e439f0f8SKowalski, Kamil json_response["VLANEnable"] = true; 1390e439f0f8SKowalski, Kamil json_response["VLANId"] = *eth_data.vlan_id; 1391e439f0f8SKowalski, Kamil 1392e439f0f8SKowalski, Kamil return json_response; 1393e439f0f8SKowalski, Kamil } 1394e439f0f8SKowalski, Kamil 1395e439f0f8SKowalski, Kamil bool verifyNames(crow::response &res, const std::string &parent, 1396e439f0f8SKowalski, Kamil const std::string &iface) { 1397e439f0f8SKowalski, Kamil if (!boost::starts_with(iface, parent + "_")) { 1398e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1399e439f0f8SKowalski, Kamil res.json_value, 1400e439f0f8SKowalski, Kamil messages::resourceNotFound("VLAN Network Interface", iface)); 1401e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::bad_request); 1402e439f0f8SKowalski, Kamil res.end(); 1403e439f0f8SKowalski, Kamil 1404e439f0f8SKowalski, Kamil return false; 1405e439f0f8SKowalski, Kamil } else { 1406e439f0f8SKowalski, Kamil return true; 1407e439f0f8SKowalski, Kamil } 1408e439f0f8SKowalski, Kamil } 1409e439f0f8SKowalski, Kamil 1410e439f0f8SKowalski, Kamil /** 1411e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1412e439f0f8SKowalski, Kamil */ 1413e439f0f8SKowalski, Kamil void doGet(crow::response &res, const crow::request &req, 1414e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1415e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1416e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1417e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1418e439f0f8SKowalski, Kamil // impossible. 1419e439f0f8SKowalski, Kamil if (params.size() != 2) { 1420e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1421e439f0f8SKowalski, Kamil res.end(); 1422e439f0f8SKowalski, Kamil return; 1423e439f0f8SKowalski, Kamil } 1424e439f0f8SKowalski, Kamil 1425e439f0f8SKowalski, Kamil const std::string &parent_iface_id = params[0]; 1426e439f0f8SKowalski, Kamil const std::string &iface_id = params[1]; 1427e439f0f8SKowalski, Kamil 1428e439f0f8SKowalski, Kamil if (!verifyNames(res, parent_iface_id, iface_id)) { 1429e439f0f8SKowalski, Kamil return; 1430e439f0f8SKowalski, Kamil } 1431e439f0f8SKowalski, Kamil 1432e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1433e439f0f8SKowalski, Kamil // preparation 1434e439f0f8SKowalski, Kamil ethernet_provider.getEthernetIfaceData( 1435e439f0f8SKowalski, Kamil iface_id, 1436e439f0f8SKowalski, Kamil [&, parent_iface_id, iface_id]( 1437e439f0f8SKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1438e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1439e439f0f8SKowalski, Kamil if (success && eth_data.vlan_id != nullptr) { 1440e439f0f8SKowalski, Kamil res.json_value = parseInterfaceData(parent_iface_id, iface_id, 1441e439f0f8SKowalski, Kamil eth_data, ipv4_data); 1442e439f0f8SKowalski, Kamil } else { 1443e439f0f8SKowalski, Kamil // ... otherwise return error 1444e439f0f8SKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1445e439f0f8SKowalski, Kamil // and 1446e439f0f8SKowalski, Kamil // other errors 1447e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1448e439f0f8SKowalski, Kamil } 1449e439f0f8SKowalski, Kamil res.end(); 1450e439f0f8SKowalski, Kamil }); 1451e439f0f8SKowalski, Kamil } 1452e439f0f8SKowalski, Kamil 1453e439f0f8SKowalski, Kamil void doPatch(crow::response &res, const crow::request &req, 1454e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1455e439f0f8SKowalski, Kamil if (params.size() != 2) { 1456e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1457e439f0f8SKowalski, Kamil res.end(); 1458e439f0f8SKowalski, Kamil return; 1459e439f0f8SKowalski, Kamil } 1460e439f0f8SKowalski, Kamil 1461e439f0f8SKowalski, Kamil const std::string &parent_iface_id = params[0]; 1462e439f0f8SKowalski, Kamil const std::string &iface_id = params[1]; 1463e439f0f8SKowalski, Kamil 1464e439f0f8SKowalski, Kamil if (!verifyNames(res, parent_iface_id, iface_id)) { 1465e439f0f8SKowalski, Kamil return; 1466e439f0f8SKowalski, Kamil } 1467e439f0f8SKowalski, Kamil 1468e439f0f8SKowalski, Kamil nlohmann::json patchReq; 1469e439f0f8SKowalski, Kamil 1470e439f0f8SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1471e439f0f8SKowalski, Kamil return; 1472e439f0f8SKowalski, Kamil } 1473e439f0f8SKowalski, Kamil 1474e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1475e439f0f8SKowalski, Kamil // preparation 1476e439f0f8SKowalski, Kamil ethernet_provider.getEthernetIfaceData( 1477e439f0f8SKowalski, Kamil iface_id, 1478e439f0f8SKowalski, Kamil [&, parent_iface_id, iface_id, patchReq = std::move(patchReq) ]( 1479e439f0f8SKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1480e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1481e439f0f8SKowalski, Kamil if (!success) { 1482e439f0f8SKowalski, Kamil // ... otherwise return error 1483e439f0f8SKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1484e439f0f8SKowalski, Kamil // and 1485e439f0f8SKowalski, Kamil // other errors 1486e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1487e439f0f8SKowalski, Kamil res.end(); 1488e439f0f8SKowalski, Kamil 1489e439f0f8SKowalski, Kamil return; 1490e439f0f8SKowalski, Kamil } 1491e439f0f8SKowalski, Kamil 1492e439f0f8SKowalski, Kamil res.json_value = parseInterfaceData(parent_iface_id, iface_id, 1493e439f0f8SKowalski, Kamil eth_data, ipv4_data); 1494e439f0f8SKowalski, Kamil 1495e439f0f8SKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1496e439f0f8SKowalski, Kamil std::make_shared<AsyncResp>(res); 1497e439f0f8SKowalski, Kamil 1498e439f0f8SKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1499e439f0f8SKowalski, Kamil ++propertyIt) { 1500e439f0f8SKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 1501e439f0f8SKowalski, Kamil propertyIt.key() != "VLANId") { 1502e439f0f8SKowalski, Kamil auto fieldInJsonIt = res.json_value.find(propertyIt.key()); 1503e439f0f8SKowalski, Kamil 1504e439f0f8SKowalski, Kamil if (fieldInJsonIt == res.json_value.end()) { 1505e439f0f8SKowalski, Kamil // Field not in scope of defined fields 1506e439f0f8SKowalski, Kamil messages::addMessageToJsonRoot( 1507e439f0f8SKowalski, Kamil res.json_value, 1508e439f0f8SKowalski, Kamil messages::propertyUnknown(propertyIt.key())); 1509e439f0f8SKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1510e439f0f8SKowalski, Kamil // User attempted to modify non-writable field 1511e439f0f8SKowalski, Kamil messages::addMessageToJsonRoot( 1512e439f0f8SKowalski, Kamil res.json_value, 1513e439f0f8SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1514e439f0f8SKowalski, Kamil } 1515e439f0f8SKowalski, Kamil } 1516e439f0f8SKowalski, Kamil } 1517e439f0f8SKowalski, Kamil 1518e439f0f8SKowalski, Kamil EthernetInterface::handleVlanPatch(iface_id, patchReq, eth_data, "/", 1519e439f0f8SKowalski, Kamil asyncResp); 1520e439f0f8SKowalski, Kamil }); 1521e439f0f8SKowalski, Kamil } 1522e439f0f8SKowalski, Kamil 1523e439f0f8SKowalski, Kamil void doDelete(crow::response &res, const crow::request &req, 1524e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1525e439f0f8SKowalski, Kamil if (params.size() != 2) { 1526e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1527e439f0f8SKowalski, Kamil res.end(); 1528e439f0f8SKowalski, Kamil return; 1529e439f0f8SKowalski, Kamil } 1530e439f0f8SKowalski, Kamil 1531e439f0f8SKowalski, Kamil const std::string &parent_iface_id = params[0]; 1532e439f0f8SKowalski, Kamil const std::string &iface_id = params[1]; 1533e439f0f8SKowalski, Kamil 1534e439f0f8SKowalski, Kamil if (!verifyNames(res, parent_iface_id, iface_id)) { 1535e439f0f8SKowalski, Kamil return; 1536e439f0f8SKowalski, Kamil } 1537e439f0f8SKowalski, Kamil 1538e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1539e439f0f8SKowalski, Kamil // preparation 1540e439f0f8SKowalski, Kamil ethernet_provider.getEthernetIfaceData( 1541e439f0f8SKowalski, Kamil iface_id, 1542e439f0f8SKowalski, Kamil [&, parent_iface_id, iface_id]( 1543e439f0f8SKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1544e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1545e439f0f8SKowalski, Kamil if (success && eth_data.vlan_id != nullptr) { 1546e439f0f8SKowalski, Kamil res.json_value = parseInterfaceData(parent_iface_id, iface_id, 1547e439f0f8SKowalski, Kamil eth_data, ipv4_data); 1548e439f0f8SKowalski, Kamil 1549e439f0f8SKowalski, Kamil // Disable VLAN 1550e439f0f8SKowalski, Kamil OnDemandEthernetProvider::disableVlan( 1551e439f0f8SKowalski, Kamil iface_id, [&](const boost::system::error_code ec) { 1552e439f0f8SKowalski, Kamil if (ec) { 1553e439f0f8SKowalski, Kamil res.json_value = nlohmann::json::object(); 1554e439f0f8SKowalski, Kamil messages::addMessageToErrorJson(res.json_value, 1555e439f0f8SKowalski, Kamil messages::internalError()); 1556e439f0f8SKowalski, Kamil res.result( 1557e439f0f8SKowalski, Kamil boost::beast::http::status::internal_server_error); 1558e439f0f8SKowalski, Kamil } 1559e439f0f8SKowalski, Kamil res.end(); 1560e439f0f8SKowalski, Kamil }); 1561e439f0f8SKowalski, Kamil } else { 1562e439f0f8SKowalski, Kamil // ... otherwise return error 1563e439f0f8SKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1564e439f0f8SKowalski, Kamil // and 1565e439f0f8SKowalski, Kamil // other errors 1566e439f0f8SKowalski, Kamil 1567e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1568e439f0f8SKowalski, Kamil res.end(); 1569e439f0f8SKowalski, Kamil } 1570e439f0f8SKowalski, Kamil }); 1571e439f0f8SKowalski, Kamil } 1572e439f0f8SKowalski, Kamil 1573e439f0f8SKowalski, Kamil /** 1574e439f0f8SKowalski, Kamil * This allows VlanNetworkInterfaceCollection to reuse this class' doGet 1575e439f0f8SKowalski, Kamil * method, to maintain consistency of returned data, as Collection's doPost 1576e439f0f8SKowalski, Kamil * should return data for created member which should match member's doGet 1577e439f0f8SKowalski, Kamil * result in 100%. 1578e439f0f8SKowalski, Kamil */ 1579e439f0f8SKowalski, Kamil friend VlanNetworkInterfaceCollection; 1580e439f0f8SKowalski, Kamil 1581e439f0f8SKowalski, Kamil // Ethernet Provider object 1582e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 1583e439f0f8SKowalski, Kamil OnDemandEthernetProvider ethernet_provider; 1584e439f0f8SKowalski, Kamil }; 1585e439f0f8SKowalski, Kamil 1586e439f0f8SKowalski, Kamil /** 1587e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1588e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1589e439f0f8SKowalski, Kamil */ 1590e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection : public Node { 1591e439f0f8SKowalski, Kamil public: 1592e439f0f8SKowalski, Kamil template <typename CrowApp> 1593e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1594e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1595e439f0f8SKowalski, Kamil // GetSubroutes method 1596e439f0f8SKowalski, Kamil VlanNetworkInterfaceCollection(CrowApp &app) 1597e439f0f8SKowalski, Kamil : Node(app, 1598e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/", 1599e439f0f8SKowalski, Kamil std::string()), 1600e439f0f8SKowalski, Kamil memberVlan(app) { 1601e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1602e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1603e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1604e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1605e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1606e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1607e439f0f8SKowalski, Kamil 1608e439f0f8SKowalski, Kamil entityPrivileges = { 1609e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1610e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1611e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1612e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1613e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1614e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1615e439f0f8SKowalski, Kamil } 1616e439f0f8SKowalski, Kamil 1617e439f0f8SKowalski, Kamil private: 1618e439f0f8SKowalski, Kamil /** 1619e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1620e439f0f8SKowalski, Kamil */ 1621e439f0f8SKowalski, Kamil void doGet(crow::response &res, const crow::request &req, 1622e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1623e439f0f8SKowalski, Kamil if (params.size() != 1) { 1624e439f0f8SKowalski, Kamil // This means there is a problem with the router 1625e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1626e439f0f8SKowalski, Kamil res.end(); 1627e439f0f8SKowalski, Kamil 1628e439f0f8SKowalski, Kamil return; 1629e439f0f8SKowalski, Kamil } 1630e439f0f8SKowalski, Kamil 1631e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1632e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 1633e439f0f8SKowalski, Kamil std::string manager_id = "openbmc"; 1634e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1635e439f0f8SKowalski, Kamil 1636e439f0f8SKowalski, Kamil // Get eth interface list, and call the below callback for JSON preparation 1637e439f0f8SKowalski, Kamil ethernet_provider.getEthernetIfaceList([ 1638e439f0f8SKowalski, Kamil &, manager_id{std::move(manager_id)}, 1639e439f0f8SKowalski, Kamil rootInterfaceName{std::move(rootInterfaceName)} 1640e439f0f8SKowalski, Kamil ](const bool &success, const std::vector<std::string> &iface_list) { 1641e439f0f8SKowalski, Kamil if (success) { 1642e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 1643e439f0f8SKowalski, Kamil nlohmann::json iface_array = nlohmann::json::array(); 1644e439f0f8SKowalski, Kamil 1645e439f0f8SKowalski, Kamil for (const std::string &iface_item : iface_list) { 1646e439f0f8SKowalski, Kamil if (iface_item == rootInterfaceName) { 1647e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1648e439f0f8SKowalski, Kamil } else if (boost::starts_with(iface_item, rootInterfaceName + "_")) { 1649e439f0f8SKowalski, Kamil iface_array.push_back( 1650e439f0f8SKowalski, Kamil {{"@odata.id", "/redfish/v1/Managers/" + manager_id + 1651e439f0f8SKowalski, Kamil "/EthernetInterfaces/" + rootInterfaceName + 1652e439f0f8SKowalski, Kamil "/VLANs/" + iface_item}}); 1653e439f0f8SKowalski, Kamil } 1654e439f0f8SKowalski, Kamil } 1655e439f0f8SKowalski, Kamil 1656e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 1657e439f0f8SKowalski, Kamil Node::json["Members"] = iface_array; 1658e439f0f8SKowalski, Kamil Node::json["Members@odata.count"] = iface_array.size(); 1659e439f0f8SKowalski, Kamil Node::json["@odata.id"] = "/redfish/v1/Managers/" + manager_id + 1660e439f0f8SKowalski, Kamil "/EthernetInterfaces/" + rootInterfaceName + 1661e439f0f8SKowalski, Kamil "/VLANs"; 1662e439f0f8SKowalski, Kamil res.json_value = Node::json; 1663e439f0f8SKowalski, Kamil } else { 1664e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1665e439f0f8SKowalski, Kamil res.json_value, messages::resourceNotFound("EthernetInterface", 1666e439f0f8SKowalski, Kamil rootInterfaceName)); 1667e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1668e439f0f8SKowalski, Kamil res.end(); 1669e439f0f8SKowalski, Kamil } 1670e439f0f8SKowalski, Kamil } else { 1671e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1672e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1673e439f0f8SKowalski, Kamil } 1674e439f0f8SKowalski, Kamil res.end(); 1675e439f0f8SKowalski, Kamil }); 1676e439f0f8SKowalski, Kamil } 1677e439f0f8SKowalski, Kamil 1678e439f0f8SKowalski, Kamil void doPost(crow::response &res, const crow::request &req, 1679e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1680e439f0f8SKowalski, Kamil if (params.size() != 1) { 1681e439f0f8SKowalski, Kamil // This means there is a problem with the router 1682e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1683e439f0f8SKowalski, Kamil res.end(); 1684e439f0f8SKowalski, Kamil return; 1685e439f0f8SKowalski, Kamil } 1686e439f0f8SKowalski, Kamil 1687e439f0f8SKowalski, Kamil nlohmann::json postReq; 1688e439f0f8SKowalski, Kamil 1689e439f0f8SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, postReq)) { 1690e439f0f8SKowalski, Kamil return; 1691e439f0f8SKowalski, Kamil } 1692e439f0f8SKowalski, Kamil 1693e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1694e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 1695e439f0f8SKowalski, Kamil std::string manager_id = "openbmc"; 1696e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1697e439f0f8SKowalski, Kamil uint64_t vlanId; 1698e439f0f8SKowalski, Kamil bool errorDetected; 1699e439f0f8SKowalski, Kamil 1700e439f0f8SKowalski, Kamil if (json_util::getUnsigned( 1701e439f0f8SKowalski, Kamil "VLANId", postReq, vlanId, 1702e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::MISSING) | 1703e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 1704e439f0f8SKowalski, Kamil res.json_value, "/VLANId") != json_util::Result::SUCCESS) { 1705e439f0f8SKowalski, Kamil res.end(); 1706e439f0f8SKowalski, Kamil return; 1707e439f0f8SKowalski, Kamil } 1708e439f0f8SKowalski, Kamil 1709e439f0f8SKowalski, Kamil // Get eth interface list, and call the below callback for JSON preparation 1710e439f0f8SKowalski, Kamil ethernet_provider.getEthernetIfaceList([ 1711e439f0f8SKowalski, Kamil &, manager_id{std::move(manager_id)}, 1712e439f0f8SKowalski, Kamil rootInterfaceName{std::move(rootInterfaceName)} 1713e439f0f8SKowalski, Kamil ](const bool &success, const std::vector<std::string> &iface_list) { 1714e439f0f8SKowalski, Kamil if (success) { 1715e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 1716e439f0f8SKowalski, Kamil 1717e439f0f8SKowalski, Kamil for (const std::string &iface_item : iface_list) { 1718e439f0f8SKowalski, Kamil if (iface_item == rootInterfaceName) { 1719e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1720e439f0f8SKowalski, Kamil break; 1721e439f0f8SKowalski, Kamil } 1722e439f0f8SKowalski, Kamil } 1723e439f0f8SKowalski, Kamil 1724e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 1725e439f0f8SKowalski, Kamil ethernet_provider.createVlan( 1726e439f0f8SKowalski, Kamil rootInterfaceName, vlanId, 1727e439f0f8SKowalski, Kamil [&, vlanId, rootInterfaceName, 1728e439f0f8SKowalski, Kamil req{std::move(req)} ](const boost::system::error_code ec) { 1729e439f0f8SKowalski, Kamil if (ec) { 1730e439f0f8SKowalski, Kamil messages::addMessageToErrorJson(res.json_value, 1731e439f0f8SKowalski, Kamil messages::internalError()); 1732e439f0f8SKowalski, Kamil res.end(); 1733e439f0f8SKowalski, Kamil } else { 1734e439f0f8SKowalski, Kamil memberVlan.doGet( 1735e439f0f8SKowalski, Kamil res, req, 1736e439f0f8SKowalski, Kamil {rootInterfaceName, 1737e439f0f8SKowalski, Kamil rootInterfaceName + "_" + std::to_string(vlanId)}); 1738e439f0f8SKowalski, Kamil } 1739e439f0f8SKowalski, Kamil }); 1740e439f0f8SKowalski, Kamil } else { 1741e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1742e439f0f8SKowalski, Kamil res.json_value, messages::resourceNotFound("EthernetInterface", 1743e439f0f8SKowalski, Kamil rootInterfaceName)); 1744e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1745e439f0f8SKowalski, Kamil res.end(); 1746e439f0f8SKowalski, Kamil } 1747e439f0f8SKowalski, Kamil } else { 1748e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1749e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1750e439f0f8SKowalski, Kamil res.end(); 1751e439f0f8SKowalski, Kamil } 1752e439f0f8SKowalski, Kamil }); 1753e439f0f8SKowalski, Kamil } 1754e439f0f8SKowalski, Kamil 1755e439f0f8SKowalski, Kamil // Ethernet Provider object 1756e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 1757e439f0f8SKowalski, Kamil OnDemandEthernetProvider ethernet_provider; 1758e439f0f8SKowalski, Kamil VlanNetworkInterface memberVlan; 1759e439f0f8SKowalski, Kamil }; 1760e439f0f8SKowalski, Kamil 17619391bb9cSRapkiewicz, Pawel } // namespace redfish 1762