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; 7255c7b7a2SEd Tanous const bool *autoNeg; 739391bb9cSRapkiewicz, Pawel const std::string *hostname; 7455c7b7a2SEd Tanous const std::string *defaultGateway; 7555c7b7a2SEd Tanous const std::string *macAddress; 7655c7b7a2SEd Tanous const unsigned int *vlanId; 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 9155c7b7a2SEd Tanous const size_t maxIpV4AddressesPerInterface = 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) { 9855c7b7a2SEd Tanous const auto &dbusObj = dbus_data.find(objpath); 9955c7b7a2SEd Tanous if (dbusObj != dbus_data.end()) { 10055c7b7a2SEd Tanous const auto &iface = dbusObj->second.find(interface); 10155c7b7a2SEd Tanous if (iface != dbusObj->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) { 11355c7b7a2SEd Tanous const auto &dbusObj = sdbusplus::message::object_path{objpath}; 11455c7b7a2SEd Tanous return extractInterfaceProperties(dbusObj, 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()) { 12455c7b7a2SEd Tanous return mapbox::getPtr<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 13355c7b7a2SEd Tanous void extractEthernetInterfaceData(const std::string ðifaceId, 1349391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 1359391bb9cSRapkiewicz, Pawel EthernetInterfaceData ð_data) { 1369391bb9cSRapkiewicz, Pawel // Extract data that contains MAC Address 13755c7b7a2SEd Tanous const PropertiesMapType *macProperties = extractInterfaceProperties( 13855c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 1399391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.MACAddress", dbus_data); 1409391bb9cSRapkiewicz, Pawel 14155c7b7a2SEd Tanous if (macProperties != nullptr) { 14255c7b7a2SEd Tanous eth_data.macAddress = 14355c7b7a2SEd Tanous extractProperty<std::string>(*macProperties, "MACAddress"); 1449391bb9cSRapkiewicz, Pawel } 1459391bb9cSRapkiewicz, Pawel 14655c7b7a2SEd Tanous const PropertiesMapType *vlanProperties = extractInterfaceProperties( 14755c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 148c7070ac2SKowalski, Kamil "xyz.openbmc_project.Network.VLAN", dbus_data); 149c7070ac2SKowalski, Kamil 15055c7b7a2SEd Tanous if (vlanProperties != nullptr) { 15155c7b7a2SEd Tanous eth_data.vlanId = extractProperty<unsigned int>(*vlanProperties, "Id"); 152c7070ac2SKowalski, Kamil } 153c7070ac2SKowalski, Kamil 1549391bb9cSRapkiewicz, Pawel // Extract data that contains link information (auto negotiation and speed) 15555c7b7a2SEd Tanous const PropertiesMapType *ethProperties = extractInterfaceProperties( 15655c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 1579391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface", dbus_data); 1589391bb9cSRapkiewicz, Pawel 15955c7b7a2SEd Tanous if (ethProperties != nullptr) { 16055c7b7a2SEd Tanous eth_data.autoNeg = extractProperty<bool>(*ethProperties, "AutoNeg"); 16155c7b7a2SEd Tanous eth_data.speed = extractProperty<unsigned int>(*ethProperties, "Speed"); 1629391bb9cSRapkiewicz, Pawel } 1639391bb9cSRapkiewicz, Pawel 1649391bb9cSRapkiewicz, Pawel // Extract data that contains network config (HostName and DefaultGW) 16555c7b7a2SEd Tanous const PropertiesMapType *configProperties = extractInterfaceProperties( 1669391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/config", 1679391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.SystemConfiguration", dbus_data); 1689391bb9cSRapkiewicz, Pawel 16955c7b7a2SEd Tanous if (configProperties != nullptr) { 1709391bb9cSRapkiewicz, Pawel eth_data.hostname = 17155c7b7a2SEd Tanous extractProperty<std::string>(*configProperties, "HostName"); 17255c7b7a2SEd Tanous eth_data.defaultGateway = 17355c7b7a2SEd Tanous extractProperty<std::string>(*configProperties, "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 18955c7b7a2SEd Tanous void extractIPv4Data(const std::string ðifaceId, 1909391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 1919391bb9cSRapkiewicz, Pawel std::vector<IPv4AddressData> &ipv4_config) { 192179db1d7SKowalski, Kamil const std::string pathStart = 19355c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId + "/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 199a434f2bdSEd Tanous if (boost::starts_with(static_cast<const std::string &>(objpath.first), 200a434f2bdSEd Tanous pathStart)) { 2019391bb9cSRapkiewicz, Pawel // and get approrpiate interface 2029391bb9cSRapkiewicz, Pawel const auto &interface = 2039391bb9cSRapkiewicz, Pawel objpath.second.find("xyz.openbmc_project.Network.IP"); 2049391bb9cSRapkiewicz, Pawel if (interface != objpath.second.end()) { 2059391bb9cSRapkiewicz, Pawel // Make a properties 'shortcut', to make everything more readable 2069391bb9cSRapkiewicz, Pawel const PropertiesMapType &properties = interface->second; 2079391bb9cSRapkiewicz, Pawel // Instance IPv4AddressData structure, and set as appropriate 20855c7b7a2SEd Tanous IPv4AddressData ipv4Address; 209179db1d7SKowalski, Kamil 21055c7b7a2SEd Tanous ipv4Address.id = static_cast<const std::string &>(objpath.first) 211179db1d7SKowalski, Kamil .substr(pathStart.size()); 212179db1d7SKowalski, Kamil 2139391bb9cSRapkiewicz, Pawel // IPv4 address 21455c7b7a2SEd Tanous ipv4Address.address = 2159391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Address"); 2169391bb9cSRapkiewicz, Pawel // IPv4 gateway 21755c7b7a2SEd Tanous ipv4Address.gateway = 2189391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Gateway"); 2199391bb9cSRapkiewicz, Pawel 2209391bb9cSRapkiewicz, Pawel // Origin is kind of DBus object so fetch pointer... 2219391bb9cSRapkiewicz, Pawel const std::string *origin = 2229391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Origin"); 2239391bb9cSRapkiewicz, Pawel if (origin != nullptr) { 22455c7b7a2SEd Tanous ipv4Address.origin = 225179db1d7SKowalski, Kamil translateAddressOriginBetweenDBusAndRedfish(origin, true, true); 2269391bb9cSRapkiewicz, Pawel } 2279391bb9cSRapkiewicz, Pawel 2289391bb9cSRapkiewicz, Pawel // Netmask is presented as PrefixLength 2299391bb9cSRapkiewicz, Pawel const auto *mask = 2309391bb9cSRapkiewicz, Pawel extractProperty<uint8_t>(properties, "PrefixLength"); 2319391bb9cSRapkiewicz, Pawel if (mask != nullptr) { 2329391bb9cSRapkiewicz, Pawel // convert it to the string 23355c7b7a2SEd Tanous ipv4Address.netmask = getNetmask(*mask); 2349391bb9cSRapkiewicz, Pawel } 2359391bb9cSRapkiewicz, Pawel 2369391bb9cSRapkiewicz, Pawel // Attach IPv4 only if address is present 23755c7b7a2SEd Tanous if (ipv4Address.address != nullptr) { 238a434f2bdSEd Tanous // Check if given address is local, or global 23955c7b7a2SEd Tanous if (boost::starts_with(*ipv4Address.address, "169.254")) { 24055c7b7a2SEd Tanous ipv4Address.global = false; 2419391bb9cSRapkiewicz, Pawel } else { 24255c7b7a2SEd Tanous ipv4Address.global = true; 2439391bb9cSRapkiewicz, Pawel } 24455c7b7a2SEd Tanous ipv4_config.emplace_back(std::move(ipv4Address)); 2459391bb9cSRapkiewicz, Pawel } 2469391bb9cSRapkiewicz, Pawel } 2479391bb9cSRapkiewicz, Pawel } 2489391bb9cSRapkiewicz, Pawel } 249179db1d7SKowalski, Kamil 250179db1d7SKowalski, Kamil /** 251179db1d7SKowalski, Kamil * We have to sort this vector and ensure that order of IPv4 addresses 252179db1d7SKowalski, Kamil * is consistent between GETs to allow modification and deletion in PATCHes 253179db1d7SKowalski, Kamil */ 254179db1d7SKowalski, Kamil std::sort(ipv4_config.begin(), ipv4_config.end()); 2559391bb9cSRapkiewicz, Pawel } 2569391bb9cSRapkiewicz, Pawel 257179db1d7SKowalski, Kamil static const constexpr int ipV4AddressSectionsCount = 4; 258179db1d7SKowalski, Kamil 2599391bb9cSRapkiewicz, Pawel public: 2609391bb9cSRapkiewicz, Pawel /** 261588c3f0dSKowalski, Kamil * @brief Creates VLAN for given interface with given Id through D-Bus 262588c3f0dSKowalski, Kamil * 263588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of interface for which VLAN will be created 264588c3f0dSKowalski, Kamil * @param[in] inputVlanId ID of the new VLAN 265588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 266588c3f0dSKowalski, Kamil * 267588c3f0dSKowalski, Kamil * @return None. 268588c3f0dSKowalski, Kamil */ 269588c3f0dSKowalski, Kamil template <typename CallbackFunc> 270588c3f0dSKowalski, Kamil void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId, 271588c3f0dSKowalski, Kamil CallbackFunc &&callback) { 27255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 273588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 274588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId, 275588c3f0dSKowalski, Kamil static_cast<uint32_t>(inputVlanId)); 276588c3f0dSKowalski, Kamil }; 277588c3f0dSKowalski, Kamil 278588c3f0dSKowalski, Kamil /** 279588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 280588c3f0dSKowalski, Kamil * 281588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 282588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 283588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 284588c3f0dSKowalski, Kamil * 285588c3f0dSKowalski, Kamil * @return None. 286588c3f0dSKowalski, Kamil */ 287588c3f0dSKowalski, Kamil template <typename CallbackFunc> 288e439f0f8SKowalski, Kamil static void changeVlanId(const std::string &ifaceId, 289e439f0f8SKowalski, Kamil const uint32_t &inputVlanId, 290588c3f0dSKowalski, Kamil CallbackFunc &&callback) { 29155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 292588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 293588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 294588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 295588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 296588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 297588c3f0dSKowalski, Kamil }; 298588c3f0dSKowalski, Kamil 299588c3f0dSKowalski, Kamil /** 300179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 301179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 302179db1d7SKowalski, Kamil * bit count for Subnet Mask. 303179db1d7SKowalski, Kamil * 304179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 305179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 306179db1d7SKowalski, Kamil * 307179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 308179db1d7SKowalski, Kamil */ 309179db1d7SKowalski, Kamil bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 310179db1d7SKowalski, Kamil uint8_t *bits = nullptr) { 311179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 312179db1d7SKowalski, Kamil 313179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 314179db1d7SKowalski, Kamil 315179db1d7SKowalski, Kamil if (bytesInMask.size() != ipV4AddressSectionsCount) { 316179db1d7SKowalski, Kamil return false; 317179db1d7SKowalski, Kamil } 318179db1d7SKowalski, Kamil 319179db1d7SKowalski, Kamil if (bits != nullptr) { 320179db1d7SKowalski, Kamil *bits = 0; 321179db1d7SKowalski, Kamil } 322179db1d7SKowalski, Kamil 323179db1d7SKowalski, Kamil char *endPtr; 324179db1d7SKowalski, Kamil long previousValue = 255; 325179db1d7SKowalski, Kamil bool firstZeroInByteHit; 3261db9ca37SKowalski, Kamil for (const std::string &byte : bytesInMask) { 3271db9ca37SKowalski, Kamil if (byte.empty()) { 3281db9ca37SKowalski, Kamil return false; 3291db9ca37SKowalski, Kamil } 3301db9ca37SKowalski, Kamil 331179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 3321db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 333179db1d7SKowalski, Kamil 334179db1d7SKowalski, Kamil // endPtr should point to the end of the string, otherwise given string 335179db1d7SKowalski, Kamil // is not 100% number 336179db1d7SKowalski, Kamil if (*endPtr != '\0') { 337179db1d7SKowalski, Kamil return false; 338179db1d7SKowalski, Kamil } 339179db1d7SKowalski, Kamil 340179db1d7SKowalski, Kamil // Value should be contained in byte 341179db1d7SKowalski, Kamil if (value < 0 || value > 255) { 342179db1d7SKowalski, Kamil return false; 343179db1d7SKowalski, Kamil } 344179db1d7SKowalski, Kamil 345179db1d7SKowalski, Kamil if (bits != nullptr) { 346179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 347179db1d7SKowalski, Kamil if (previousValue != 255 && value != 0) { 348179db1d7SKowalski, Kamil return false; 349179db1d7SKowalski, Kamil } 350179db1d7SKowalski, Kamil 351179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 352179db1d7SKowalski, Kamil firstZeroInByteHit = false; 353179db1d7SKowalski, Kamil 354179db1d7SKowalski, Kamil // Count bits 355179db1d7SKowalski, Kamil for (int bitIdx = 7; bitIdx >= 0; bitIdx--) { 356179db1d7SKowalski, Kamil if (value & (1 << bitIdx)) { 357179db1d7SKowalski, Kamil if (firstZeroInByteHit) { 358179db1d7SKowalski, Kamil // Continuity not preserved 359179db1d7SKowalski, Kamil return false; 360179db1d7SKowalski, Kamil } else { 361179db1d7SKowalski, Kamil (*bits)++; 362179db1d7SKowalski, Kamil } 363179db1d7SKowalski, Kamil } else { 364179db1d7SKowalski, Kamil firstZeroInByteHit = true; 365179db1d7SKowalski, Kamil } 366179db1d7SKowalski, Kamil } 367179db1d7SKowalski, Kamil } 368179db1d7SKowalski, Kamil 369179db1d7SKowalski, Kamil previousValue = value; 370179db1d7SKowalski, Kamil } 371179db1d7SKowalski, Kamil 372179db1d7SKowalski, Kamil return true; 373179db1d7SKowalski, Kamil } 374179db1d7SKowalski, Kamil 375179db1d7SKowalski, Kamil /** 376179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 377179db1d7SKowalski, Kamil * 378179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 37955c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 380179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 381179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 382179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 383179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 384179db1d7SKowalski, Kamil * 385179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 386179db1d7SKowalski, Kamil * otherwise 387179db1d7SKowalski, Kamil */ 388179db1d7SKowalski, Kamil void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx, 389179db1d7SKowalski, Kamil const std::string &ipHash, 390179db1d7SKowalski, Kamil const std::string &name, 391179db1d7SKowalski, Kamil const std::string &newValue, 392179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 393*8ceb2ecaSEd Tanous auto callback = [ 394*8ceb2ecaSEd Tanous asyncResp, ipIdx{std::move(ipIdx)}, name{std::move(name)}, 395*8ceb2ecaSEd Tanous newValue{std::move(newValue)} 396*8ceb2ecaSEd Tanous ](const boost::system::error_code ec) { 397179db1d7SKowalski, Kamil if (ec) { 398179db1d7SKowalski, Kamil messages::addMessageToJson( 39955c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 400179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 401179db1d7SKowalski, Kamil } else { 40255c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 403179db1d7SKowalski, Kamil } 404179db1d7SKowalski, Kamil }; 405179db1d7SKowalski, Kamil 40655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 407179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 408179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 409179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 410179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 411179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 412179db1d7SKowalski, Kamil }; 413179db1d7SKowalski, Kamil 414179db1d7SKowalski, Kamil /** 415179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 416179db1d7SKowalski, Kamil * 417179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 41855c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 419179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 420179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 421179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 422179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 423179db1d7SKowalski, Kamil * 424179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 425179db1d7SKowalski, Kamil * otherwise 426179db1d7SKowalski, Kamil */ 427179db1d7SKowalski, Kamil void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 428179db1d7SKowalski, Kamil const std::string &ipHash, const std::string &newValue, 429179db1d7SKowalski, Kamil const std::string &newValueDbus, 430179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 431179db1d7SKowalski, Kamil auto callback = 432179db1d7SKowalski, Kamil [ asyncResp, ipIdx{std::move(ipIdx)}, 433179db1d7SKowalski, Kamil newValue{std::move(newValue)} ](const boost::system::error_code ec) { 434179db1d7SKowalski, Kamil if (ec) { 435179db1d7SKowalski, Kamil messages::addMessageToJson( 43655c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 437179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin"); 438179db1d7SKowalski, Kamil } else { 43955c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 440179db1d7SKowalski, Kamil newValue; 441179db1d7SKowalski, Kamil } 442179db1d7SKowalski, Kamil }; 443179db1d7SKowalski, Kamil 44455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 445179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 446179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 447179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 448179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 449179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 450179db1d7SKowalski, Kamil }; 451179db1d7SKowalski, Kamil 452179db1d7SKowalski, Kamil /** 453179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 454179db1d7SKowalski, Kamil * 455179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 45655c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 457179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 458179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 459179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 460179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 461179db1d7SKowalski, Kamil * 462179db1d7SKowalski, Kamil * @return None 463179db1d7SKowalski, Kamil */ 464179db1d7SKowalski, Kamil void changeIPv4SubnetMaskProperty( 465179db1d7SKowalski, Kamil const std::string &ifaceId, int ipIdx, const std::string &ipHash, 466179db1d7SKowalski, Kamil const std::string &newValueStr, uint8_t &newValue, 467179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 468*8ceb2ecaSEd Tanous auto callback = [ 469*8ceb2ecaSEd Tanous asyncResp, ipIdx{std::move(ipIdx)}, newValueStr{std::move(newValueStr)} 470*8ceb2ecaSEd Tanous ](const boost::system::error_code ec) { 471179db1d7SKowalski, Kamil if (ec) { 472179db1d7SKowalski, Kamil messages::addMessageToJson( 47355c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 474179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 475179db1d7SKowalski, Kamil } else { 47655c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 477179db1d7SKowalski, Kamil newValueStr; 478179db1d7SKowalski, Kamil } 479179db1d7SKowalski, Kamil }; 480179db1d7SKowalski, Kamil 48155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 482179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 483179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 484179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 485179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 486179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 487179db1d7SKowalski, Kamil }; 488179db1d7SKowalski, Kamil 489179db1d7SKowalski, Kamil /** 490588c3f0dSKowalski, Kamil * @brief Disables VLAN with given ifaceId 491588c3f0dSKowalski, Kamil * 492588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be disabled 493588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 494588c3f0dSKowalski, Kamil * 495588c3f0dSKowalski, Kamil * @return None. 496588c3f0dSKowalski, Kamil */ 497588c3f0dSKowalski, Kamil template <typename CallbackFunc> 498e439f0f8SKowalski, Kamil static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) { 49955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 500588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 501588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 502588c3f0dSKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 503588c3f0dSKowalski, Kamil }; 504588c3f0dSKowalski, Kamil 505588c3f0dSKowalski, Kamil /** 506588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 507588c3f0dSKowalski, Kamil * 508588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 509588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 510588c3f0dSKowalski, Kamil * 511588c3f0dSKowalski, Kamil * @return None. 512588c3f0dSKowalski, Kamil */ 513588c3f0dSKowalski, Kamil template <typename CallbackFunc> 514588c3f0dSKowalski, Kamil void setHostName(const std::string &newHostname, CallbackFunc &&callback) { 51555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 516588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 517588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 518588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 519588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 520588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 521588c3f0dSKowalski, Kamil }; 522588c3f0dSKowalski, Kamil 523588c3f0dSKowalski, Kamil /** 524179db1d7SKowalski, Kamil * @brief Deletes given IPv4 525179db1d7SKowalski, Kamil * 526179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 52755c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 528179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 529179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 530179db1d7SKowalski, Kamil * 531179db1d7SKowalski, Kamil * @return None 532179db1d7SKowalski, Kamil */ 533179db1d7SKowalski, Kamil void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 534179db1d7SKowalski, Kamil unsigned int ipIdx, 535179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 53655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 537*8ceb2ecaSEd Tanous [ ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} ]( 538*8ceb2ecaSEd Tanous const boost::system::error_code ec) { 539179db1d7SKowalski, Kamil if (ec) { 540179db1d7SKowalski, Kamil messages::addMessageToJson( 54155c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 542179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 543179db1d7SKowalski, Kamil } else { 54455c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 545179db1d7SKowalski, Kamil } 546179db1d7SKowalski, Kamil }, 547179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 548179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 549179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 550179db1d7SKowalski, Kamil } 551179db1d7SKowalski, Kamil 552179db1d7SKowalski, Kamil /** 553179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 554179db1d7SKowalski, Kamil * 555179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 55655c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 557179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 558179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 559179db1d7SKowalski, Kamil * 560179db1d7SKowalski, Kamil * @return None 561179db1d7SKowalski, Kamil */ 562179db1d7SKowalski, Kamil void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 563179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 564179db1d7SKowalski, Kamil const std::string &address, 565179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 566*8ceb2ecaSEd Tanous auto createIpHandler = [ 567*8ceb2ecaSEd Tanous ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} 568*8ceb2ecaSEd Tanous ](const boost::system::error_code ec) { 569179db1d7SKowalski, Kamil if (ec) { 570179db1d7SKowalski, Kamil messages::addMessageToJson( 57155c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 572179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 573179db1d7SKowalski, Kamil } 574179db1d7SKowalski, Kamil }; 575179db1d7SKowalski, Kamil 57655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 577179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 578179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 579179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 580179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 581179db1d7SKowalski, Kamil gateway); 582179db1d7SKowalski, Kamil } 583179db1d7SKowalski, Kamil 584179db1d7SKowalski, Kamil /** 585179db1d7SKowalski, Kamil * @brief Translates Address Origin value from D-Bus to Redfish format and 586179db1d7SKowalski, Kamil * vice-versa 587179db1d7SKowalski, Kamil * 588179db1d7SKowalski, Kamil * @param[in] inputOrigin Input value that should be translated 589179db1d7SKowalski, Kamil * @param[in] isIPv4 True for IPv4 origins, False for IPv6 590179db1d7SKowalski, Kamil * @param[in] isFromDBus True for DBus->Redfish conversion, false for reverse 591179db1d7SKowalski, Kamil * 592179db1d7SKowalski, Kamil * @return Empty string in case of failure, translated value otherwise 593179db1d7SKowalski, Kamil */ 594179db1d7SKowalski, Kamil std::string translateAddressOriginBetweenDBusAndRedfish( 595179db1d7SKowalski, Kamil const std::string *inputOrigin, bool isIPv4, bool isFromDBus) { 596179db1d7SKowalski, Kamil // Invalid pointer 597179db1d7SKowalski, Kamil if (inputOrigin == nullptr) { 598179db1d7SKowalski, Kamil return ""; 599179db1d7SKowalski, Kamil } 600179db1d7SKowalski, Kamil 601179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv4OnlyIdx = 1; 602179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv6OnlyIdx = 3; 603179db1d7SKowalski, Kamil 604179db1d7SKowalski, Kamil std::array<std::pair<const char *, const char *>, 6> translationTable{ 605179db1d7SKowalski, Kamil {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"}, 606179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"}, 607179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 608179db1d7SKowalski, Kamil "IPv4LinkLocal"}, 609179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"}, 610179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 611179db1d7SKowalski, Kamil "LinkLocal"}, 612179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}}; 613179db1d7SKowalski, Kamil 614179db1d7SKowalski, Kamil for (unsigned int i = 0; i < translationTable.size(); i++) { 615179db1d7SKowalski, Kamil // Skip unrelated 616179db1d7SKowalski, Kamil if (isIPv4 && i >= firstIPv6OnlyIdx) break; 617179db1d7SKowalski, Kamil if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) continue; 618179db1d7SKowalski, Kamil 619179db1d7SKowalski, Kamil // When translating D-Bus to Redfish compare input to first element 620179db1d7SKowalski, Kamil if (isFromDBus && translationTable[i].first == *inputOrigin) 621179db1d7SKowalski, Kamil return translationTable[i].second; 622179db1d7SKowalski, Kamil 623179db1d7SKowalski, Kamil // When translating Redfish to D-Bus compare input to second element 624179db1d7SKowalski, Kamil if (!isFromDBus && translationTable[i].second == *inputOrigin) 625179db1d7SKowalski, Kamil return translationTable[i].first; 626179db1d7SKowalski, Kamil } 627179db1d7SKowalski, Kamil 628179db1d7SKowalski, Kamil // If we are still here, that means that value has not been found 629179db1d7SKowalski, Kamil return ""; 630179db1d7SKowalski, Kamil } 631179db1d7SKowalski, Kamil 632179db1d7SKowalski, Kamil /** 633179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 634179db1d7SKowalski, Kamil * Object 635179db1d7SKowalski, Kamil * from EntityManager Network Manager 63655c7b7a2SEd Tanous * @param ethifaceId a eth interface id to query on DBus 637179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 638179db1d7SKowalski, Kamil * into JSON 639179db1d7SKowalski, Kamil */ 640179db1d7SKowalski, Kamil template <typename CallbackFunc> 64155c7b7a2SEd Tanous void getEthernetIfaceData(const std::string ðifaceId, 642179db1d7SKowalski, Kamil CallbackFunc &&callback) { 64355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 644*8ceb2ecaSEd Tanous [ 645*8ceb2ecaSEd Tanous this, ethifaceId{std::move(ethifaceId)}, callback{std::move(callback)} 646*8ceb2ecaSEd Tanous ](const boost::system::error_code error_code, 647179db1d7SKowalski, Kamil const GetManagedObjectsType &resp) { 648*8ceb2ecaSEd Tanous 64955c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 65055c7b7a2SEd Tanous std::vector<IPv4AddressData> ipv4Data; 65155c7b7a2SEd Tanous ipv4Data.reserve(maxIpV4AddressesPerInterface); 652179db1d7SKowalski, Kamil 653179db1d7SKowalski, Kamil if (error_code) { 654179db1d7SKowalski, Kamil // Something wrong on DBus, the error_code is not important at 655179db1d7SKowalski, Kamil // this moment, just return success=false, and empty output. Since 656179db1d7SKowalski, Kamil // size of vector may vary depending on information from Network 657179db1d7SKowalski, Kamil // Manager, and empty output could not be treated same way as 658179db1d7SKowalski, Kamil // error. 65955c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 660179db1d7SKowalski, Kamil return; 661179db1d7SKowalski, Kamil } 662179db1d7SKowalski, Kamil 663927a505aSKowalski, Kamil // Find interface 66455c7b7a2SEd Tanous if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) == 665927a505aSKowalski, Kamil resp.end()) { 666927a505aSKowalski, Kamil // Interface has not been found 66755c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 668927a505aSKowalski, Kamil return; 669927a505aSKowalski, Kamil } 670927a505aSKowalski, Kamil 67155c7b7a2SEd Tanous extractEthernetInterfaceData(ethifaceId, resp, ethData); 67255c7b7a2SEd Tanous extractIPv4Data(ethifaceId, resp, ipv4Data); 673179db1d7SKowalski, Kamil 674179db1d7SKowalski, Kamil // Fix global GW 67555c7b7a2SEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) { 676179db1d7SKowalski, Kamil if ((ipv4.global) && 677179db1d7SKowalski, Kamil ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) { 67855c7b7a2SEd Tanous ipv4.gateway = ethData.defaultGateway; 679179db1d7SKowalski, Kamil } 680179db1d7SKowalski, Kamil } 681179db1d7SKowalski, Kamil 682a434f2bdSEd Tanous // Finally make a callback with useful data 68355c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 684179db1d7SKowalski, Kamil }, 685179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 686179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 687179db1d7SKowalski, Kamil }; 688179db1d7SKowalski, Kamil 689179db1d7SKowalski, Kamil /** 6909391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6919391bb9cSRapkiewicz, Pawel * Manager 6929391bb9cSRapkiewicz, Pawel * @param callback a function that shall be called to convert Dbus output into 6939391bb9cSRapkiewicz, Pawel * JSON. 6949391bb9cSRapkiewicz, Pawel */ 6959391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 6969391bb9cSRapkiewicz, Pawel void getEthernetIfaceList(CallbackFunc &&callback) { 69755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6989391bb9cSRapkiewicz, Pawel [ this, callback{std::move(callback)} ]( 6999391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 700aa2e59c1SEd Tanous GetManagedObjectsType &resp) { 7019391bb9cSRapkiewicz, Pawel // Callback requires vector<string> to retrieve all available ethernet 7029391bb9cSRapkiewicz, Pawel // interfaces 70355c7b7a2SEd Tanous std::vector<std::string> ifaceList; 70455c7b7a2SEd Tanous ifaceList.reserve(resp.size()); 7059391bb9cSRapkiewicz, Pawel if (error_code) { 7069391bb9cSRapkiewicz, Pawel // Something wrong on DBus, the error_code is not important at this 7079391bb9cSRapkiewicz, Pawel // moment, just return success=false, and empty output. Since size 7089391bb9cSRapkiewicz, Pawel // of vector may vary depending on information from Network Manager, 7099391bb9cSRapkiewicz, Pawel // and empty output could not be treated same way as error. 71055c7b7a2SEd Tanous callback(false, ifaceList); 7119391bb9cSRapkiewicz, Pawel return; 7129391bb9cSRapkiewicz, Pawel } 7139391bb9cSRapkiewicz, Pawel 7149391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7159391bb9cSRapkiewicz, Pawel for (auto &objpath : resp) { 7169391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7179391bb9cSRapkiewicz, Pawel for (auto &interface : objpath.second) { 7189391bb9cSRapkiewicz, Pawel // If interface is xyz.openbmc_project.Network.EthernetInterface, 7199391bb9cSRapkiewicz, Pawel // this is what we're looking for. 7209391bb9cSRapkiewicz, Pawel if (interface.first == 7219391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface") { 722a434f2bdSEd Tanous // Cut out everything until last "/", ... 72355c7b7a2SEd Tanous const std::string &ifaceId = 724daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first); 72555c7b7a2SEd Tanous std::size_t lastPos = ifaceId.rfind("/"); 72655c7b7a2SEd Tanous if (lastPos != std::string::npos) { 7279391bb9cSRapkiewicz, Pawel // and put it into output vector. 72855c7b7a2SEd Tanous ifaceList.emplace_back(ifaceId.substr(lastPos + 1)); 7299391bb9cSRapkiewicz, Pawel } 7309391bb9cSRapkiewicz, Pawel } 7319391bb9cSRapkiewicz, Pawel } 7329391bb9cSRapkiewicz, Pawel } 733a434f2bdSEd Tanous // Finally make a callback with useful data 73455c7b7a2SEd Tanous callback(true, ifaceList); 7359391bb9cSRapkiewicz, Pawel }, 736aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 737aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7389391bb9cSRapkiewicz, Pawel }; 7399391bb9cSRapkiewicz, Pawel }; 7409391bb9cSRapkiewicz, Pawel 7419391bb9cSRapkiewicz, Pawel /** 7429391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7439391bb9cSRapkiewicz, Pawel */ 7449391bb9cSRapkiewicz, Pawel class EthernetCollection : public Node { 7459391bb9cSRapkiewicz, Pawel public: 7469391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 7479391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 7489391bb9cSRapkiewicz, Pawel // GetSubroutes method 7499391bb9cSRapkiewicz, Pawel EthernetCollection(CrowApp &app) 7509391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") { 7519391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7529391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7539391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7549391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7559391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7569391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces"; 7579391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7589391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7599391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7609391bb9cSRapkiewicz, Pawel 761588c3f0dSKowalski, Kamil entityPrivileges = { 762588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 763e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 764e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 765e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 766e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 767e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7689391bb9cSRapkiewicz, Pawel } 7699391bb9cSRapkiewicz, Pawel 7709391bb9cSRapkiewicz, Pawel private: 7719391bb9cSRapkiewicz, Pawel /** 7729391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7739391bb9cSRapkiewicz, Pawel */ 77455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7759391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 7769391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 7779391bb9cSRapkiewicz, Pawel // any Manager, not only hardcoded 'openbmc'. 77855c7b7a2SEd Tanous std::string managerId = "openbmc"; 7799391bb9cSRapkiewicz, Pawel 78055c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 781*8ceb2ecaSEd Tanous ethernetProvider.getEthernetIfaceList([&, managerId{std::move(managerId)} ]( 7829391bb9cSRapkiewicz, Pawel const bool &success, const std::vector<std::string> &iface_list) { 7839391bb9cSRapkiewicz, Pawel if (success) { 78455c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 78555c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 78655c7b7a2SEd Tanous ifaceArray.push_back( 78755c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + managerId + 78855c7b7a2SEd Tanous "/EthernetInterfaces/" + ifaceItem}}); 7899391bb9cSRapkiewicz, Pawel } 79055c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 79155c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 7929391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = 79355c7b7a2SEd Tanous "/redfish/v1/Managers/" + managerId + "/EthernetInterfaces"; 79455c7b7a2SEd Tanous res.jsonValue = Node::json; 7959391bb9cSRapkiewicz, Pawel } else { 7969391bb9cSRapkiewicz, Pawel // No success, best what we can do is return INTERNALL ERROR 797e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 7989391bb9cSRapkiewicz, Pawel } 7999391bb9cSRapkiewicz, Pawel res.end(); 8009391bb9cSRapkiewicz, Pawel }); 8019391bb9cSRapkiewicz, Pawel } 8029391bb9cSRapkiewicz, Pawel 8039391bb9cSRapkiewicz, Pawel // Ethernet Provider object 8049391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 80555c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 8069391bb9cSRapkiewicz, Pawel }; 8079391bb9cSRapkiewicz, Pawel 8089391bb9cSRapkiewicz, Pawel /** 8099391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8109391bb9cSRapkiewicz, Pawel */ 8119391bb9cSRapkiewicz, Pawel class EthernetInterface : public Node { 8129391bb9cSRapkiewicz, Pawel public: 8139391bb9cSRapkiewicz, Pawel /* 8149391bb9cSRapkiewicz, Pawel * Default Constructor 8159391bb9cSRapkiewicz, Pawel */ 8169391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 8179391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 8189391bb9cSRapkiewicz, Pawel // GetSubroutes method 8199391bb9cSRapkiewicz, Pawel EthernetInterface(CrowApp &app) 8209391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/", 8219391bb9cSRapkiewicz, Pawel std::string()) { 8229391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface"; 8239391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8249391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8259391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8269391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8279391bb9cSRapkiewicz, Pawel 828588c3f0dSKowalski, Kamil entityPrivileges = { 829588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 830e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 831e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 832e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 833e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 834e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8359391bb9cSRapkiewicz, Pawel } 8369391bb9cSRapkiewicz, Pawel 837e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 838e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 839e439f0f8SKowalski, Kamil const nlohmann::json &input, 840588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 841e439f0f8SKowalski, Kamil const std::string &pathPrefix, 842588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 843588c3f0dSKowalski, Kamil if (!input.is_object()) { 844588c3f0dSKowalski, Kamil messages::addMessageToJson( 84555c7b7a2SEd Tanous asyncResp->res.jsonValue, 846e439f0f8SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "VLAN"), pathPrefix); 847588c3f0dSKowalski, Kamil return; 848588c3f0dSKowalski, Kamil } 849588c3f0dSKowalski, Kamil 850e439f0f8SKowalski, Kamil const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix; 851e439f0f8SKowalski, Kamil nlohmann::json ¶msJson = 852e439f0f8SKowalski, Kamil (pathPrefix == "/") 85355c7b7a2SEd Tanous ? asyncResp->res.jsonValue 85455c7b7a2SEd Tanous : asyncResp->res.jsonValue[nlohmann::json_pointer<nlohmann::json>( 855e439f0f8SKowalski, Kamil pathPrefix)]; 856588c3f0dSKowalski, Kamil bool inputVlanEnabled; 857588c3f0dSKowalski, Kamil uint64_t inputVlanId; 858e439f0f8SKowalski, Kamil 859588c3f0dSKowalski, Kamil json_util::Result inputVlanEnabledState = json_util::getBool( 860588c3f0dSKowalski, Kamil "VLANEnable", input, inputVlanEnabled, 861588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 86255c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable")); 863588c3f0dSKowalski, Kamil json_util::Result inputVlanIdState = json_util::getUnsigned( 864588c3f0dSKowalski, Kamil "VLANId", input, inputVlanId, 865588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 86655c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANId")); 867588c3f0dSKowalski, Kamil bool inputInvalid = false; 868588c3f0dSKowalski, Kamil 869588c3f0dSKowalski, Kamil // Do not proceed if fields in VLAN object were of wrong type 870588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::WRONG_TYPE || 871588c3f0dSKowalski, Kamil inputVlanIdState == json_util::Result::WRONG_TYPE) { 872588c3f0dSKowalski, Kamil return; 873588c3f0dSKowalski, Kamil } 874588c3f0dSKowalski, Kamil 875588c3f0dSKowalski, Kamil // Verify input 87655c7b7a2SEd Tanous if (eth_data.vlanId == nullptr) { 877e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 878e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 87955c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 880588c3f0dSKowalski, Kamil messages::propertyMissing("VLANEnable"), 881e439f0f8SKowalski, Kamil pathPrefix); 882588c3f0dSKowalski, Kamil 883588c3f0dSKowalski, Kamil inputInvalid = true; 884588c3f0dSKowalski, Kamil } else { 885588c3f0dSKowalski, Kamil // Load actual data into field values if they were not provided 886588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::NOT_EXIST) { 887588c3f0dSKowalski, Kamil inputVlanEnabled = true; 888588c3f0dSKowalski, Kamil } 889588c3f0dSKowalski, Kamil 890588c3f0dSKowalski, Kamil if (inputVlanIdState == json_util::Result::NOT_EXIST) { 89155c7b7a2SEd Tanous inputVlanId = *eth_data.vlanId; 892588c3f0dSKowalski, Kamil } 893588c3f0dSKowalski, Kamil } 894588c3f0dSKowalski, Kamil 895588c3f0dSKowalski, Kamil // Do not proceed if input has not been valid 896588c3f0dSKowalski, Kamil if (inputInvalid) { 897588c3f0dSKowalski, Kamil return; 898588c3f0dSKowalski, Kamil } 899588c3f0dSKowalski, Kamil 900588c3f0dSKowalski, Kamil // VLAN is configured on the interface 90155c7b7a2SEd Tanous if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId) { 902588c3f0dSKowalski, Kamil // Change VLAN Id 903e439f0f8SKowalski, Kamil paramsJson["VLANId"] = inputVlanId; 904e439f0f8SKowalski, Kamil OnDemandEthernetProvider::changeVlanId( 905e439f0f8SKowalski, Kamil ifaceId, static_cast<uint32_t>(inputVlanId), 906e439f0f8SKowalski, Kamil [&, asyncResp, pathPrefx{std::move(pathPrefix)} ]( 907e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 908588c3f0dSKowalski, Kamil if (ec) { 90955c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 910e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 911588c3f0dSKowalski, Kamil } else { 912e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = true; 913e439f0f8SKowalski, Kamil } 914e439f0f8SKowalski, Kamil }); 915e439f0f8SKowalski, Kamil } else if (inputVlanEnabled == false) { 916e439f0f8SKowalski, Kamil // Disable VLAN 917e439f0f8SKowalski, Kamil OnDemandEthernetProvider::disableVlan( 918e439f0f8SKowalski, Kamil ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)} ]( 919e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 920e439f0f8SKowalski, Kamil if (ec) { 92155c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 922e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 923e439f0f8SKowalski, Kamil } else { 924e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = false; 925588c3f0dSKowalski, Kamil } 926588c3f0dSKowalski, Kamil }); 927588c3f0dSKowalski, Kamil } 928588c3f0dSKowalski, Kamil } 929588c3f0dSKowalski, Kamil 930e439f0f8SKowalski, Kamil private: 931588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 932588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 933588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 934588c3f0dSKowalski, Kamil if (input.is_string()) { 935588c3f0dSKowalski, Kamil std::string newHostname = input.get<std::string>(); 936588c3f0dSKowalski, Kamil 937588c3f0dSKowalski, Kamil if (eth_data.hostname == nullptr || newHostname != *eth_data.hostname) { 938588c3f0dSKowalski, Kamil // Change hostname 93955c7b7a2SEd Tanous ethernetProvider.setHostName( 940588c3f0dSKowalski, Kamil newHostname, 941588c3f0dSKowalski, Kamil [asyncResp, newHostname](const boost::system::error_code ec) { 942588c3f0dSKowalski, Kamil if (ec) { 94355c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 944588c3f0dSKowalski, Kamil messages::internalError(), 945588c3f0dSKowalski, Kamil "/HostName"); 946588c3f0dSKowalski, Kamil } else { 94755c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 948588c3f0dSKowalski, Kamil } 949588c3f0dSKowalski, Kamil }); 950588c3f0dSKowalski, Kamil } 951588c3f0dSKowalski, Kamil } else { 952588c3f0dSKowalski, Kamil messages::addMessageToJson( 95355c7b7a2SEd Tanous asyncResp->res.jsonValue, 954588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "HostName"), 955588c3f0dSKowalski, Kamil "/HostName"); 956588c3f0dSKowalski, Kamil } 957588c3f0dSKowalski, Kamil } 958588c3f0dSKowalski, Kamil 959179db1d7SKowalski, Kamil void handleIPv4Patch(const std::string &ifaceId, const nlohmann::json &input, 960179db1d7SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data, 961179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 962179db1d7SKowalski, Kamil if (!input.is_array()) { 963179db1d7SKowalski, Kamil messages::addMessageToJson( 96455c7b7a2SEd Tanous asyncResp->res.jsonValue, 965179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 966179db1d7SKowalski, Kamil "/IPv4Addresses"); 967179db1d7SKowalski, Kamil return; 968179db1d7SKowalski, Kamil } 969179db1d7SKowalski, Kamil 970179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 971179db1d7SKowalski, Kamil if (input.size() < ipv4_data.size()) { 972179db1d7SKowalski, Kamil // TODO(kkowalsk) This should be a message indicating that not enough 973179db1d7SKowalski, Kamil // data has been provided 97455c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 975179db1d7SKowalski, Kamil messages::internalError(), "/IPv4Addresses"); 976179db1d7SKowalski, Kamil return; 977179db1d7SKowalski, Kamil } 978179db1d7SKowalski, Kamil 979179db1d7SKowalski, Kamil json_util::Result addressFieldState; 980179db1d7SKowalski, Kamil json_util::Result subnetMaskFieldState; 981179db1d7SKowalski, Kamil json_util::Result addressOriginFieldState; 982179db1d7SKowalski, Kamil json_util::Result gatewayFieldState; 983179db1d7SKowalski, Kamil const std::string *addressFieldValue; 984179db1d7SKowalski, Kamil const std::string *subnetMaskFieldValue; 985179db1d7SKowalski, Kamil const std::string *addressOriginFieldValue = nullptr; 986179db1d7SKowalski, Kamil const std::string *gatewayFieldValue; 987179db1d7SKowalski, Kamil uint8_t subnetMaskAsPrefixLength; 988179db1d7SKowalski, Kamil std::string addressOriginInDBusFormat; 989179db1d7SKowalski, Kamil 990179db1d7SKowalski, Kamil bool errorDetected = false; 991179db1d7SKowalski, Kamil for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) { 992179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 993179db1d7SKowalski, Kamil if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) { 994179db1d7SKowalski, Kamil // Invalid object type 995179db1d7SKowalski, Kamil messages::addMessageToJson( 99655c7b7a2SEd Tanous asyncResp->res.jsonValue, 997179db1d7SKowalski, Kamil messages::propertyValueTypeError(input[entryIdx].dump(), 998179db1d7SKowalski, Kamil "IPv4Address"), 999179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx)); 1000179db1d7SKowalski, Kamil 1001179db1d7SKowalski, Kamil continue; 1002179db1d7SKowalski, Kamil } 1003179db1d7SKowalski, Kamil 1004179db1d7SKowalski, Kamil // Try to load fields 1005179db1d7SKowalski, Kamil addressFieldState = json_util::getString( 1006179db1d7SKowalski, Kamil "Address", input[entryIdx], addressFieldValue, 1007179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 100855c7b7a2SEd Tanous asyncResp->res.jsonValue, 1009179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1010179db1d7SKowalski, Kamil subnetMaskFieldState = json_util::getString( 1011179db1d7SKowalski, Kamil "SubnetMask", input[entryIdx], subnetMaskFieldValue, 1012179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 101355c7b7a2SEd Tanous asyncResp->res.jsonValue, 1014179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1015179db1d7SKowalski, Kamil addressOriginFieldState = json_util::getString( 1016179db1d7SKowalski, Kamil "AddressOrigin", input[entryIdx], addressOriginFieldValue, 1017179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 101855c7b7a2SEd Tanous asyncResp->res.jsonValue, 1019179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1020179db1d7SKowalski, Kamil gatewayFieldState = json_util::getString( 1021179db1d7SKowalski, Kamil "Gateway", input[entryIdx], gatewayFieldValue, 1022179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 102355c7b7a2SEd Tanous asyncResp->res.jsonValue, 1024179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1025179db1d7SKowalski, Kamil 1026179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::WRONG_TYPE || 1027179db1d7SKowalski, Kamil subnetMaskFieldState == json_util::Result::WRONG_TYPE || 1028179db1d7SKowalski, Kamil addressOriginFieldState == json_util::Result::WRONG_TYPE || 1029179db1d7SKowalski, Kamil gatewayFieldState == json_util::Result::WRONG_TYPE) { 1030179db1d7SKowalski, Kamil return; 1031179db1d7SKowalski, Kamil } 1032179db1d7SKowalski, Kamil 1033179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 103455c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount(*addressFieldValue)) { 1035179db1d7SKowalski, Kamil errorDetected = true; 1036179db1d7SKowalski, Kamil messages::addMessageToJson( 103755c7b7a2SEd Tanous asyncResp->res.jsonValue, 1038179db1d7SKowalski, Kamil messages::propertyValueFormatError(*addressFieldValue, "Address"), 1039179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1040179db1d7SKowalski, Kamil } 1041179db1d7SKowalski, Kamil 1042179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 104355c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount( 1044179db1d7SKowalski, Kamil *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) { 1045179db1d7SKowalski, Kamil errorDetected = true; 1046179db1d7SKowalski, Kamil messages::addMessageToJson( 104755c7b7a2SEd Tanous asyncResp->res.jsonValue, 1048179db1d7SKowalski, Kamil messages::propertyValueFormatError(*subnetMaskFieldValue, 1049179db1d7SKowalski, Kamil "SubnetMask"), 1050179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1051179db1d7SKowalski, Kamil } 1052179db1d7SKowalski, Kamil 105355c7b7a2SEd Tanous // get Address origin in proper format 1054179db1d7SKowalski, Kamil addressOriginInDBusFormat = 105555c7b7a2SEd Tanous ethernetProvider.translateAddressOriginBetweenDBusAndRedfish( 1056179db1d7SKowalski, Kamil addressOriginFieldValue, true, false); 1057179db1d7SKowalski, Kamil 1058179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1059179db1d7SKowalski, Kamil addressOriginInDBusFormat.empty()) { 1060179db1d7SKowalski, Kamil errorDetected = true; 1061179db1d7SKowalski, Kamil messages::addMessageToJson( 106255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1063179db1d7SKowalski, Kamil messages::propertyValueNotInList(*addressOriginFieldValue, 1064179db1d7SKowalski, Kamil "AddressOrigin"), 1065179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1066179db1d7SKowalski, Kamil } 1067179db1d7SKowalski, Kamil 1068179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 106955c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount(*gatewayFieldValue)) { 1070179db1d7SKowalski, Kamil errorDetected = true; 1071179db1d7SKowalski, Kamil messages::addMessageToJson( 107255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1073179db1d7SKowalski, Kamil messages::propertyValueFormatError(*gatewayFieldValue, "Gateway"), 1074179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1075179db1d7SKowalski, Kamil } 1076179db1d7SKowalski, Kamil 1077179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1078179db1d7SKowalski, Kamil // end loop 1079179db1d7SKowalski, Kamil if (errorDetected) { 1080179db1d7SKowalski, Kamil errorDetected = false; 1081179db1d7SKowalski, Kamil continue; 1082179db1d7SKowalski, Kamil } 1083179db1d7SKowalski, Kamil 1084179db1d7SKowalski, Kamil if (entryIdx >= ipv4_data.size()) { 108555c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = input[entryIdx]; 1086179db1d7SKowalski, Kamil 1087179db1d7SKowalski, Kamil // Verify that all field were provided 1088179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::NOT_EXIST) { 1089179db1d7SKowalski, Kamil errorDetected = true; 1090179db1d7SKowalski, Kamil messages::addMessageToJson( 109155c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("Address"), 1092179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1093179db1d7SKowalski, Kamil } 1094179db1d7SKowalski, Kamil 1095179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::NOT_EXIST) { 1096179db1d7SKowalski, Kamil errorDetected = true; 1097179db1d7SKowalski, Kamil messages::addMessageToJson( 109855c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("SubnetMask"), 1099179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1100179db1d7SKowalski, Kamil } 1101179db1d7SKowalski, Kamil 1102179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::NOT_EXIST) { 1103179db1d7SKowalski, Kamil errorDetected = true; 1104179db1d7SKowalski, Kamil messages::addMessageToJson( 110555c7b7a2SEd Tanous asyncResp->res.jsonValue, 1106179db1d7SKowalski, Kamil messages::propertyMissing("AddressOrigin"), 1107179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1108179db1d7SKowalski, Kamil } 1109179db1d7SKowalski, Kamil 1110179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::NOT_EXIST) { 1111179db1d7SKowalski, Kamil errorDetected = true; 1112179db1d7SKowalski, Kamil messages::addMessageToJson( 111355c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("Gateway"), 1114179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1115179db1d7SKowalski, Kamil } 1116179db1d7SKowalski, Kamil 1117179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1118179db1d7SKowalski, Kamil // end loop 1119179db1d7SKowalski, Kamil if (errorDetected) { 1120179db1d7SKowalski, Kamil errorDetected = false; 1121179db1d7SKowalski, Kamil continue; 1122179db1d7SKowalski, Kamil } 1123179db1d7SKowalski, Kamil 1124179db1d7SKowalski, Kamil // Create IPv4 with provided data 112555c7b7a2SEd Tanous ethernetProvider.createIPv4(ifaceId, entryIdx, subnetMaskAsPrefixLength, 112655c7b7a2SEd Tanous *gatewayFieldValue, *addressFieldValue, 112755c7b7a2SEd Tanous asyncResp); 1128179db1d7SKowalski, Kamil } else { 1129179db1d7SKowalski, Kamil // Existing object that should be modified/deleted/remain unchanged 1130179db1d7SKowalski, Kamil if (input[entryIdx].is_null()) { 1131179db1d7SKowalski, Kamil // Object should be deleted 113255c7b7a2SEd Tanous ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, entryIdx, 113355c7b7a2SEd Tanous asyncResp); 1134179db1d7SKowalski, Kamil } else if (input[entryIdx].is_object()) { 1135179db1d7SKowalski, Kamil if (input[entryIdx].size() == 0) { 1136179db1d7SKowalski, Kamil // Object shall remain unchanged 1137179db1d7SKowalski, Kamil continue; 1138179db1d7SKowalski, Kamil } 1139179db1d7SKowalski, Kamil 1140179db1d7SKowalski, Kamil // Apply changes 1141179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1142179db1d7SKowalski, Kamil ipv4_data[entryIdx].address != nullptr && 1143179db1d7SKowalski, Kamil *ipv4_data[entryIdx].address != *addressFieldValue) { 114455c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1145179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Address", 1146179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1147179db1d7SKowalski, Kamil } 1148179db1d7SKowalski, Kamil 1149179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1150179db1d7SKowalski, Kamil ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) { 115155c7b7a2SEd Tanous ethernetProvider.changeIPv4SubnetMaskProperty( 1152179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1153179db1d7SKowalski, Kamil *subnetMaskFieldValue, subnetMaskAsPrefixLength, asyncResp); 1154179db1d7SKowalski, Kamil } 1155179db1d7SKowalski, Kamil 1156179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1157179db1d7SKowalski, Kamil ipv4_data[entryIdx].origin != *addressFieldValue) { 115855c7b7a2SEd Tanous ethernetProvider.changeIPv4Origin( 1159179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1160179db1d7SKowalski, Kamil *addressOriginFieldValue, addressOriginInDBusFormat, asyncResp); 1161179db1d7SKowalski, Kamil } 1162179db1d7SKowalski, Kamil 1163179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1164179db1d7SKowalski, Kamil ipv4_data[entryIdx].gateway != nullptr && 1165179db1d7SKowalski, Kamil *ipv4_data[entryIdx].gateway != *gatewayFieldValue) { 116655c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1167179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Gateway", 1168179db1d7SKowalski, Kamil *gatewayFieldValue, asyncResp); 1169179db1d7SKowalski, Kamil } 1170179db1d7SKowalski, Kamil } 1171179db1d7SKowalski, Kamil } 1172179db1d7SKowalski, Kamil } 1173179db1d7SKowalski, Kamil } 1174179db1d7SKowalski, Kamil 1175588c3f0dSKowalski, Kamil nlohmann::json parseInterfaceData( 117655c7b7a2SEd Tanous const std::string &ifaceId, const EthernetInterfaceData ð_data, 1177588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1178588c3f0dSKowalski, Kamil // Copy JSON object to avoid race condition 117955c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1180588c3f0dSKowalski, Kamil 1181588c3f0dSKowalski, Kamil // Fill out obvious data... 118255c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 118355c7b7a2SEd Tanous jsonResponse["@odata.id"] = 118455c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId; 1185588c3f0dSKowalski, Kamil 1186588c3f0dSKowalski, Kamil // ... then the one from DBus, regarding eth iface... 118755c7b7a2SEd Tanous if (eth_data.speed != nullptr) jsonResponse["SpeedMbps"] = *eth_data.speed; 1188588c3f0dSKowalski, Kamil 118955c7b7a2SEd Tanous if (eth_data.macAddress != nullptr) 119055c7b7a2SEd Tanous jsonResponse["MACAddress"] = *eth_data.macAddress; 1191588c3f0dSKowalski, Kamil 1192588c3f0dSKowalski, Kamil if (eth_data.hostname != nullptr) 119355c7b7a2SEd Tanous jsonResponse["HostName"] = *eth_data.hostname; 1194588c3f0dSKowalski, Kamil 119555c7b7a2SEd Tanous if (eth_data.vlanId != nullptr) { 119655c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLAN"]; 1197588c3f0dSKowalski, Kamil vlanObj["VLANEnable"] = true; 119855c7b7a2SEd Tanous vlanObj["VLANId"] = *eth_data.vlanId; 1199eb547730SKowalski, Kamil } else { 120055c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLANs"]; 1201eb547730SKowalski, Kamil vlanObj["@odata.id"] = 120255c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId + 1203eb547730SKowalski, Kamil "/VLANs"; 1204588c3f0dSKowalski, Kamil } 1205588c3f0dSKowalski, Kamil 1206588c3f0dSKowalski, Kamil // ... at last, check if there are IPv4 data and prepare appropriate 1207588c3f0dSKowalski, Kamil // collection 1208588c3f0dSKowalski, Kamil if (ipv4_data.size() > 0) { 120955c7b7a2SEd Tanous nlohmann::json ipv4Array = nlohmann::json::array(); 121055c7b7a2SEd Tanous for (auto &ipv4Config : ipv4_data) { 121155c7b7a2SEd Tanous nlohmann::json jsonIpv4; 121255c7b7a2SEd Tanous if (ipv4Config.address != nullptr) { 121355c7b7a2SEd Tanous jsonIpv4["Address"] = *ipv4Config.address; 121455c7b7a2SEd Tanous if (ipv4Config.gateway != nullptr) 121555c7b7a2SEd Tanous jsonIpv4["Gateway"] = *ipv4Config.gateway; 1216588c3f0dSKowalski, Kamil 121755c7b7a2SEd Tanous jsonIpv4["AddressOrigin"] = ipv4Config.origin; 121855c7b7a2SEd Tanous jsonIpv4["SubnetMask"] = ipv4Config.netmask; 1219588c3f0dSKowalski, Kamil 122055c7b7a2SEd Tanous ipv4Array.push_back(std::move(jsonIpv4)); 1221588c3f0dSKowalski, Kamil } 1222588c3f0dSKowalski, Kamil } 122355c7b7a2SEd Tanous jsonResponse["IPv4Addresses"] = std::move(ipv4Array); 1224588c3f0dSKowalski, Kamil } 1225588c3f0dSKowalski, Kamil 122655c7b7a2SEd Tanous return jsonResponse; 1227588c3f0dSKowalski, Kamil } 1228588c3f0dSKowalski, Kamil 12299391bb9cSRapkiewicz, Pawel /** 12309391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12319391bb9cSRapkiewicz, Pawel */ 123255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12339391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 12349391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call (two params) to get 12359391bb9cSRapkiewicz, Pawel // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 12369391bb9cSRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 12379391bb9cSRapkiewicz, Pawel // impossible. 12389391bb9cSRapkiewicz, Pawel if (params.size() != 1) { 1239e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 12409391bb9cSRapkiewicz, Pawel res.end(); 12419391bb9cSRapkiewicz, Pawel return; 12429391bb9cSRapkiewicz, Pawel } 12439391bb9cSRapkiewicz, Pawel 124455c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 12459391bb9cSRapkiewicz, Pawel 124655c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 12479391bb9cSRapkiewicz, Pawel // preparation 124855c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 124955c7b7a2SEd Tanous ifaceId, 125055c7b7a2SEd Tanous [&, ifaceId](const bool &success, const EthernetInterfaceData ð_data, 12519391bb9cSRapkiewicz, Pawel const std::vector<IPv4AddressData> &ipv4_data) { 12529391bb9cSRapkiewicz, Pawel if (success) { 125355c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data); 12549391bb9cSRapkiewicz, Pawel } else { 12559391bb9cSRapkiewicz, Pawel // ... otherwise return error 12569391bb9cSRapkiewicz, Pawel // TODO(Pawel)consider distinguish between non existing object, and 12579391bb9cSRapkiewicz, Pawel // other errors 1258e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 125955c7b7a2SEd Tanous res.jsonValue, 126055c7b7a2SEd Tanous messages::resourceNotFound("EthernetInterface", ifaceId)); 1261e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 12629391bb9cSRapkiewicz, Pawel } 12639391bb9cSRapkiewicz, Pawel res.end(); 12649391bb9cSRapkiewicz, Pawel }); 12659391bb9cSRapkiewicz, Pawel } 12669391bb9cSRapkiewicz, Pawel 126755c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1268588c3f0dSKowalski, Kamil const std::vector<std::string> ¶ms) override { 1269588c3f0dSKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1270588c3f0dSKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1271588c3f0dSKowalski, Kamil // Check if there is required param, truly entering this shall be 1272588c3f0dSKowalski, Kamil // impossible. 1273588c3f0dSKowalski, Kamil if (params.size() != 1) { 1274588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1275588c3f0dSKowalski, Kamil res.end(); 1276588c3f0dSKowalski, Kamil return; 1277588c3f0dSKowalski, Kamil } 1278588c3f0dSKowalski, Kamil 127955c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 1280588c3f0dSKowalski, Kamil 1281179db1d7SKowalski, Kamil nlohmann::json patchReq; 1282588c3f0dSKowalski, Kamil 1283179db1d7SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1284588c3f0dSKowalski, Kamil return; 1285588c3f0dSKowalski, Kamil } 1286588c3f0dSKowalski, Kamil 128755c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 1288588c3f0dSKowalski, Kamil // preparation 128955c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 129055c7b7a2SEd Tanous ifaceId, [&, ifaceId, patchReq = std::move(patchReq) ]( 1291588c3f0dSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1292588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1293588c3f0dSKowalski, Kamil if (!success) { 1294588c3f0dSKowalski, Kamil // ... otherwise return error 1295588c3f0dSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1296588c3f0dSKowalski, Kamil // other errors 1297927a505aSKowalski, Kamil messages::addMessageToErrorJson( 129855c7b7a2SEd Tanous res.jsonValue, 129955c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1300588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1301588c3f0dSKowalski, Kamil res.end(); 1302588c3f0dSKowalski, Kamil 1303588c3f0dSKowalski, Kamil return; 1304588c3f0dSKowalski, Kamil } 1305588c3f0dSKowalski, Kamil 130655c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data); 1307588c3f0dSKowalski, Kamil 1308588c3f0dSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1309588c3f0dSKowalski, Kamil std::make_shared<AsyncResp>(res); 1310588c3f0dSKowalski, Kamil 1311588c3f0dSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1312588c3f0dSKowalski, Kamil ++propertyIt) { 1313588c3f0dSKowalski, Kamil if (propertyIt.key() == "VLAN") { 131455c7b7a2SEd Tanous handleVlanPatch(ifaceId, propertyIt.value(), eth_data, "/VLAN", 1315588c3f0dSKowalski, Kamil asyncResp); 1316588c3f0dSKowalski, Kamil } else if (propertyIt.key() == "HostName") { 1317588c3f0dSKowalski, Kamil handleHostnamePatch(propertyIt.value(), eth_data, asyncResp); 1318179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv4Addresses") { 131955c7b7a2SEd Tanous handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data, 1320179db1d7SKowalski, Kamil asyncResp); 1321179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv6Addresses") { 1322179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1323179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 132455c7b7a2SEd Tanous res.jsonValue, 1325179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1326588c3f0dSKowalski, Kamil } else { 132755c7b7a2SEd Tanous auto fieldInJsonIt = res.jsonValue.find(propertyIt.key()); 1328588c3f0dSKowalski, Kamil 132955c7b7a2SEd Tanous if (fieldInJsonIt == res.jsonValue.end()) { 1330588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1331588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 133255c7b7a2SEd Tanous res.jsonValue, messages::propertyUnknown(propertyIt.key())); 1333588c3f0dSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1334588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1335588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 133655c7b7a2SEd Tanous res.jsonValue, 1337588c3f0dSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1338588c3f0dSKowalski, Kamil } 1339588c3f0dSKowalski, Kamil } 1340588c3f0dSKowalski, Kamil } 1341588c3f0dSKowalski, Kamil }); 1342588c3f0dSKowalski, Kamil } 1343588c3f0dSKowalski, Kamil 13449391bb9cSRapkiewicz, Pawel // Ethernet Provider object 13459391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 134655c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 13479391bb9cSRapkiewicz, Pawel }; 13489391bb9cSRapkiewicz, Pawel 1349e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection; 1350e439f0f8SKowalski, Kamil 1351e439f0f8SKowalski, Kamil /** 1352e439f0f8SKowalski, Kamil * VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema 1353e439f0f8SKowalski, Kamil */ 1354e439f0f8SKowalski, Kamil class VlanNetworkInterface : public Node { 1355e439f0f8SKowalski, Kamil public: 1356e439f0f8SKowalski, Kamil /* 1357e439f0f8SKowalski, Kamil * Default Constructor 1358e439f0f8SKowalski, Kamil */ 1359e439f0f8SKowalski, Kamil template <typename CrowApp> 1360e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1361e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1362e439f0f8SKowalski, Kamil // GetSubroutes method 1363e439f0f8SKowalski, Kamil VlanNetworkInterface(CrowApp &app) 1364eb547730SKowalski, Kamil : Node( 1365eb547730SKowalski, Kamil app, 1366eb547730SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/<str>", 1367e439f0f8SKowalski, Kamil std::string(), std::string()) { 1368e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1369e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1370e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1371e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1372e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1373e439f0f8SKowalski, Kamil 1374e439f0f8SKowalski, Kamil entityPrivileges = { 1375e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1376e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1377e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1378e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1379e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1380e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1381e439f0f8SKowalski, Kamil } 1382e439f0f8SKowalski, Kamil 1383e439f0f8SKowalski, Kamil private: 1384e439f0f8SKowalski, Kamil nlohmann::json parseInterfaceData( 138555c7b7a2SEd Tanous const std::string &parent_ifaceId, const std::string &ifaceId, 1386e439f0f8SKowalski, Kamil const EthernetInterfaceData ð_data, 1387e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1388e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 138955c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1390e439f0f8SKowalski, Kamil 1391e439f0f8SKowalski, Kamil // Fill out obvious data... 139255c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 139355c7b7a2SEd Tanous jsonResponse["@odata.id"] = 139455c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + parent_ifaceId + 139555c7b7a2SEd Tanous "/VLANs/" + ifaceId; 1396e439f0f8SKowalski, Kamil 139755c7b7a2SEd Tanous jsonResponse["VLANEnable"] = true; 139855c7b7a2SEd Tanous jsonResponse["VLANId"] = *eth_data.vlanId; 1399e439f0f8SKowalski, Kamil 140055c7b7a2SEd Tanous return jsonResponse; 1401e439f0f8SKowalski, Kamil } 1402e439f0f8SKowalski, Kamil 140355c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 1404927a505aSKowalski, Kamil const std::string &iface) { 1405927a505aSKowalski, Kamil if (!boost::starts_with(iface, parent + "_")) { 1406927a505aSKowalski, Kamil messages::addMessageToErrorJson( 140755c7b7a2SEd Tanous res.jsonValue, 1408927a505aSKowalski, Kamil messages::resourceNotFound("VLAN Network Interface", iface)); 1409927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1410927a505aSKowalski, Kamil res.end(); 1411927a505aSKowalski, Kamil 1412927a505aSKowalski, Kamil return false; 1413927a505aSKowalski, Kamil } else { 1414927a505aSKowalski, Kamil return true; 1415927a505aSKowalski, Kamil } 1416927a505aSKowalski, Kamil } 1417927a505aSKowalski, Kamil 1418e439f0f8SKowalski, Kamil /** 1419e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1420e439f0f8SKowalski, Kamil */ 142155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1422e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1423e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1424e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1425e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1426e439f0f8SKowalski, Kamil // impossible. 1427e439f0f8SKowalski, Kamil if (params.size() != 2) { 1428e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1429e439f0f8SKowalski, Kamil res.end(); 1430e439f0f8SKowalski, Kamil return; 1431e439f0f8SKowalski, Kamil } 1432e439f0f8SKowalski, Kamil 143355c7b7a2SEd Tanous const std::string &parentIfaceId = params[0]; 143455c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1435e439f0f8SKowalski, Kamil 1436a434f2bdSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) { 1437a434f2bdSEd Tanous return; 1438a434f2bdSEd Tanous } 1439a434f2bdSEd Tanous 1440e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1441e439f0f8SKowalski, Kamil // preparation 144255c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1443a434f2bdSEd Tanous ifaceId, [&, parentIfaceId, ifaceId]( 1444e439f0f8SKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1445e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 144655c7b7a2SEd Tanous if (success && eth_data.vlanId != nullptr) { 1447a434f2bdSEd Tanous res.jsonValue = 1448a434f2bdSEd Tanous parseInterfaceData(parentIfaceId, ifaceId, eth_data, ipv4_data); 1449e439f0f8SKowalski, Kamil } else { 1450e439f0f8SKowalski, Kamil // ... otherwise return error 1451eb547730SKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1452e439f0f8SKowalski, Kamil // other errors 1453927a505aSKowalski, Kamil messages::addMessageToErrorJson( 145455c7b7a2SEd Tanous res.jsonValue, 145555c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1456e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1457e439f0f8SKowalski, Kamil } 1458e439f0f8SKowalski, Kamil res.end(); 1459e439f0f8SKowalski, Kamil }); 1460e439f0f8SKowalski, Kamil } 1461e439f0f8SKowalski, Kamil 146255c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1463e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1464e439f0f8SKowalski, Kamil if (params.size() != 2) { 1465e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1466e439f0f8SKowalski, Kamil res.end(); 1467e439f0f8SKowalski, Kamil return; 1468e439f0f8SKowalski, Kamil } 1469e439f0f8SKowalski, Kamil 147055c7b7a2SEd Tanous const std::string &parent_ifaceId = params[0]; 147155c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1472927a505aSKowalski, Kamil 147355c7b7a2SEd Tanous if (!verifyNames(res, parent_ifaceId, ifaceId)) { 1474927a505aSKowalski, Kamil return; 1475927a505aSKowalski, Kamil } 1476927a505aSKowalski, Kamil 1477927a505aSKowalski, Kamil nlohmann::json patchReq; 1478927a505aSKowalski, Kamil 1479927a505aSKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1480927a505aSKowalski, Kamil return; 1481927a505aSKowalski, Kamil } 1482927a505aSKowalski, Kamil 1483927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1484927a505aSKowalski, Kamil // preparation 148555c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1486a434f2bdSEd Tanous ifaceId, [&, parent_ifaceId, ifaceId, patchReq = std::move(patchReq) ]( 1487927a505aSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1488927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1489927a505aSKowalski, Kamil if (!success) { 1490927a505aSKowalski, Kamil // ... otherwise return error 1491927a505aSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1492927a505aSKowalski, Kamil // and 1493927a505aSKowalski, Kamil // other errors 1494927a505aSKowalski, Kamil messages::addMessageToErrorJson( 149555c7b7a2SEd Tanous res.jsonValue, 149655c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1497927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1498e439f0f8SKowalski, Kamil res.end(); 1499927a505aSKowalski, Kamil 1500927a505aSKowalski, Kamil return; 1501927a505aSKowalski, Kamil } 1502927a505aSKowalski, Kamil 1503a434f2bdSEd Tanous res.jsonValue = 1504a434f2bdSEd Tanous parseInterfaceData(parent_ifaceId, ifaceId, eth_data, ipv4_data); 1505927a505aSKowalski, Kamil 1506927a505aSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1507927a505aSKowalski, Kamil std::make_shared<AsyncResp>(res); 1508927a505aSKowalski, Kamil 1509927a505aSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1510927a505aSKowalski, Kamil ++propertyIt) { 1511927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 1512927a505aSKowalski, Kamil propertyIt.key() != "VLANId") { 151355c7b7a2SEd Tanous auto fieldInJsonIt = res.jsonValue.find(propertyIt.key()); 1514927a505aSKowalski, Kamil 151555c7b7a2SEd Tanous if (fieldInJsonIt == res.jsonValue.end()) { 1516927a505aSKowalski, Kamil // Field not in scope of defined fields 1517927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1518a434f2bdSEd Tanous res.jsonValue, messages::propertyUnknown(propertyIt.key())); 1519927a505aSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1520927a505aSKowalski, Kamil // User attempted to modify non-writable field 1521927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 152255c7b7a2SEd Tanous res.jsonValue, 1523927a505aSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1524927a505aSKowalski, Kamil } 1525927a505aSKowalski, Kamil } 1526927a505aSKowalski, Kamil } 1527927a505aSKowalski, Kamil 152855c7b7a2SEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data, "/", 1529927a505aSKowalski, Kamil asyncResp); 1530927a505aSKowalski, Kamil }); 1531e439f0f8SKowalski, Kamil } 1532e439f0f8SKowalski, Kamil 153355c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 1534e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1535e439f0f8SKowalski, Kamil if (params.size() != 2) { 1536e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1537e439f0f8SKowalski, Kamil res.end(); 1538e439f0f8SKowalski, Kamil return; 1539e439f0f8SKowalski, Kamil } 1540e439f0f8SKowalski, Kamil 154155c7b7a2SEd Tanous const std::string &parent_ifaceId = params[0]; 154255c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1543927a505aSKowalski, Kamil 154455c7b7a2SEd Tanous if (!verifyNames(res, parent_ifaceId, ifaceId)) { 1545927a505aSKowalski, Kamil return; 1546927a505aSKowalski, Kamil } 1547927a505aSKowalski, Kamil 1548927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1549927a505aSKowalski, Kamil // preparation 155055c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1551a434f2bdSEd Tanous ifaceId, [&, parent_ifaceId, ifaceId]( 1552927a505aSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1553927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 155455c7b7a2SEd Tanous if (success && eth_data.vlanId != nullptr) { 155555c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(parent_ifaceId, ifaceId, 1556927a505aSKowalski, Kamil eth_data, ipv4_data); 1557927a505aSKowalski, Kamil 1558927a505aSKowalski, Kamil // Disable VLAN 1559927a505aSKowalski, Kamil OnDemandEthernetProvider::disableVlan( 156055c7b7a2SEd Tanous ifaceId, [&](const boost::system::error_code ec) { 1561927a505aSKowalski, Kamil if (ec) { 156255c7b7a2SEd Tanous res.jsonValue = nlohmann::json::object(); 156355c7b7a2SEd Tanous messages::addMessageToErrorJson(res.jsonValue, 1564927a505aSKowalski, Kamil messages::internalError()); 1565927a505aSKowalski, Kamil res.result( 1566927a505aSKowalski, Kamil boost::beast::http::status::internal_server_error); 1567927a505aSKowalski, Kamil } 1568e439f0f8SKowalski, Kamil res.end(); 1569927a505aSKowalski, Kamil }); 1570927a505aSKowalski, Kamil } else { 1571927a505aSKowalski, Kamil // ... otherwise return error 1572927a505aSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1573927a505aSKowalski, Kamil // and 1574927a505aSKowalski, Kamil // other errors 1575927a505aSKowalski, Kamil messages::addMessageToErrorJson( 157655c7b7a2SEd Tanous res.jsonValue, 157755c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1578927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1579927a505aSKowalski, Kamil res.end(); 1580927a505aSKowalski, Kamil } 1581927a505aSKowalski, Kamil }); 1582e439f0f8SKowalski, Kamil } 1583e439f0f8SKowalski, Kamil 1584e439f0f8SKowalski, Kamil /** 1585e439f0f8SKowalski, Kamil * This allows VlanNetworkInterfaceCollection to reuse this class' doGet 1586e439f0f8SKowalski, Kamil * method, to maintain consistency of returned data, as Collection's doPost 1587e439f0f8SKowalski, Kamil * should return data for created member which should match member's doGet 1588e439f0f8SKowalski, Kamil * result in 100%. 1589e439f0f8SKowalski, Kamil */ 1590e439f0f8SKowalski, Kamil friend VlanNetworkInterfaceCollection; 1591e439f0f8SKowalski, Kamil 1592e439f0f8SKowalski, Kamil // Ethernet Provider object 1593e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 159455c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 1595e439f0f8SKowalski, Kamil }; 1596e439f0f8SKowalski, Kamil 1597e439f0f8SKowalski, Kamil /** 1598e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1599e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1600e439f0f8SKowalski, Kamil */ 1601e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection : public Node { 1602e439f0f8SKowalski, Kamil public: 1603e439f0f8SKowalski, Kamil template <typename CrowApp> 1604e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1605e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1606e439f0f8SKowalski, Kamil // GetSubroutes method 1607e439f0f8SKowalski, Kamil VlanNetworkInterfaceCollection(CrowApp &app) 1608e439f0f8SKowalski, Kamil : Node(app, 1609e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/", 1610e439f0f8SKowalski, Kamil std::string()), 1611e439f0f8SKowalski, Kamil memberVlan(app) { 1612e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1613e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1614e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1615e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1616e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1617e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1618e439f0f8SKowalski, Kamil 1619e439f0f8SKowalski, Kamil entityPrivileges = { 1620e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1621e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1622e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1623e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1624e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1625e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1626e439f0f8SKowalski, Kamil } 1627e439f0f8SKowalski, Kamil 1628e439f0f8SKowalski, Kamil private: 1629e439f0f8SKowalski, Kamil /** 1630e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1631e439f0f8SKowalski, Kamil */ 163255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1633e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1634e439f0f8SKowalski, Kamil if (params.size() != 1) { 1635e439f0f8SKowalski, Kamil // This means there is a problem with the router 1636e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1637e439f0f8SKowalski, Kamil res.end(); 1638e439f0f8SKowalski, Kamil 1639e439f0f8SKowalski, Kamil return; 1640e439f0f8SKowalski, Kamil } 1641e439f0f8SKowalski, Kamil 1642e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1643e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 164455c7b7a2SEd Tanous std::string managerId = "openbmc"; 1645e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1646e439f0f8SKowalski, Kamil 164755c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 1648*8ceb2ecaSEd Tanous ethernetProvider.getEthernetIfaceList([ 1649*8ceb2ecaSEd Tanous &, managerId{std::move(managerId)}, 1650*8ceb2ecaSEd Tanous rootInterfaceName{std::move(rootInterfaceName)} 1651*8ceb2ecaSEd Tanous ](const bool &success, const std::vector<std::string> &iface_list) { 1652e439f0f8SKowalski, Kamil if (success) { 1653e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 165455c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 1655e439f0f8SKowalski, Kamil 165655c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 165755c7b7a2SEd Tanous if (ifaceItem == rootInterfaceName) { 1658e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1659*8ceb2ecaSEd Tanous } else if (boost::starts_with(ifaceItem, rootInterfaceName + "_")) { 166055c7b7a2SEd Tanous ifaceArray.push_back( 166155c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + managerId + 1662*8ceb2ecaSEd Tanous "/EthernetInterfaces/" + rootInterfaceName + 1663*8ceb2ecaSEd Tanous "/VLANs/" + ifaceItem}}); 1664e439f0f8SKowalski, Kamil } 1665e439f0f8SKowalski, Kamil } 1666e439f0f8SKowalski, Kamil 1667e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 166855c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 166955c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 167055c7b7a2SEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/" + managerId + 1671*8ceb2ecaSEd Tanous "/EthernetInterfaces/" + rootInterfaceName + 1672*8ceb2ecaSEd Tanous "/VLANs"; 167355c7b7a2SEd Tanous res.jsonValue = Node::json; 1674e439f0f8SKowalski, Kamil } else { 1675e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 167655c7b7a2SEd Tanous res.jsonValue, messages::resourceNotFound("EthernetInterface", 1677e439f0f8SKowalski, Kamil rootInterfaceName)); 1678e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1679e439f0f8SKowalski, Kamil res.end(); 1680e439f0f8SKowalski, Kamil } 1681e439f0f8SKowalski, Kamil } else { 1682e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1683e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1684e439f0f8SKowalski, Kamil } 1685e439f0f8SKowalski, Kamil res.end(); 1686e439f0f8SKowalski, Kamil }); 1687e439f0f8SKowalski, Kamil } 1688e439f0f8SKowalski, Kamil 168955c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 1690e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1691e439f0f8SKowalski, Kamil if (params.size() != 1) { 1692e439f0f8SKowalski, Kamil // This means there is a problem with the router 1693e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1694e439f0f8SKowalski, Kamil res.end(); 1695e439f0f8SKowalski, Kamil return; 1696e439f0f8SKowalski, Kamil } 1697e439f0f8SKowalski, Kamil 1698e439f0f8SKowalski, Kamil nlohmann::json postReq; 1699e439f0f8SKowalski, Kamil 1700e439f0f8SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, postReq)) { 1701e439f0f8SKowalski, Kamil return; 1702e439f0f8SKowalski, Kamil } 1703e439f0f8SKowalski, Kamil 1704e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1705e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 170655c7b7a2SEd Tanous std::string managerId = "openbmc"; 1707e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1708e439f0f8SKowalski, Kamil uint64_t vlanId; 1709e439f0f8SKowalski, Kamil bool errorDetected; 1710e439f0f8SKowalski, Kamil 1711e439f0f8SKowalski, Kamil if (json_util::getUnsigned( 1712e439f0f8SKowalski, Kamil "VLANId", postReq, vlanId, 1713e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::MISSING) | 1714e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 171555c7b7a2SEd Tanous res.jsonValue, "/VLANId") != json_util::Result::SUCCESS) { 1716e439f0f8SKowalski, Kamil res.end(); 1717e439f0f8SKowalski, Kamil return; 1718e439f0f8SKowalski, Kamil } 1719e439f0f8SKowalski, Kamil 172055c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 1721*8ceb2ecaSEd Tanous ethernetProvider.getEthernetIfaceList([ 1722*8ceb2ecaSEd Tanous &, managerId{std::move(managerId)}, 1723*8ceb2ecaSEd Tanous rootInterfaceName{std::move(rootInterfaceName)} 1724*8ceb2ecaSEd Tanous ](const bool &success, const std::vector<std::string> &iface_list) { 1725e439f0f8SKowalski, Kamil if (success) { 1726e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 1727e439f0f8SKowalski, Kamil 172855c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 172955c7b7a2SEd Tanous if (ifaceItem == rootInterfaceName) { 1730e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1731e439f0f8SKowalski, Kamil break; 1732e439f0f8SKowalski, Kamil } 1733e439f0f8SKowalski, Kamil } 1734e439f0f8SKowalski, Kamil 1735e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 173655c7b7a2SEd Tanous ethernetProvider.createVlan( 1737e439f0f8SKowalski, Kamil rootInterfaceName, vlanId, 1738e439f0f8SKowalski, Kamil [&, vlanId, rootInterfaceName, 1739e439f0f8SKowalski, Kamil req{std::move(req)} ](const boost::system::error_code ec) { 1740e439f0f8SKowalski, Kamil if (ec) { 1741*8ceb2ecaSEd Tanous messages::addMessageToErrorJson(res.jsonValue, 1742*8ceb2ecaSEd Tanous messages::internalError()); 1743e439f0f8SKowalski, Kamil res.end(); 1744e439f0f8SKowalski, Kamil } else { 1745e439f0f8SKowalski, Kamil memberVlan.doGet( 1746e439f0f8SKowalski, Kamil res, req, 1747e439f0f8SKowalski, Kamil {rootInterfaceName, 1748e439f0f8SKowalski, Kamil rootInterfaceName + "_" + std::to_string(vlanId)}); 1749e439f0f8SKowalski, Kamil } 1750e439f0f8SKowalski, Kamil }); 1751e439f0f8SKowalski, Kamil } else { 1752e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 175355c7b7a2SEd Tanous res.jsonValue, messages::resourceNotFound("EthernetInterface", 1754e439f0f8SKowalski, Kamil rootInterfaceName)); 1755e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1756e439f0f8SKowalski, Kamil res.end(); 1757e439f0f8SKowalski, Kamil } 1758e439f0f8SKowalski, Kamil } else { 1759e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1760e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1761e439f0f8SKowalski, Kamil res.end(); 1762e439f0f8SKowalski, Kamil } 1763e439f0f8SKowalski, Kamil }); 1764e439f0f8SKowalski, Kamil } 1765e439f0f8SKowalski, Kamil 1766e439f0f8SKowalski, Kamil // Ethernet Provider object 1767e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 176855c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 1769e439f0f8SKowalski, Kamil VlanNetworkInterface memberVlan; 1770e439f0f8SKowalski, Kamil }; 1771e439f0f8SKowalski, Kamil 17729391bb9cSRapkiewicz, Pawel } // namespace redfish 1773