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 199*a434f2bdSEd Tanous if (boost::starts_with(static_cast<const std::string &>(objpath.first), 200*a434f2bdSEd 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) { 238*a434f2bdSEd 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*a434f2bdSEd Tanous auto callback = 394*a434f2bdSEd Tanous [asyncResp, ipIdx{std::move(ipIdx)}, name{std::move(name)}, 395*a434f2bdSEd Tanous newValue{std::move(newValue)}](const boost::system::error_code ec) { 396179db1d7SKowalski, Kamil if (ec) { 397179db1d7SKowalski, Kamil messages::addMessageToJson( 39855c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 399179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 400179db1d7SKowalski, Kamil } else { 40155c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 402179db1d7SKowalski, Kamil } 403179db1d7SKowalski, Kamil }; 404179db1d7SKowalski, Kamil 40555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 406179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 407179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 408179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 409179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 410179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 411179db1d7SKowalski, Kamil }; 412179db1d7SKowalski, Kamil 413179db1d7SKowalski, Kamil /** 414179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 415179db1d7SKowalski, Kamil * 416179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 41755c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 418179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 419179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 420179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 421179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 422179db1d7SKowalski, Kamil * 423179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 424179db1d7SKowalski, Kamil * otherwise 425179db1d7SKowalski, Kamil */ 426179db1d7SKowalski, Kamil void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 427179db1d7SKowalski, Kamil const std::string &ipHash, const std::string &newValue, 428179db1d7SKowalski, Kamil const std::string &newValueDbus, 429179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 430179db1d7SKowalski, Kamil auto callback = 431179db1d7SKowalski, Kamil [asyncResp, ipIdx{std::move(ipIdx)}, 432179db1d7SKowalski, Kamil newValue{std::move(newValue)}](const boost::system::error_code ec) { 433179db1d7SKowalski, Kamil if (ec) { 434179db1d7SKowalski, Kamil messages::addMessageToJson( 43555c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 436179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin"); 437179db1d7SKowalski, Kamil } else { 43855c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 439179db1d7SKowalski, Kamil newValue; 440179db1d7SKowalski, Kamil } 441179db1d7SKowalski, Kamil }; 442179db1d7SKowalski, Kamil 44355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 444179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 445179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 446179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 447179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 448179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 449179db1d7SKowalski, Kamil }; 450179db1d7SKowalski, Kamil 451179db1d7SKowalski, Kamil /** 452179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 453179db1d7SKowalski, Kamil * 454179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 45555c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 456179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 457179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 458179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 459179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 460179db1d7SKowalski, Kamil * 461179db1d7SKowalski, Kamil * @return None 462179db1d7SKowalski, Kamil */ 463179db1d7SKowalski, Kamil void changeIPv4SubnetMaskProperty( 464179db1d7SKowalski, Kamil const std::string &ifaceId, int ipIdx, const std::string &ipHash, 465179db1d7SKowalski, Kamil const std::string &newValueStr, uint8_t &newValue, 466179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 467*a434f2bdSEd Tanous auto callback = [asyncResp, ipIdx{std::move(ipIdx)}, 468*a434f2bdSEd Tanous newValueStr{std::move(newValueStr)}]( 469*a434f2bdSEd Tanous const boost::system::error_code ec) { 470179db1d7SKowalski, Kamil if (ec) { 471179db1d7SKowalski, Kamil messages::addMessageToJson( 47255c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 473179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 474179db1d7SKowalski, Kamil } else { 47555c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 476179db1d7SKowalski, Kamil newValueStr; 477179db1d7SKowalski, Kamil } 478179db1d7SKowalski, Kamil }; 479179db1d7SKowalski, Kamil 48055c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 481179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 482179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 483179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 484179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 485179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 486179db1d7SKowalski, Kamil }; 487179db1d7SKowalski, Kamil 488179db1d7SKowalski, Kamil /** 489588c3f0dSKowalski, Kamil * @brief Disables VLAN with given ifaceId 490588c3f0dSKowalski, Kamil * 491588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be disabled 492588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 493588c3f0dSKowalski, Kamil * 494588c3f0dSKowalski, Kamil * @return None. 495588c3f0dSKowalski, Kamil */ 496588c3f0dSKowalski, Kamil template <typename CallbackFunc> 497e439f0f8SKowalski, Kamil static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) { 49855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 499588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 500588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 501588c3f0dSKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 502588c3f0dSKowalski, Kamil }; 503588c3f0dSKowalski, Kamil 504588c3f0dSKowalski, Kamil /** 505588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 506588c3f0dSKowalski, Kamil * 507588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 508588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 509588c3f0dSKowalski, Kamil * 510588c3f0dSKowalski, Kamil * @return None. 511588c3f0dSKowalski, Kamil */ 512588c3f0dSKowalski, Kamil template <typename CallbackFunc> 513588c3f0dSKowalski, Kamil void setHostName(const std::string &newHostname, CallbackFunc &&callback) { 51455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 515588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 516588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 517588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 518588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 519588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 520588c3f0dSKowalski, Kamil }; 521588c3f0dSKowalski, Kamil 522588c3f0dSKowalski, Kamil /** 523179db1d7SKowalski, Kamil * @brief Deletes given IPv4 524179db1d7SKowalski, Kamil * 525179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 52655c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 527179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 528179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 529179db1d7SKowalski, Kamil * 530179db1d7SKowalski, Kamil * @return None 531179db1d7SKowalski, Kamil */ 532179db1d7SKowalski, Kamil void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 533179db1d7SKowalski, Kamil unsigned int ipIdx, 534179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 53555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 536*a434f2bdSEd Tanous [ipIdx{std::move(ipIdx)}, 537*a434f2bdSEd Tanous asyncResp{std::move(asyncResp)}](const boost::system::error_code ec) { 538179db1d7SKowalski, Kamil if (ec) { 539179db1d7SKowalski, Kamil messages::addMessageToJson( 54055c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 541179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 542179db1d7SKowalski, Kamil } else { 54355c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 544179db1d7SKowalski, Kamil } 545179db1d7SKowalski, Kamil }, 546179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 547179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 548179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 549179db1d7SKowalski, Kamil } 550179db1d7SKowalski, Kamil 551179db1d7SKowalski, Kamil /** 552179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 553179db1d7SKowalski, Kamil * 554179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 55555c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 556179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 557179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 558179db1d7SKowalski, Kamil * 559179db1d7SKowalski, Kamil * @return None 560179db1d7SKowalski, Kamil */ 561179db1d7SKowalski, Kamil void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 562179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 563179db1d7SKowalski, Kamil const std::string &address, 564179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 565*a434f2bdSEd Tanous auto createIpHandler = 566*a434f2bdSEd Tanous [ipIdx{std::move(ipIdx)}, 567*a434f2bdSEd Tanous asyncResp{std::move(asyncResp)}](const boost::system::error_code ec) { 568179db1d7SKowalski, Kamil if (ec) { 569179db1d7SKowalski, Kamil messages::addMessageToJson( 57055c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 571179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 572179db1d7SKowalski, Kamil } 573179db1d7SKowalski, Kamil }; 574179db1d7SKowalski, Kamil 57555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 576179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 577179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 578179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 579179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 580179db1d7SKowalski, Kamil gateway); 581179db1d7SKowalski, Kamil } 582179db1d7SKowalski, Kamil 583179db1d7SKowalski, Kamil /** 584179db1d7SKowalski, Kamil * @brief Translates Address Origin value from D-Bus to Redfish format and 585179db1d7SKowalski, Kamil * vice-versa 586179db1d7SKowalski, Kamil * 587179db1d7SKowalski, Kamil * @param[in] inputOrigin Input value that should be translated 588179db1d7SKowalski, Kamil * @param[in] isIPv4 True for IPv4 origins, False for IPv6 589179db1d7SKowalski, Kamil * @param[in] isFromDBus True for DBus->Redfish conversion, false for reverse 590179db1d7SKowalski, Kamil * 591179db1d7SKowalski, Kamil * @return Empty string in case of failure, translated value otherwise 592179db1d7SKowalski, Kamil */ 593179db1d7SKowalski, Kamil std::string translateAddressOriginBetweenDBusAndRedfish( 594179db1d7SKowalski, Kamil const std::string *inputOrigin, bool isIPv4, bool isFromDBus) { 595179db1d7SKowalski, Kamil // Invalid pointer 596179db1d7SKowalski, Kamil if (inputOrigin == nullptr) { 597179db1d7SKowalski, Kamil return ""; 598179db1d7SKowalski, Kamil } 599179db1d7SKowalski, Kamil 600179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv4OnlyIdx = 1; 601179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv6OnlyIdx = 3; 602179db1d7SKowalski, Kamil 603179db1d7SKowalski, Kamil std::array<std::pair<const char *, const char *>, 6> translationTable{ 604179db1d7SKowalski, Kamil {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"}, 605179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"}, 606179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 607179db1d7SKowalski, Kamil "IPv4LinkLocal"}, 608179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"}, 609179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 610179db1d7SKowalski, Kamil "LinkLocal"}, 611179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}}; 612179db1d7SKowalski, Kamil 613179db1d7SKowalski, Kamil for (unsigned int i = 0; i < translationTable.size(); i++) { 614179db1d7SKowalski, Kamil // Skip unrelated 615179db1d7SKowalski, Kamil if (isIPv4 && i >= firstIPv6OnlyIdx) break; 616179db1d7SKowalski, Kamil if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) continue; 617179db1d7SKowalski, Kamil 618179db1d7SKowalski, Kamil // When translating D-Bus to Redfish compare input to first element 619179db1d7SKowalski, Kamil if (isFromDBus && translationTable[i].first == *inputOrigin) 620179db1d7SKowalski, Kamil return translationTable[i].second; 621179db1d7SKowalski, Kamil 622179db1d7SKowalski, Kamil // When translating Redfish to D-Bus compare input to second element 623179db1d7SKowalski, Kamil if (!isFromDBus && translationTable[i].second == *inputOrigin) 624179db1d7SKowalski, Kamil return translationTable[i].first; 625179db1d7SKowalski, Kamil } 626179db1d7SKowalski, Kamil 627179db1d7SKowalski, Kamil // If we are still here, that means that value has not been found 628179db1d7SKowalski, Kamil return ""; 629179db1d7SKowalski, Kamil } 630179db1d7SKowalski, Kamil 631179db1d7SKowalski, Kamil /** 632179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 633179db1d7SKowalski, Kamil * Object 634179db1d7SKowalski, Kamil * from EntityManager Network Manager 63555c7b7a2SEd Tanous * @param ethifaceId a eth interface id to query on DBus 636179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 637179db1d7SKowalski, Kamil * into JSON 638179db1d7SKowalski, Kamil */ 639179db1d7SKowalski, Kamil template <typename CallbackFunc> 64055c7b7a2SEd Tanous void getEthernetIfaceData(const std::string ðifaceId, 641179db1d7SKowalski, Kamil CallbackFunc &&callback) { 64255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 643*a434f2bdSEd Tanous [this, ethifaceId{std::move(ethifaceId)}, 644*a434f2bdSEd Tanous callback{std::move(callback)}]( 645*a434f2bdSEd Tanous const boost::system::error_code error_code, 646179db1d7SKowalski, Kamil const GetManagedObjectsType &resp) { 64755c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 64855c7b7a2SEd Tanous std::vector<IPv4AddressData> ipv4Data; 64955c7b7a2SEd Tanous ipv4Data.reserve(maxIpV4AddressesPerInterface); 650179db1d7SKowalski, Kamil 651179db1d7SKowalski, Kamil if (error_code) { 652179db1d7SKowalski, Kamil // Something wrong on DBus, the error_code is not important at 653179db1d7SKowalski, Kamil // this moment, just return success=false, and empty output. Since 654179db1d7SKowalski, Kamil // size of vector may vary depending on information from Network 655179db1d7SKowalski, Kamil // Manager, and empty output could not be treated same way as 656179db1d7SKowalski, Kamil // error. 65755c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 658179db1d7SKowalski, Kamil return; 659179db1d7SKowalski, Kamil } 660179db1d7SKowalski, Kamil 661927a505aSKowalski, Kamil // Find interface 66255c7b7a2SEd Tanous if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) == 663927a505aSKowalski, Kamil resp.end()) { 664927a505aSKowalski, Kamil // Interface has not been found 66555c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 666927a505aSKowalski, Kamil return; 667927a505aSKowalski, Kamil } 668927a505aSKowalski, Kamil 66955c7b7a2SEd Tanous extractEthernetInterfaceData(ethifaceId, resp, ethData); 67055c7b7a2SEd Tanous extractIPv4Data(ethifaceId, resp, ipv4Data); 671179db1d7SKowalski, Kamil 672179db1d7SKowalski, Kamil // Fix global GW 67355c7b7a2SEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) { 674179db1d7SKowalski, Kamil if ((ipv4.global) && 675179db1d7SKowalski, Kamil ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) { 67655c7b7a2SEd Tanous ipv4.gateway = ethData.defaultGateway; 677179db1d7SKowalski, Kamil } 678179db1d7SKowalski, Kamil } 679179db1d7SKowalski, Kamil 680*a434f2bdSEd Tanous // Finally make a callback with useful data 68155c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 682179db1d7SKowalski, Kamil }, 683179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 684179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 685179db1d7SKowalski, Kamil }; 686179db1d7SKowalski, Kamil 687179db1d7SKowalski, Kamil /** 6889391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6899391bb9cSRapkiewicz, Pawel * Manager 6909391bb9cSRapkiewicz, Pawel * @param callback a function that shall be called to convert Dbus output into 6919391bb9cSRapkiewicz, Pawel * JSON. 6929391bb9cSRapkiewicz, Pawel */ 6939391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 6949391bb9cSRapkiewicz, Pawel void getEthernetIfaceList(CallbackFunc &&callback) { 69555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6969391bb9cSRapkiewicz, Pawel [this, callback{std::move(callback)}]( 6979391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 698aa2e59c1SEd Tanous GetManagedObjectsType &resp) { 6999391bb9cSRapkiewicz, Pawel // Callback requires vector<string> to retrieve all available ethernet 7009391bb9cSRapkiewicz, Pawel // interfaces 70155c7b7a2SEd Tanous std::vector<std::string> ifaceList; 70255c7b7a2SEd Tanous ifaceList.reserve(resp.size()); 7039391bb9cSRapkiewicz, Pawel if (error_code) { 7049391bb9cSRapkiewicz, Pawel // Something wrong on DBus, the error_code is not important at this 7059391bb9cSRapkiewicz, Pawel // moment, just return success=false, and empty output. Since size 7069391bb9cSRapkiewicz, Pawel // of vector may vary depending on information from Network Manager, 7079391bb9cSRapkiewicz, Pawel // and empty output could not be treated same way as error. 70855c7b7a2SEd Tanous callback(false, ifaceList); 7099391bb9cSRapkiewicz, Pawel return; 7109391bb9cSRapkiewicz, Pawel } 7119391bb9cSRapkiewicz, Pawel 7129391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7139391bb9cSRapkiewicz, Pawel for (auto &objpath : resp) { 7149391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7159391bb9cSRapkiewicz, Pawel for (auto &interface : objpath.second) { 7169391bb9cSRapkiewicz, Pawel // If interface is xyz.openbmc_project.Network.EthernetInterface, 7179391bb9cSRapkiewicz, Pawel // this is what we're looking for. 7189391bb9cSRapkiewicz, Pawel if (interface.first == 7199391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface") { 720*a434f2bdSEd Tanous // Cut out everything until last "/", ... 72155c7b7a2SEd Tanous const std::string &ifaceId = 722daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first); 72355c7b7a2SEd Tanous std::size_t lastPos = ifaceId.rfind("/"); 72455c7b7a2SEd Tanous if (lastPos != std::string::npos) { 7259391bb9cSRapkiewicz, Pawel // and put it into output vector. 72655c7b7a2SEd Tanous ifaceList.emplace_back(ifaceId.substr(lastPos + 1)); 7279391bb9cSRapkiewicz, Pawel } 7289391bb9cSRapkiewicz, Pawel } 7299391bb9cSRapkiewicz, Pawel } 7309391bb9cSRapkiewicz, Pawel } 731*a434f2bdSEd Tanous // Finally make a callback with useful data 73255c7b7a2SEd Tanous callback(true, ifaceList); 7339391bb9cSRapkiewicz, Pawel }, 734aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 735aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7369391bb9cSRapkiewicz, Pawel }; 7379391bb9cSRapkiewicz, Pawel }; 7389391bb9cSRapkiewicz, Pawel 7399391bb9cSRapkiewicz, Pawel /** 7409391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7419391bb9cSRapkiewicz, Pawel */ 7429391bb9cSRapkiewicz, Pawel class EthernetCollection : public Node { 7439391bb9cSRapkiewicz, Pawel public: 7449391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 7459391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 7469391bb9cSRapkiewicz, Pawel // GetSubroutes method 7479391bb9cSRapkiewicz, Pawel EthernetCollection(CrowApp &app) 7489391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") { 7499391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7509391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7519391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7529391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7539391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7549391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces"; 7559391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7569391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7579391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7589391bb9cSRapkiewicz, Pawel 759588c3f0dSKowalski, Kamil entityPrivileges = { 760588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 761e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 762e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 763e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 764e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 765e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7669391bb9cSRapkiewicz, Pawel } 7679391bb9cSRapkiewicz, Pawel 7689391bb9cSRapkiewicz, Pawel private: 7699391bb9cSRapkiewicz, Pawel /** 7709391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7719391bb9cSRapkiewicz, Pawel */ 77255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7739391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 7749391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 7759391bb9cSRapkiewicz, Pawel // any Manager, not only hardcoded 'openbmc'. 77655c7b7a2SEd Tanous std::string managerId = "openbmc"; 7779391bb9cSRapkiewicz, Pawel 77855c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 779*a434f2bdSEd Tanous ethernetProvider.getEthernetIfaceList( 780*a434f2bdSEd Tanous [&, managerId{std::move(managerId)}]( 7819391bb9cSRapkiewicz, Pawel const bool &success, const std::vector<std::string> &iface_list) { 7829391bb9cSRapkiewicz, Pawel if (success) { 78355c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 78455c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 78555c7b7a2SEd Tanous ifaceArray.push_back( 78655c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + managerId + 78755c7b7a2SEd Tanous "/EthernetInterfaces/" + ifaceItem}}); 7889391bb9cSRapkiewicz, Pawel } 78955c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 79055c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 7919391bb9cSRapkiewicz, Pawel Node::json["@odata.id"] = 79255c7b7a2SEd Tanous "/redfish/v1/Managers/" + managerId + "/EthernetInterfaces"; 79355c7b7a2SEd Tanous res.jsonValue = Node::json; 7949391bb9cSRapkiewicz, Pawel } else { 7959391bb9cSRapkiewicz, Pawel // No success, best what we can do is return INTERNALL ERROR 796e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 7979391bb9cSRapkiewicz, Pawel } 7989391bb9cSRapkiewicz, Pawel res.end(); 7999391bb9cSRapkiewicz, Pawel }); 8009391bb9cSRapkiewicz, Pawel } 8019391bb9cSRapkiewicz, Pawel 8029391bb9cSRapkiewicz, Pawel // Ethernet Provider object 8039391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 80455c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 8059391bb9cSRapkiewicz, Pawel }; 8069391bb9cSRapkiewicz, Pawel 8079391bb9cSRapkiewicz, Pawel /** 8089391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8099391bb9cSRapkiewicz, Pawel */ 8109391bb9cSRapkiewicz, Pawel class EthernetInterface : public Node { 8119391bb9cSRapkiewicz, Pawel public: 8129391bb9cSRapkiewicz, Pawel /* 8139391bb9cSRapkiewicz, Pawel * Default Constructor 8149391bb9cSRapkiewicz, Pawel */ 8159391bb9cSRapkiewicz, Pawel // TODO(Pawel) Remove line from below, where we assume that there is only one 8169391bb9cSRapkiewicz, Pawel // manager called openbmc This shall be generic, but requires to update 8179391bb9cSRapkiewicz, Pawel // GetSubroutes method 8189391bb9cSRapkiewicz, Pawel EthernetInterface(CrowApp &app) 8199391bb9cSRapkiewicz, Pawel : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/", 8209391bb9cSRapkiewicz, Pawel std::string()) { 8219391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface"; 8229391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8239391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8249391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8259391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8269391bb9cSRapkiewicz, Pawel 827588c3f0dSKowalski, Kamil entityPrivileges = { 828588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 829e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 830e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 831e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 832e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 833e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8349391bb9cSRapkiewicz, Pawel } 8359391bb9cSRapkiewicz, Pawel 836e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 837e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 838e439f0f8SKowalski, Kamil const nlohmann::json &input, 839588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 840e439f0f8SKowalski, Kamil const std::string &pathPrefix, 841588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 842588c3f0dSKowalski, Kamil if (!input.is_object()) { 843588c3f0dSKowalski, Kamil messages::addMessageToJson( 84455c7b7a2SEd Tanous asyncResp->res.jsonValue, 845e439f0f8SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "VLAN"), pathPrefix); 846588c3f0dSKowalski, Kamil return; 847588c3f0dSKowalski, Kamil } 848588c3f0dSKowalski, Kamil 849e439f0f8SKowalski, Kamil const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix; 850e439f0f8SKowalski, Kamil nlohmann::json ¶msJson = 851e439f0f8SKowalski, Kamil (pathPrefix == "/") 85255c7b7a2SEd Tanous ? asyncResp->res.jsonValue 85355c7b7a2SEd Tanous : asyncResp->res.jsonValue[nlohmann::json_pointer<nlohmann::json>( 854e439f0f8SKowalski, Kamil pathPrefix)]; 855588c3f0dSKowalski, Kamil bool inputVlanEnabled; 856588c3f0dSKowalski, Kamil uint64_t inputVlanId; 857e439f0f8SKowalski, Kamil 858588c3f0dSKowalski, Kamil json_util::Result inputVlanEnabledState = json_util::getBool( 859588c3f0dSKowalski, Kamil "VLANEnable", input, inputVlanEnabled, 860588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 86155c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable")); 862588c3f0dSKowalski, Kamil json_util::Result inputVlanIdState = json_util::getUnsigned( 863588c3f0dSKowalski, Kamil "VLANId", input, inputVlanId, 864588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 86555c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANId")); 866588c3f0dSKowalski, Kamil bool inputInvalid = false; 867588c3f0dSKowalski, Kamil 868588c3f0dSKowalski, Kamil // Do not proceed if fields in VLAN object were of wrong type 869588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::WRONG_TYPE || 870588c3f0dSKowalski, Kamil inputVlanIdState == json_util::Result::WRONG_TYPE) { 871588c3f0dSKowalski, Kamil return; 872588c3f0dSKowalski, Kamil } 873588c3f0dSKowalski, Kamil 874588c3f0dSKowalski, Kamil // Verify input 87555c7b7a2SEd Tanous if (eth_data.vlanId == nullptr) { 876e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 877e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 87855c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 879588c3f0dSKowalski, Kamil messages::propertyMissing("VLANEnable"), 880e439f0f8SKowalski, Kamil pathPrefix); 881588c3f0dSKowalski, Kamil 882588c3f0dSKowalski, Kamil inputInvalid = true; 883588c3f0dSKowalski, Kamil } else { 884588c3f0dSKowalski, Kamil // Load actual data into field values if they were not provided 885588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::NOT_EXIST) { 886588c3f0dSKowalski, Kamil inputVlanEnabled = true; 887588c3f0dSKowalski, Kamil } 888588c3f0dSKowalski, Kamil 889588c3f0dSKowalski, Kamil if (inputVlanIdState == json_util::Result::NOT_EXIST) { 89055c7b7a2SEd Tanous inputVlanId = *eth_data.vlanId; 891588c3f0dSKowalski, Kamil } 892588c3f0dSKowalski, Kamil } 893588c3f0dSKowalski, Kamil 894588c3f0dSKowalski, Kamil // Do not proceed if input has not been valid 895588c3f0dSKowalski, Kamil if (inputInvalid) { 896588c3f0dSKowalski, Kamil return; 897588c3f0dSKowalski, Kamil } 898588c3f0dSKowalski, Kamil 899588c3f0dSKowalski, Kamil // VLAN is configured on the interface 90055c7b7a2SEd Tanous if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId) { 901588c3f0dSKowalski, Kamil // Change VLAN Id 902e439f0f8SKowalski, Kamil paramsJson["VLANId"] = inputVlanId; 903e439f0f8SKowalski, Kamil OnDemandEthernetProvider::changeVlanId( 904e439f0f8SKowalski, Kamil ifaceId, static_cast<uint32_t>(inputVlanId), 905e439f0f8SKowalski, Kamil [&, asyncResp, pathPrefx{std::move(pathPrefix)}]( 906e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 907588c3f0dSKowalski, Kamil if (ec) { 90855c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 909e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 910588c3f0dSKowalski, Kamil } else { 911e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = true; 912e439f0f8SKowalski, Kamil } 913e439f0f8SKowalski, Kamil }); 914e439f0f8SKowalski, Kamil } else if (inputVlanEnabled == false) { 915e439f0f8SKowalski, Kamil // Disable VLAN 916e439f0f8SKowalski, Kamil OnDemandEthernetProvider::disableVlan( 917e439f0f8SKowalski, Kamil ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)}]( 918e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 919e439f0f8SKowalski, Kamil if (ec) { 92055c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 921e439f0f8SKowalski, Kamil messages::internalError(), pathPrefix); 922e439f0f8SKowalski, Kamil } else { 923e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = false; 924588c3f0dSKowalski, Kamil } 925588c3f0dSKowalski, Kamil }); 926588c3f0dSKowalski, Kamil } 927588c3f0dSKowalski, Kamil } 928588c3f0dSKowalski, Kamil 929e439f0f8SKowalski, Kamil private: 930588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 931588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 932588c3f0dSKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 933588c3f0dSKowalski, Kamil if (input.is_string()) { 934588c3f0dSKowalski, Kamil std::string newHostname = input.get<std::string>(); 935588c3f0dSKowalski, Kamil 936588c3f0dSKowalski, Kamil if (eth_data.hostname == nullptr || newHostname != *eth_data.hostname) { 937588c3f0dSKowalski, Kamil // Change hostname 93855c7b7a2SEd Tanous ethernetProvider.setHostName( 939588c3f0dSKowalski, Kamil newHostname, 940588c3f0dSKowalski, Kamil [asyncResp, newHostname](const boost::system::error_code ec) { 941588c3f0dSKowalski, Kamil if (ec) { 94255c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 943588c3f0dSKowalski, Kamil messages::internalError(), 944588c3f0dSKowalski, Kamil "/HostName"); 945588c3f0dSKowalski, Kamil } else { 94655c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 947588c3f0dSKowalski, Kamil } 948588c3f0dSKowalski, Kamil }); 949588c3f0dSKowalski, Kamil } 950588c3f0dSKowalski, Kamil } else { 951588c3f0dSKowalski, Kamil messages::addMessageToJson( 95255c7b7a2SEd Tanous asyncResp->res.jsonValue, 953588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "HostName"), 954588c3f0dSKowalski, Kamil "/HostName"); 955588c3f0dSKowalski, Kamil } 956588c3f0dSKowalski, Kamil } 957588c3f0dSKowalski, Kamil 958179db1d7SKowalski, Kamil void handleIPv4Patch(const std::string &ifaceId, const nlohmann::json &input, 959179db1d7SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data, 960179db1d7SKowalski, Kamil const std::shared_ptr<AsyncResp> &asyncResp) { 961179db1d7SKowalski, Kamil if (!input.is_array()) { 962179db1d7SKowalski, Kamil messages::addMessageToJson( 96355c7b7a2SEd Tanous asyncResp->res.jsonValue, 964179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 965179db1d7SKowalski, Kamil "/IPv4Addresses"); 966179db1d7SKowalski, Kamil return; 967179db1d7SKowalski, Kamil } 968179db1d7SKowalski, Kamil 969179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 970179db1d7SKowalski, Kamil if (input.size() < ipv4_data.size()) { 971179db1d7SKowalski, Kamil // TODO(kkowalsk) This should be a message indicating that not enough 972179db1d7SKowalski, Kamil // data has been provided 97355c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 974179db1d7SKowalski, Kamil messages::internalError(), "/IPv4Addresses"); 975179db1d7SKowalski, Kamil return; 976179db1d7SKowalski, Kamil } 977179db1d7SKowalski, Kamil 978179db1d7SKowalski, Kamil json_util::Result addressFieldState; 979179db1d7SKowalski, Kamil json_util::Result subnetMaskFieldState; 980179db1d7SKowalski, Kamil json_util::Result addressOriginFieldState; 981179db1d7SKowalski, Kamil json_util::Result gatewayFieldState; 982179db1d7SKowalski, Kamil const std::string *addressFieldValue; 983179db1d7SKowalski, Kamil const std::string *subnetMaskFieldValue; 984179db1d7SKowalski, Kamil const std::string *addressOriginFieldValue = nullptr; 985179db1d7SKowalski, Kamil const std::string *gatewayFieldValue; 986179db1d7SKowalski, Kamil uint8_t subnetMaskAsPrefixLength; 987179db1d7SKowalski, Kamil std::string addressOriginInDBusFormat; 988179db1d7SKowalski, Kamil 989179db1d7SKowalski, Kamil bool errorDetected = false; 990179db1d7SKowalski, Kamil for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) { 991179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 992179db1d7SKowalski, Kamil if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) { 993179db1d7SKowalski, Kamil // Invalid object type 994179db1d7SKowalski, Kamil messages::addMessageToJson( 99555c7b7a2SEd Tanous asyncResp->res.jsonValue, 996179db1d7SKowalski, Kamil messages::propertyValueTypeError(input[entryIdx].dump(), 997179db1d7SKowalski, Kamil "IPv4Address"), 998179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx)); 999179db1d7SKowalski, Kamil 1000179db1d7SKowalski, Kamil continue; 1001179db1d7SKowalski, Kamil } 1002179db1d7SKowalski, Kamil 1003179db1d7SKowalski, Kamil // Try to load fields 1004179db1d7SKowalski, Kamil addressFieldState = json_util::getString( 1005179db1d7SKowalski, Kamil "Address", input[entryIdx], addressFieldValue, 1006179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 100755c7b7a2SEd Tanous asyncResp->res.jsonValue, 1008179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1009179db1d7SKowalski, Kamil subnetMaskFieldState = json_util::getString( 1010179db1d7SKowalski, Kamil "SubnetMask", input[entryIdx], subnetMaskFieldValue, 1011179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 101255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1013179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1014179db1d7SKowalski, Kamil addressOriginFieldState = json_util::getString( 1015179db1d7SKowalski, Kamil "AddressOrigin", input[entryIdx], addressOriginFieldValue, 1016179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 101755c7b7a2SEd Tanous asyncResp->res.jsonValue, 1018179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1019179db1d7SKowalski, Kamil gatewayFieldState = json_util::getString( 1020179db1d7SKowalski, Kamil "Gateway", input[entryIdx], gatewayFieldValue, 1021179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 102255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1023179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1024179db1d7SKowalski, Kamil 1025179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::WRONG_TYPE || 1026179db1d7SKowalski, Kamil subnetMaskFieldState == json_util::Result::WRONG_TYPE || 1027179db1d7SKowalski, Kamil addressOriginFieldState == json_util::Result::WRONG_TYPE || 1028179db1d7SKowalski, Kamil gatewayFieldState == json_util::Result::WRONG_TYPE) { 1029179db1d7SKowalski, Kamil return; 1030179db1d7SKowalski, Kamil } 1031179db1d7SKowalski, Kamil 1032179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 103355c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount(*addressFieldValue)) { 1034179db1d7SKowalski, Kamil errorDetected = true; 1035179db1d7SKowalski, Kamil messages::addMessageToJson( 103655c7b7a2SEd Tanous asyncResp->res.jsonValue, 1037179db1d7SKowalski, Kamil messages::propertyValueFormatError(*addressFieldValue, "Address"), 1038179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1039179db1d7SKowalski, Kamil } 1040179db1d7SKowalski, Kamil 1041179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 104255c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount( 1043179db1d7SKowalski, Kamil *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) { 1044179db1d7SKowalski, Kamil errorDetected = true; 1045179db1d7SKowalski, Kamil messages::addMessageToJson( 104655c7b7a2SEd Tanous asyncResp->res.jsonValue, 1047179db1d7SKowalski, Kamil messages::propertyValueFormatError(*subnetMaskFieldValue, 1048179db1d7SKowalski, Kamil "SubnetMask"), 1049179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1050179db1d7SKowalski, Kamil } 1051179db1d7SKowalski, Kamil 105255c7b7a2SEd Tanous // get Address origin in proper format 1053179db1d7SKowalski, Kamil addressOriginInDBusFormat = 105455c7b7a2SEd Tanous ethernetProvider.translateAddressOriginBetweenDBusAndRedfish( 1055179db1d7SKowalski, Kamil addressOriginFieldValue, true, false); 1056179db1d7SKowalski, Kamil 1057179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1058179db1d7SKowalski, Kamil addressOriginInDBusFormat.empty()) { 1059179db1d7SKowalski, Kamil errorDetected = true; 1060179db1d7SKowalski, Kamil messages::addMessageToJson( 106155c7b7a2SEd Tanous asyncResp->res.jsonValue, 1062179db1d7SKowalski, Kamil messages::propertyValueNotInList(*addressOriginFieldValue, 1063179db1d7SKowalski, Kamil "AddressOrigin"), 1064179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1065179db1d7SKowalski, Kamil } 1066179db1d7SKowalski, Kamil 1067179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 106855c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount(*gatewayFieldValue)) { 1069179db1d7SKowalski, Kamil errorDetected = true; 1070179db1d7SKowalski, Kamil messages::addMessageToJson( 107155c7b7a2SEd Tanous asyncResp->res.jsonValue, 1072179db1d7SKowalski, Kamil messages::propertyValueFormatError(*gatewayFieldValue, "Gateway"), 1073179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1074179db1d7SKowalski, Kamil } 1075179db1d7SKowalski, Kamil 1076179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1077179db1d7SKowalski, Kamil // end loop 1078179db1d7SKowalski, Kamil if (errorDetected) { 1079179db1d7SKowalski, Kamil errorDetected = false; 1080179db1d7SKowalski, Kamil continue; 1081179db1d7SKowalski, Kamil } 1082179db1d7SKowalski, Kamil 1083179db1d7SKowalski, Kamil if (entryIdx >= ipv4_data.size()) { 108455c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = input[entryIdx]; 1085179db1d7SKowalski, Kamil 1086179db1d7SKowalski, Kamil // Verify that all field were provided 1087179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::NOT_EXIST) { 1088179db1d7SKowalski, Kamil errorDetected = true; 1089179db1d7SKowalski, Kamil messages::addMessageToJson( 109055c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("Address"), 1091179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1092179db1d7SKowalski, Kamil } 1093179db1d7SKowalski, Kamil 1094179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::NOT_EXIST) { 1095179db1d7SKowalski, Kamil errorDetected = true; 1096179db1d7SKowalski, Kamil messages::addMessageToJson( 109755c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("SubnetMask"), 1098179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1099179db1d7SKowalski, Kamil } 1100179db1d7SKowalski, Kamil 1101179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::NOT_EXIST) { 1102179db1d7SKowalski, Kamil errorDetected = true; 1103179db1d7SKowalski, Kamil messages::addMessageToJson( 110455c7b7a2SEd Tanous asyncResp->res.jsonValue, 1105179db1d7SKowalski, Kamil messages::propertyMissing("AddressOrigin"), 1106179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin"); 1107179db1d7SKowalski, Kamil } 1108179db1d7SKowalski, Kamil 1109179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::NOT_EXIST) { 1110179db1d7SKowalski, Kamil errorDetected = true; 1111179db1d7SKowalski, Kamil messages::addMessageToJson( 111255c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::propertyMissing("Gateway"), 1113179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1114179db1d7SKowalski, Kamil } 1115179db1d7SKowalski, Kamil 1116179db1d7SKowalski, Kamil // If any error occured do not proceed with current entry, but do not 1117179db1d7SKowalski, Kamil // end loop 1118179db1d7SKowalski, Kamil if (errorDetected) { 1119179db1d7SKowalski, Kamil errorDetected = false; 1120179db1d7SKowalski, Kamil continue; 1121179db1d7SKowalski, Kamil } 1122179db1d7SKowalski, Kamil 1123179db1d7SKowalski, Kamil // Create IPv4 with provided data 112455c7b7a2SEd Tanous ethernetProvider.createIPv4(ifaceId, entryIdx, subnetMaskAsPrefixLength, 112555c7b7a2SEd Tanous *gatewayFieldValue, *addressFieldValue, 112655c7b7a2SEd Tanous asyncResp); 1127179db1d7SKowalski, Kamil } else { 1128179db1d7SKowalski, Kamil // Existing object that should be modified/deleted/remain unchanged 1129179db1d7SKowalski, Kamil if (input[entryIdx].is_null()) { 1130179db1d7SKowalski, Kamil // Object should be deleted 113155c7b7a2SEd Tanous ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, entryIdx, 113255c7b7a2SEd Tanous asyncResp); 1133179db1d7SKowalski, Kamil } else if (input[entryIdx].is_object()) { 1134179db1d7SKowalski, Kamil if (input[entryIdx].size() == 0) { 1135179db1d7SKowalski, Kamil // Object shall remain unchanged 1136179db1d7SKowalski, Kamil continue; 1137179db1d7SKowalski, Kamil } 1138179db1d7SKowalski, Kamil 1139179db1d7SKowalski, Kamil // Apply changes 1140179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1141179db1d7SKowalski, Kamil ipv4_data[entryIdx].address != nullptr && 1142179db1d7SKowalski, Kamil *ipv4_data[entryIdx].address != *addressFieldValue) { 114355c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1144179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Address", 1145179db1d7SKowalski, Kamil *addressFieldValue, asyncResp); 1146179db1d7SKowalski, Kamil } 1147179db1d7SKowalski, Kamil 1148179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1149179db1d7SKowalski, Kamil ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) { 115055c7b7a2SEd Tanous ethernetProvider.changeIPv4SubnetMaskProperty( 1151179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1152179db1d7SKowalski, Kamil *subnetMaskFieldValue, subnetMaskAsPrefixLength, asyncResp); 1153179db1d7SKowalski, Kamil } 1154179db1d7SKowalski, Kamil 1155179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1156179db1d7SKowalski, Kamil ipv4_data[entryIdx].origin != *addressFieldValue) { 115755c7b7a2SEd Tanous ethernetProvider.changeIPv4Origin( 1158179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1159179db1d7SKowalski, Kamil *addressOriginFieldValue, addressOriginInDBusFormat, asyncResp); 1160179db1d7SKowalski, Kamil } 1161179db1d7SKowalski, Kamil 1162179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1163179db1d7SKowalski, Kamil ipv4_data[entryIdx].gateway != nullptr && 1164179db1d7SKowalski, Kamil *ipv4_data[entryIdx].gateway != *gatewayFieldValue) { 116555c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1166179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, "Gateway", 1167179db1d7SKowalski, Kamil *gatewayFieldValue, asyncResp); 1168179db1d7SKowalski, Kamil } 1169179db1d7SKowalski, Kamil } 1170179db1d7SKowalski, Kamil } 1171179db1d7SKowalski, Kamil } 1172179db1d7SKowalski, Kamil } 1173179db1d7SKowalski, Kamil 1174588c3f0dSKowalski, Kamil nlohmann::json parseInterfaceData( 117555c7b7a2SEd Tanous const std::string &ifaceId, const EthernetInterfaceData ð_data, 1176588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1177588c3f0dSKowalski, Kamil // Copy JSON object to avoid race condition 117855c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1179588c3f0dSKowalski, Kamil 1180588c3f0dSKowalski, Kamil // Fill out obvious data... 118155c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 118255c7b7a2SEd Tanous jsonResponse["@odata.id"] = 118355c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId; 1184588c3f0dSKowalski, Kamil 1185588c3f0dSKowalski, Kamil // ... then the one from DBus, regarding eth iface... 118655c7b7a2SEd Tanous if (eth_data.speed != nullptr) jsonResponse["SpeedMbps"] = *eth_data.speed; 1187588c3f0dSKowalski, Kamil 118855c7b7a2SEd Tanous if (eth_data.macAddress != nullptr) 118955c7b7a2SEd Tanous jsonResponse["MACAddress"] = *eth_data.macAddress; 1190588c3f0dSKowalski, Kamil 1191588c3f0dSKowalski, Kamil if (eth_data.hostname != nullptr) 119255c7b7a2SEd Tanous jsonResponse["HostName"] = *eth_data.hostname; 1193588c3f0dSKowalski, Kamil 119455c7b7a2SEd Tanous if (eth_data.vlanId != nullptr) { 119555c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLAN"]; 1196588c3f0dSKowalski, Kamil vlanObj["VLANEnable"] = true; 119755c7b7a2SEd Tanous vlanObj["VLANId"] = *eth_data.vlanId; 1198eb547730SKowalski, Kamil } else { 119955c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLANs"]; 1200eb547730SKowalski, Kamil vlanObj["@odata.id"] = 120155c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId + 1202eb547730SKowalski, Kamil "/VLANs"; 1203588c3f0dSKowalski, Kamil } 1204588c3f0dSKowalski, Kamil 1205588c3f0dSKowalski, Kamil // ... at last, check if there are IPv4 data and prepare appropriate 1206588c3f0dSKowalski, Kamil // collection 1207588c3f0dSKowalski, Kamil if (ipv4_data.size() > 0) { 120855c7b7a2SEd Tanous nlohmann::json ipv4Array = nlohmann::json::array(); 120955c7b7a2SEd Tanous for (auto &ipv4Config : ipv4_data) { 121055c7b7a2SEd Tanous nlohmann::json jsonIpv4; 121155c7b7a2SEd Tanous if (ipv4Config.address != nullptr) { 121255c7b7a2SEd Tanous jsonIpv4["Address"] = *ipv4Config.address; 121355c7b7a2SEd Tanous if (ipv4Config.gateway != nullptr) 121455c7b7a2SEd Tanous jsonIpv4["Gateway"] = *ipv4Config.gateway; 1215588c3f0dSKowalski, Kamil 121655c7b7a2SEd Tanous jsonIpv4["AddressOrigin"] = ipv4Config.origin; 121755c7b7a2SEd Tanous jsonIpv4["SubnetMask"] = ipv4Config.netmask; 1218588c3f0dSKowalski, Kamil 121955c7b7a2SEd Tanous ipv4Array.push_back(std::move(jsonIpv4)); 1220588c3f0dSKowalski, Kamil } 1221588c3f0dSKowalski, Kamil } 122255c7b7a2SEd Tanous jsonResponse["IPv4Addresses"] = std::move(ipv4Array); 1223588c3f0dSKowalski, Kamil } 1224588c3f0dSKowalski, Kamil 122555c7b7a2SEd Tanous return jsonResponse; 1226588c3f0dSKowalski, Kamil } 1227588c3f0dSKowalski, Kamil 12289391bb9cSRapkiewicz, Pawel /** 12299391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12309391bb9cSRapkiewicz, Pawel */ 123155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12329391bb9cSRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 12339391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call (two params) to get 12349391bb9cSRapkiewicz, Pawel // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 12359391bb9cSRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 12369391bb9cSRapkiewicz, Pawel // impossible. 12379391bb9cSRapkiewicz, Pawel if (params.size() != 1) { 1238e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 12399391bb9cSRapkiewicz, Pawel res.end(); 12409391bb9cSRapkiewicz, Pawel return; 12419391bb9cSRapkiewicz, Pawel } 12429391bb9cSRapkiewicz, Pawel 124355c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 12449391bb9cSRapkiewicz, Pawel 124555c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 12469391bb9cSRapkiewicz, Pawel // preparation 124755c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 124855c7b7a2SEd Tanous ifaceId, 124955c7b7a2SEd Tanous [&, ifaceId](const bool &success, const EthernetInterfaceData ð_data, 12509391bb9cSRapkiewicz, Pawel const std::vector<IPv4AddressData> &ipv4_data) { 12519391bb9cSRapkiewicz, Pawel if (success) { 125255c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data); 12539391bb9cSRapkiewicz, Pawel } else { 12549391bb9cSRapkiewicz, Pawel // ... otherwise return error 12559391bb9cSRapkiewicz, Pawel // TODO(Pawel)consider distinguish between non existing object, and 12569391bb9cSRapkiewicz, Pawel // other errors 1257e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 125855c7b7a2SEd Tanous res.jsonValue, 125955c7b7a2SEd Tanous messages::resourceNotFound("EthernetInterface", ifaceId)); 1260e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 12619391bb9cSRapkiewicz, Pawel } 12629391bb9cSRapkiewicz, Pawel res.end(); 12639391bb9cSRapkiewicz, Pawel }); 12649391bb9cSRapkiewicz, Pawel } 12659391bb9cSRapkiewicz, Pawel 126655c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1267588c3f0dSKowalski, Kamil const std::vector<std::string> ¶ms) override { 1268588c3f0dSKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1269588c3f0dSKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1270588c3f0dSKowalski, Kamil // Check if there is required param, truly entering this shall be 1271588c3f0dSKowalski, Kamil // impossible. 1272588c3f0dSKowalski, Kamil if (params.size() != 1) { 1273588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1274588c3f0dSKowalski, Kamil res.end(); 1275588c3f0dSKowalski, Kamil return; 1276588c3f0dSKowalski, Kamil } 1277588c3f0dSKowalski, Kamil 127855c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 1279588c3f0dSKowalski, Kamil 1280179db1d7SKowalski, Kamil nlohmann::json patchReq; 1281588c3f0dSKowalski, Kamil 1282179db1d7SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1283588c3f0dSKowalski, Kamil return; 1284588c3f0dSKowalski, Kamil } 1285588c3f0dSKowalski, Kamil 128655c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 1287588c3f0dSKowalski, Kamil // preparation 128855c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 128955c7b7a2SEd Tanous ifaceId, [&, ifaceId, patchReq = std::move(patchReq)]( 1290588c3f0dSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1291588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1292588c3f0dSKowalski, Kamil if (!success) { 1293588c3f0dSKowalski, Kamil // ... otherwise return error 1294588c3f0dSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1295588c3f0dSKowalski, Kamil // other errors 1296927a505aSKowalski, Kamil messages::addMessageToErrorJson( 129755c7b7a2SEd Tanous res.jsonValue, 129855c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1299588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1300588c3f0dSKowalski, Kamil res.end(); 1301588c3f0dSKowalski, Kamil 1302588c3f0dSKowalski, Kamil return; 1303588c3f0dSKowalski, Kamil } 1304588c3f0dSKowalski, Kamil 130555c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data); 1306588c3f0dSKowalski, Kamil 1307588c3f0dSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1308588c3f0dSKowalski, Kamil std::make_shared<AsyncResp>(res); 1309588c3f0dSKowalski, Kamil 1310588c3f0dSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1311588c3f0dSKowalski, Kamil ++propertyIt) { 1312588c3f0dSKowalski, Kamil if (propertyIt.key() == "VLAN") { 131355c7b7a2SEd Tanous handleVlanPatch(ifaceId, propertyIt.value(), eth_data, "/VLAN", 1314588c3f0dSKowalski, Kamil asyncResp); 1315588c3f0dSKowalski, Kamil } else if (propertyIt.key() == "HostName") { 1316588c3f0dSKowalski, Kamil handleHostnamePatch(propertyIt.value(), eth_data, asyncResp); 1317179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv4Addresses") { 131855c7b7a2SEd Tanous handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data, 1319179db1d7SKowalski, Kamil asyncResp); 1320179db1d7SKowalski, Kamil } else if (propertyIt.key() == "IPv6Addresses") { 1321179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1322179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 132355c7b7a2SEd Tanous res.jsonValue, 1324179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1325588c3f0dSKowalski, Kamil } else { 132655c7b7a2SEd Tanous auto fieldInJsonIt = res.jsonValue.find(propertyIt.key()); 1327588c3f0dSKowalski, Kamil 132855c7b7a2SEd Tanous if (fieldInJsonIt == res.jsonValue.end()) { 1329588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1330588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 133155c7b7a2SEd Tanous res.jsonValue, messages::propertyUnknown(propertyIt.key())); 1332588c3f0dSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1333588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1334588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 133555c7b7a2SEd Tanous res.jsonValue, 1336588c3f0dSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1337588c3f0dSKowalski, Kamil } 1338588c3f0dSKowalski, Kamil } 1339588c3f0dSKowalski, Kamil } 1340588c3f0dSKowalski, Kamil }); 1341588c3f0dSKowalski, Kamil } 1342588c3f0dSKowalski, Kamil 13439391bb9cSRapkiewicz, Pawel // Ethernet Provider object 13449391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 134555c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 13469391bb9cSRapkiewicz, Pawel }; 13479391bb9cSRapkiewicz, Pawel 1348e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection; 1349e439f0f8SKowalski, Kamil 1350e439f0f8SKowalski, Kamil /** 1351e439f0f8SKowalski, Kamil * VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema 1352e439f0f8SKowalski, Kamil */ 1353e439f0f8SKowalski, Kamil class VlanNetworkInterface : public Node { 1354e439f0f8SKowalski, Kamil public: 1355e439f0f8SKowalski, Kamil /* 1356e439f0f8SKowalski, Kamil * Default Constructor 1357e439f0f8SKowalski, Kamil */ 1358e439f0f8SKowalski, Kamil template <typename CrowApp> 1359e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1360e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1361e439f0f8SKowalski, Kamil // GetSubroutes method 1362e439f0f8SKowalski, Kamil VlanNetworkInterface(CrowApp &app) 1363eb547730SKowalski, Kamil : Node( 1364eb547730SKowalski, Kamil app, 1365eb547730SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/<str>", 1366e439f0f8SKowalski, Kamil std::string(), std::string()) { 1367e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1368e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1369e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1370e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1371e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1372e439f0f8SKowalski, Kamil 1373e439f0f8SKowalski, Kamil entityPrivileges = { 1374e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1375e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1376e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1377e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1378e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1379e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1380e439f0f8SKowalski, Kamil } 1381e439f0f8SKowalski, Kamil 1382e439f0f8SKowalski, Kamil private: 1383e439f0f8SKowalski, Kamil nlohmann::json parseInterfaceData( 138455c7b7a2SEd Tanous const std::string &parent_ifaceId, const std::string &ifaceId, 1385e439f0f8SKowalski, Kamil const EthernetInterfaceData ð_data, 1386e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1387e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 138855c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1389e439f0f8SKowalski, Kamil 1390e439f0f8SKowalski, Kamil // Fill out obvious data... 139155c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 139255c7b7a2SEd Tanous jsonResponse["@odata.id"] = 139355c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + parent_ifaceId + 139455c7b7a2SEd Tanous "/VLANs/" + ifaceId; 1395e439f0f8SKowalski, Kamil 139655c7b7a2SEd Tanous jsonResponse["VLANEnable"] = true; 139755c7b7a2SEd Tanous jsonResponse["VLANId"] = *eth_data.vlanId; 1398e439f0f8SKowalski, Kamil 139955c7b7a2SEd Tanous return jsonResponse; 1400e439f0f8SKowalski, Kamil } 1401e439f0f8SKowalski, Kamil 140255c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 1403927a505aSKowalski, Kamil const std::string &iface) { 1404927a505aSKowalski, Kamil if (!boost::starts_with(iface, parent + "_")) { 1405927a505aSKowalski, Kamil messages::addMessageToErrorJson( 140655c7b7a2SEd Tanous res.jsonValue, 1407927a505aSKowalski, Kamil messages::resourceNotFound("VLAN Network Interface", iface)); 1408927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1409927a505aSKowalski, Kamil res.end(); 1410927a505aSKowalski, Kamil 1411927a505aSKowalski, Kamil return false; 1412927a505aSKowalski, Kamil } else { 1413927a505aSKowalski, Kamil return true; 1414927a505aSKowalski, Kamil } 1415927a505aSKowalski, Kamil } 1416927a505aSKowalski, Kamil 1417e439f0f8SKowalski, Kamil /** 1418e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1419e439f0f8SKowalski, Kamil */ 142055c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1421e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1422e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1423e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1424e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1425e439f0f8SKowalski, Kamil // impossible. 1426e439f0f8SKowalski, Kamil if (params.size() != 2) { 1427e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1428e439f0f8SKowalski, Kamil res.end(); 1429e439f0f8SKowalski, Kamil return; 1430e439f0f8SKowalski, Kamil } 1431e439f0f8SKowalski, Kamil 143255c7b7a2SEd Tanous const std::string &parentIfaceId = params[0]; 143355c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1434e439f0f8SKowalski, Kamil 1435*a434f2bdSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) { 1436*a434f2bdSEd Tanous return; 1437*a434f2bdSEd Tanous } 1438*a434f2bdSEd Tanous 1439e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1440e439f0f8SKowalski, Kamil // preparation 144155c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1442*a434f2bdSEd Tanous ifaceId, [&, parentIfaceId, ifaceId]( 1443e439f0f8SKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1444e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 144555c7b7a2SEd Tanous if (success && eth_data.vlanId != nullptr) { 1446*a434f2bdSEd Tanous res.jsonValue = 1447*a434f2bdSEd Tanous parseInterfaceData(parentIfaceId, ifaceId, eth_data, ipv4_data); 1448e439f0f8SKowalski, Kamil } else { 1449e439f0f8SKowalski, Kamil // ... otherwise return error 1450eb547730SKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, and 1451e439f0f8SKowalski, Kamil // other errors 1452927a505aSKowalski, Kamil messages::addMessageToErrorJson( 145355c7b7a2SEd Tanous res.jsonValue, 145455c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1455e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1456e439f0f8SKowalski, Kamil } 1457e439f0f8SKowalski, Kamil res.end(); 1458e439f0f8SKowalski, Kamil }); 1459e439f0f8SKowalski, Kamil } 1460e439f0f8SKowalski, Kamil 146155c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1462e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1463e439f0f8SKowalski, Kamil if (params.size() != 2) { 1464e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1465e439f0f8SKowalski, Kamil res.end(); 1466e439f0f8SKowalski, Kamil return; 1467e439f0f8SKowalski, Kamil } 1468e439f0f8SKowalski, Kamil 146955c7b7a2SEd Tanous const std::string &parent_ifaceId = params[0]; 147055c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1471927a505aSKowalski, Kamil 147255c7b7a2SEd Tanous if (!verifyNames(res, parent_ifaceId, ifaceId)) { 1473927a505aSKowalski, Kamil return; 1474927a505aSKowalski, Kamil } 1475927a505aSKowalski, Kamil 1476927a505aSKowalski, Kamil nlohmann::json patchReq; 1477927a505aSKowalski, Kamil 1478927a505aSKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, patchReq)) { 1479927a505aSKowalski, Kamil return; 1480927a505aSKowalski, Kamil } 1481927a505aSKowalski, Kamil 1482927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1483927a505aSKowalski, Kamil // preparation 148455c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1485*a434f2bdSEd Tanous ifaceId, [&, parent_ifaceId, ifaceId, patchReq = std::move(patchReq)]( 1486927a505aSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1487927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1488927a505aSKowalski, Kamil if (!success) { 1489927a505aSKowalski, Kamil // ... otherwise return error 1490927a505aSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1491927a505aSKowalski, Kamil // and 1492927a505aSKowalski, Kamil // other errors 1493927a505aSKowalski, Kamil messages::addMessageToErrorJson( 149455c7b7a2SEd Tanous res.jsonValue, 149555c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1496927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1497e439f0f8SKowalski, Kamil res.end(); 1498927a505aSKowalski, Kamil 1499927a505aSKowalski, Kamil return; 1500927a505aSKowalski, Kamil } 1501927a505aSKowalski, Kamil 1502*a434f2bdSEd Tanous res.jsonValue = 1503*a434f2bdSEd Tanous parseInterfaceData(parent_ifaceId, ifaceId, eth_data, ipv4_data); 1504927a505aSKowalski, Kamil 1505927a505aSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1506927a505aSKowalski, Kamil std::make_shared<AsyncResp>(res); 1507927a505aSKowalski, Kamil 1508927a505aSKowalski, Kamil for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end(); 1509927a505aSKowalski, Kamil ++propertyIt) { 1510927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 1511927a505aSKowalski, Kamil propertyIt.key() != "VLANId") { 151255c7b7a2SEd Tanous auto fieldInJsonIt = res.jsonValue.find(propertyIt.key()); 1513927a505aSKowalski, Kamil 151455c7b7a2SEd Tanous if (fieldInJsonIt == res.jsonValue.end()) { 1515927a505aSKowalski, Kamil // Field not in scope of defined fields 1516927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1517*a434f2bdSEd Tanous res.jsonValue, messages::propertyUnknown(propertyIt.key())); 1518927a505aSKowalski, Kamil } else if (*fieldInJsonIt != *propertyIt) { 1519927a505aSKowalski, Kamil // User attempted to modify non-writable field 1520927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 152155c7b7a2SEd Tanous res.jsonValue, 1522927a505aSKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1523927a505aSKowalski, Kamil } 1524927a505aSKowalski, Kamil } 1525927a505aSKowalski, Kamil } 1526927a505aSKowalski, Kamil 152755c7b7a2SEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data, "/", 1528927a505aSKowalski, Kamil asyncResp); 1529927a505aSKowalski, Kamil }); 1530e439f0f8SKowalski, Kamil } 1531e439f0f8SKowalski, Kamil 153255c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 1533e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1534e439f0f8SKowalski, Kamil if (params.size() != 2) { 1535e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1536e439f0f8SKowalski, Kamil res.end(); 1537e439f0f8SKowalski, Kamil return; 1538e439f0f8SKowalski, Kamil } 1539e439f0f8SKowalski, Kamil 154055c7b7a2SEd Tanous const std::string &parent_ifaceId = params[0]; 154155c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1542927a505aSKowalski, Kamil 154355c7b7a2SEd Tanous if (!verifyNames(res, parent_ifaceId, ifaceId)) { 1544927a505aSKowalski, Kamil return; 1545927a505aSKowalski, Kamil } 1546927a505aSKowalski, Kamil 1547927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1548927a505aSKowalski, Kamil // preparation 154955c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1550*a434f2bdSEd Tanous ifaceId, [&, parent_ifaceId, ifaceId]( 1551927a505aSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1552927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 155355c7b7a2SEd Tanous if (success && eth_data.vlanId != nullptr) { 155455c7b7a2SEd Tanous res.jsonValue = parseInterfaceData(parent_ifaceId, ifaceId, 1555927a505aSKowalski, Kamil eth_data, ipv4_data); 1556927a505aSKowalski, Kamil 1557927a505aSKowalski, Kamil // Disable VLAN 1558927a505aSKowalski, Kamil OnDemandEthernetProvider::disableVlan( 155955c7b7a2SEd Tanous ifaceId, [&](const boost::system::error_code ec) { 1560927a505aSKowalski, Kamil if (ec) { 156155c7b7a2SEd Tanous res.jsonValue = nlohmann::json::object(); 156255c7b7a2SEd Tanous messages::addMessageToErrorJson(res.jsonValue, 1563927a505aSKowalski, Kamil messages::internalError()); 1564927a505aSKowalski, Kamil res.result( 1565927a505aSKowalski, Kamil boost::beast::http::status::internal_server_error); 1566927a505aSKowalski, Kamil } 1567e439f0f8SKowalski, Kamil res.end(); 1568927a505aSKowalski, Kamil }); 1569927a505aSKowalski, Kamil } else { 1570927a505aSKowalski, Kamil // ... otherwise return error 1571927a505aSKowalski, Kamil // TODO(Pawel)consider distinguish between non existing object, 1572927a505aSKowalski, Kamil // and 1573927a505aSKowalski, Kamil // other errors 1574927a505aSKowalski, Kamil messages::addMessageToErrorJson( 157555c7b7a2SEd Tanous res.jsonValue, 157655c7b7a2SEd Tanous messages::resourceNotFound("VLAN Network Interface", ifaceId)); 1577927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1578927a505aSKowalski, Kamil res.end(); 1579927a505aSKowalski, Kamil } 1580927a505aSKowalski, Kamil }); 1581e439f0f8SKowalski, Kamil } 1582e439f0f8SKowalski, Kamil 1583e439f0f8SKowalski, Kamil /** 1584e439f0f8SKowalski, Kamil * This allows VlanNetworkInterfaceCollection to reuse this class' doGet 1585e439f0f8SKowalski, Kamil * method, to maintain consistency of returned data, as Collection's doPost 1586e439f0f8SKowalski, Kamil * should return data for created member which should match member's doGet 1587e439f0f8SKowalski, Kamil * result in 100%. 1588e439f0f8SKowalski, Kamil */ 1589e439f0f8SKowalski, Kamil friend VlanNetworkInterfaceCollection; 1590e439f0f8SKowalski, Kamil 1591e439f0f8SKowalski, Kamil // Ethernet Provider object 1592e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 159355c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 1594e439f0f8SKowalski, Kamil }; 1595e439f0f8SKowalski, Kamil 1596e439f0f8SKowalski, Kamil /** 1597e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1598e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1599e439f0f8SKowalski, Kamil */ 1600e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection : public Node { 1601e439f0f8SKowalski, Kamil public: 1602e439f0f8SKowalski, Kamil template <typename CrowApp> 1603e439f0f8SKowalski, Kamil // TODO(Pawel) Remove line from below, where we assume that there is only one 1604e439f0f8SKowalski, Kamil // manager called openbmc This shall be generic, but requires to update 1605e439f0f8SKowalski, Kamil // GetSubroutes method 1606e439f0f8SKowalski, Kamil VlanNetworkInterfaceCollection(CrowApp &app) 1607e439f0f8SKowalski, Kamil : Node(app, 1608e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/", 1609e439f0f8SKowalski, Kamil std::string()), 1610e439f0f8SKowalski, Kamil memberVlan(app) { 1611e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1612e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1613e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1614e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1615e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1616e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1617e439f0f8SKowalski, Kamil 1618e439f0f8SKowalski, Kamil entityPrivileges = { 1619e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1620e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1621e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1622e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1623e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1624e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1625e439f0f8SKowalski, Kamil } 1626e439f0f8SKowalski, Kamil 1627e439f0f8SKowalski, Kamil private: 1628e439f0f8SKowalski, Kamil /** 1629e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1630e439f0f8SKowalski, Kamil */ 163155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1632e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1633e439f0f8SKowalski, Kamil if (params.size() != 1) { 1634e439f0f8SKowalski, Kamil // This means there is a problem with the router 1635e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1636e439f0f8SKowalski, Kamil res.end(); 1637e439f0f8SKowalski, Kamil 1638e439f0f8SKowalski, Kamil return; 1639e439f0f8SKowalski, Kamil } 1640e439f0f8SKowalski, Kamil 1641e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1642e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 164355c7b7a2SEd Tanous std::string managerId = "openbmc"; 1644e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1645e439f0f8SKowalski, Kamil 164655c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 1647*a434f2bdSEd Tanous ethernetProvider.getEthernetIfaceList( 1648*a434f2bdSEd Tanous [&, managerId{std::move(managerId)}, 1649*a434f2bdSEd Tanous rootInterfaceName{std::move(rootInterfaceName)}]( 1650*a434f2bdSEd Tanous const bool &success, const std::vector<std::string> &iface_list) { 1651e439f0f8SKowalski, Kamil if (success) { 1652e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 165355c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 1654e439f0f8SKowalski, Kamil 165555c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 165655c7b7a2SEd Tanous if (ifaceItem == rootInterfaceName) { 1657e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1658*a434f2bdSEd Tanous } else if (boost::starts_with(ifaceItem, 1659*a434f2bdSEd Tanous rootInterfaceName + "_")) { 166055c7b7a2SEd Tanous ifaceArray.push_back( 166155c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + managerId + 1662*a434f2bdSEd Tanous "/EthernetInterfaces/" + 1663*a434f2bdSEd Tanous rootInterfaceName + "/VLANs/" + 1664*a434f2bdSEd Tanous ifaceItem}}); 1665e439f0f8SKowalski, Kamil } 1666e439f0f8SKowalski, Kamil } 1667e439f0f8SKowalski, Kamil 1668e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 166955c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 167055c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 167155c7b7a2SEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/" + managerId + 1672*a434f2bdSEd Tanous "/EthernetInterfaces/" + 1673*a434f2bdSEd Tanous rootInterfaceName + "/VLANs"; 167455c7b7a2SEd Tanous res.jsonValue = Node::json; 1675e439f0f8SKowalski, Kamil } else { 1676e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 167755c7b7a2SEd Tanous res.jsonValue, messages::resourceNotFound("EthernetInterface", 1678e439f0f8SKowalski, Kamil rootInterfaceName)); 1679e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1680e439f0f8SKowalski, Kamil res.end(); 1681e439f0f8SKowalski, Kamil } 1682e439f0f8SKowalski, Kamil } else { 1683e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1684e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1685e439f0f8SKowalski, Kamil } 1686e439f0f8SKowalski, Kamil res.end(); 1687e439f0f8SKowalski, Kamil }); 1688e439f0f8SKowalski, Kamil } 1689e439f0f8SKowalski, Kamil 169055c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 1691e439f0f8SKowalski, Kamil const std::vector<std::string> ¶ms) override { 1692e439f0f8SKowalski, Kamil if (params.size() != 1) { 1693e439f0f8SKowalski, Kamil // This means there is a problem with the router 1694e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1695e439f0f8SKowalski, Kamil res.end(); 1696e439f0f8SKowalski, Kamil return; 1697e439f0f8SKowalski, Kamil } 1698e439f0f8SKowalski, Kamil 1699e439f0f8SKowalski, Kamil nlohmann::json postReq; 1700e439f0f8SKowalski, Kamil 1701e439f0f8SKowalski, Kamil if (!json_util::processJsonFromRequest(res, req, postReq)) { 1702e439f0f8SKowalski, Kamil return; 1703e439f0f8SKowalski, Kamil } 1704e439f0f8SKowalski, Kamil 1705e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for 1706e439f0f8SKowalski, Kamil // any Manager, not only hardcoded 'openbmc'. 170755c7b7a2SEd Tanous std::string managerId = "openbmc"; 1708e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1709e439f0f8SKowalski, Kamil uint64_t vlanId; 1710e439f0f8SKowalski, Kamil bool errorDetected; 1711e439f0f8SKowalski, Kamil 1712e439f0f8SKowalski, Kamil if (json_util::getUnsigned( 1713e439f0f8SKowalski, Kamil "VLANId", postReq, vlanId, 1714e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::MISSING) | 1715e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 171655c7b7a2SEd Tanous res.jsonValue, "/VLANId") != json_util::Result::SUCCESS) { 1717e439f0f8SKowalski, Kamil res.end(); 1718e439f0f8SKowalski, Kamil return; 1719e439f0f8SKowalski, Kamil } 1720e439f0f8SKowalski, Kamil 172155c7b7a2SEd Tanous // get eth interface list, and call the below callback for JSON preparation 1722*a434f2bdSEd Tanous ethernetProvider.getEthernetIfaceList( 1723*a434f2bdSEd Tanous [&, managerId{std::move(managerId)}, 1724*a434f2bdSEd Tanous rootInterfaceName{std::move(rootInterfaceName)}]( 1725*a434f2bdSEd Tanous const bool &success, const std::vector<std::string> &iface_list) { 1726e439f0f8SKowalski, Kamil if (success) { 1727e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 1728e439f0f8SKowalski, Kamil 172955c7b7a2SEd Tanous for (const std::string &ifaceItem : iface_list) { 173055c7b7a2SEd Tanous if (ifaceItem == rootInterfaceName) { 1731e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1732e439f0f8SKowalski, Kamil break; 1733e439f0f8SKowalski, Kamil } 1734e439f0f8SKowalski, Kamil } 1735e439f0f8SKowalski, Kamil 1736e439f0f8SKowalski, Kamil if (rootInterfaceFound) { 173755c7b7a2SEd Tanous ethernetProvider.createVlan( 1738e439f0f8SKowalski, Kamil rootInterfaceName, vlanId, 1739e439f0f8SKowalski, Kamil [&, vlanId, rootInterfaceName, 1740e439f0f8SKowalski, Kamil req{std::move(req)}](const boost::system::error_code ec) { 1741e439f0f8SKowalski, Kamil if (ec) { 1742*a434f2bdSEd Tanous messages::addMessageToErrorJson( 1743*a434f2bdSEd Tanous res.jsonValue, messages::internalError()); 1744e439f0f8SKowalski, Kamil res.end(); 1745e439f0f8SKowalski, Kamil } else { 1746e439f0f8SKowalski, Kamil memberVlan.doGet( 1747e439f0f8SKowalski, Kamil res, req, 1748e439f0f8SKowalski, Kamil {rootInterfaceName, 1749e439f0f8SKowalski, Kamil rootInterfaceName + "_" + std::to_string(vlanId)}); 1750e439f0f8SKowalski, Kamil } 1751e439f0f8SKowalski, Kamil }); 1752e439f0f8SKowalski, Kamil } else { 1753e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 175455c7b7a2SEd Tanous res.jsonValue, messages::resourceNotFound("EthernetInterface", 1755e439f0f8SKowalski, Kamil rootInterfaceName)); 1756e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1757e439f0f8SKowalski, Kamil res.end(); 1758e439f0f8SKowalski, Kamil } 1759e439f0f8SKowalski, Kamil } else { 1760e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1761e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1762e439f0f8SKowalski, Kamil res.end(); 1763e439f0f8SKowalski, Kamil } 1764e439f0f8SKowalski, Kamil }); 1765e439f0f8SKowalski, Kamil } 1766e439f0f8SKowalski, Kamil 1767e439f0f8SKowalski, Kamil // Ethernet Provider object 1768e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 176955c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 1770e439f0f8SKowalski, Kamil VlanNetworkInterface memberVlan; 1771e439f0f8SKowalski, Kamil }; 1772e439f0f8SKowalski, Kamil 17739391bb9cSRapkiewicz, Pawel } // namespace redfish 1774