19391bb9cSRapkiewicz, Pawel /* 29391bb9cSRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation 39391bb9cSRapkiewicz, Pawel // 49391bb9cSRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License"); 59391bb9cSRapkiewicz, Pawel // you may not use this file except in compliance with the License. 69391bb9cSRapkiewicz, Pawel // You may obtain a copy of the License at 79391bb9cSRapkiewicz, Pawel // 89391bb9cSRapkiewicz, Pawel // http://www.apache.org/licenses/LICENSE-2.0 99391bb9cSRapkiewicz, Pawel // 109391bb9cSRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software 119391bb9cSRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS, 129391bb9cSRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139391bb9cSRapkiewicz, Pawel // See the License for the specific language governing permissions and 149391bb9cSRapkiewicz, Pawel // limitations under the License. 159391bb9cSRapkiewicz, Pawel */ 169391bb9cSRapkiewicz, Pawel #pragma once 179391bb9cSRapkiewicz, Pawel 18*1abe55efSEd Tanous #include <boost/container/flat_map.hpp> 19179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 20588c3f0dSKowalski, Kamil #include <error_messages.hpp> 21179db1d7SKowalski, Kamil #include <node.hpp> 22588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 239391bb9cSRapkiewicz, Pawel 24*1abe55efSEd Tanous namespace redfish 25*1abe55efSEd Tanous { 269391bb9cSRapkiewicz, Pawel 279391bb9cSRapkiewicz, Pawel /** 289391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 299391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 309391bb9cSRapkiewicz, Pawel */ 31aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 32aa2e59c1SEd Tanous std::string, 33aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 34aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 359391bb9cSRapkiewicz, Pawel 369391bb9cSRapkiewicz, Pawel using GetManagedObjectsType = boost::container::flat_map< 37aa2e59c1SEd Tanous sdbusplus::message::object_path, 38aa2e59c1SEd Tanous boost::container::flat_map< 39aa2e59c1SEd Tanous std::string, 40aa2e59c1SEd Tanous boost::container::flat_map< 41aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 42aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 43aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>>>; 449391bb9cSRapkiewicz, Pawel 459391bb9cSRapkiewicz, Pawel /** 469391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 479391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider change everything to ptr, or to non-ptr values. 489391bb9cSRapkiewicz, Pawel */ 49*1abe55efSEd Tanous struct IPv4AddressData 50*1abe55efSEd Tanous { 51179db1d7SKowalski, Kamil std::string id; 529391bb9cSRapkiewicz, Pawel const std::string *address; 539391bb9cSRapkiewicz, Pawel const std::string *domain; 549391bb9cSRapkiewicz, Pawel const std::string *gateway; 559391bb9cSRapkiewicz, Pawel std::string netmask; 569391bb9cSRapkiewicz, Pawel std::string origin; 579391bb9cSRapkiewicz, Pawel bool global; 58179db1d7SKowalski, Kamil /** 59179db1d7SKowalski, Kamil * @brief Operator< to enable sorting 60179db1d7SKowalski, Kamil * 61179db1d7SKowalski, Kamil * @param[in] obj Object to compare with 62179db1d7SKowalski, Kamil * 63179db1d7SKowalski, Kamil * @return This object id < supplied object id 64179db1d7SKowalski, Kamil */ 65*1abe55efSEd Tanous bool operator<(const IPv4AddressData &obj) const 66*1abe55efSEd Tanous { 67*1abe55efSEd Tanous return (id < obj.id); 68*1abe55efSEd Tanous } 699391bb9cSRapkiewicz, Pawel }; 709391bb9cSRapkiewicz, Pawel 719391bb9cSRapkiewicz, Pawel /** 729391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 739391bb9cSRapkiewicz, Pawel * available from DBus 749391bb9cSRapkiewicz, Pawel */ 75*1abe55efSEd Tanous struct EthernetInterfaceData 76*1abe55efSEd Tanous { 779391bb9cSRapkiewicz, Pawel const unsigned int *speed; 7855c7b7a2SEd Tanous const bool *autoNeg; 799391bb9cSRapkiewicz, Pawel const std::string *hostname; 8055c7b7a2SEd Tanous const std::string *defaultGateway; 8155c7b7a2SEd Tanous const std::string *macAddress; 8255c7b7a2SEd Tanous const unsigned int *vlanId; 839391bb9cSRapkiewicz, Pawel }; 849391bb9cSRapkiewicz, Pawel 859391bb9cSRapkiewicz, Pawel /** 869391bb9cSRapkiewicz, Pawel * OnDemandEthernetProvider 87274fad5aSGunnar Mills * Ethernet provider class that retrieves data directly from dbus, before 88274fad5aSGunnar Mills * setting it into JSON output. This does not cache any data. 899391bb9cSRapkiewicz, Pawel * 909391bb9cSRapkiewicz, Pawel * TODO(Pawel) 919391bb9cSRapkiewicz, Pawel * This perhaps shall be different file, which has to be chosen on compile time 929391bb9cSRapkiewicz, Pawel * depending on OEM needs 939391bb9cSRapkiewicz, Pawel */ 94*1abe55efSEd Tanous class OnDemandEthernetProvider 95*1abe55efSEd Tanous { 969391bb9cSRapkiewicz, Pawel private: 97*1abe55efSEd Tanous // Consts that may have influence on EthernetProvider performance/memory 98*1abe55efSEd Tanous // usage 9955c7b7a2SEd Tanous const size_t maxIpV4AddressesPerInterface = 10; 1009391bb9cSRapkiewicz, Pawel 1019391bb9cSRapkiewicz, Pawel // Helper function that allows to extract GetAllPropertiesType from 1029391bb9cSRapkiewicz, Pawel // GetManagedObjectsType, based on object path, and interface name 1039391bb9cSRapkiewicz, Pawel const PropertiesMapType *extractInterfaceProperties( 104aa2e59c1SEd Tanous const sdbusplus::message::object_path &objpath, 105*1abe55efSEd Tanous const std::string &interface, const GetManagedObjectsType &dbus_data) 106*1abe55efSEd Tanous { 10755c7b7a2SEd Tanous const auto &dbusObj = dbus_data.find(objpath); 108*1abe55efSEd Tanous if (dbusObj != dbus_data.end()) 109*1abe55efSEd Tanous { 11055c7b7a2SEd Tanous const auto &iface = dbusObj->second.find(interface); 111*1abe55efSEd Tanous if (iface != dbusObj->second.end()) 112*1abe55efSEd Tanous { 1139391bb9cSRapkiewicz, Pawel return &iface->second; 1149391bb9cSRapkiewicz, Pawel } 1159391bb9cSRapkiewicz, Pawel } 1169391bb9cSRapkiewicz, Pawel return nullptr; 1179391bb9cSRapkiewicz, Pawel } 1189391bb9cSRapkiewicz, Pawel 1199391bb9cSRapkiewicz, Pawel // Helper Wrapper that does inline object_path conversion from string 120aa2e59c1SEd Tanous // into sdbusplus::message::object_path type 121*1abe55efSEd Tanous inline const PropertiesMapType * 122*1abe55efSEd Tanous extractInterfaceProperties(const std::string &objpath, 123*1abe55efSEd Tanous const std::string &interface, 124*1abe55efSEd Tanous const GetManagedObjectsType &dbus_data) 125*1abe55efSEd Tanous { 12655c7b7a2SEd Tanous const auto &dbusObj = sdbusplus::message::object_path{objpath}; 12755c7b7a2SEd Tanous return extractInterfaceProperties(dbusObj, interface, dbus_data); 1289391bb9cSRapkiewicz, Pawel } 1299391bb9cSRapkiewicz, Pawel 1309391bb9cSRapkiewicz, Pawel // Helper function that allows to get pointer to the property from 1319391bb9cSRapkiewicz, Pawel // GetAllPropertiesType native, or extracted by GetAllPropertiesType 1329391bb9cSRapkiewicz, Pawel template <typename T> 133aa2e59c1SEd Tanous inline T const *const extractProperty(const PropertiesMapType &properties, 134*1abe55efSEd Tanous const std::string &name) 135*1abe55efSEd Tanous { 1369391bb9cSRapkiewicz, Pawel const auto &property = properties.find(name); 137*1abe55efSEd Tanous if (property != properties.end()) 138*1abe55efSEd Tanous { 13955c7b7a2SEd Tanous return mapbox::getPtr<const T>(property->second); 1409391bb9cSRapkiewicz, Pawel } 1419391bb9cSRapkiewicz, Pawel return nullptr; 1429391bb9cSRapkiewicz, Pawel } 1439391bb9cSRapkiewicz, Pawel // TODO(Pawel) Consider to move the above functions to dbus 1449391bb9cSRapkiewicz, Pawel // generic_interfaces.hpp 1459391bb9cSRapkiewicz, Pawel 1469391bb9cSRapkiewicz, Pawel // Helper function that extracts data from several dbus objects and several 1479391bb9cSRapkiewicz, Pawel // interfaces required by single ethernet interface instance 14855c7b7a2SEd Tanous void extractEthernetInterfaceData(const std::string ðifaceId, 1499391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 150*1abe55efSEd Tanous EthernetInterfaceData ð_data) 151*1abe55efSEd Tanous { 1529391bb9cSRapkiewicz, Pawel // Extract data that contains MAC Address 15355c7b7a2SEd Tanous const PropertiesMapType *macProperties = extractInterfaceProperties( 15455c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 1559391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.MACAddress", dbus_data); 1569391bb9cSRapkiewicz, Pawel 157*1abe55efSEd Tanous if (macProperties != nullptr) 158*1abe55efSEd Tanous { 15955c7b7a2SEd Tanous eth_data.macAddress = 16055c7b7a2SEd Tanous extractProperty<std::string>(*macProperties, "MACAddress"); 1619391bb9cSRapkiewicz, Pawel } 1629391bb9cSRapkiewicz, Pawel 16355c7b7a2SEd Tanous const PropertiesMapType *vlanProperties = extractInterfaceProperties( 16455c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 165c7070ac2SKowalski, Kamil "xyz.openbmc_project.Network.VLAN", dbus_data); 166c7070ac2SKowalski, Kamil 167*1abe55efSEd Tanous if (vlanProperties != nullptr) 168*1abe55efSEd Tanous { 169*1abe55efSEd Tanous eth_data.vlanId = 170*1abe55efSEd Tanous extractProperty<unsigned int>(*vlanProperties, "Id"); 171c7070ac2SKowalski, Kamil } 172c7070ac2SKowalski, Kamil 173*1abe55efSEd Tanous // Extract data that contains link information (auto negotiation and 174*1abe55efSEd Tanous // speed) 17555c7b7a2SEd Tanous const PropertiesMapType *ethProperties = extractInterfaceProperties( 17655c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId, 1779391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.EthernetInterface", dbus_data); 1789391bb9cSRapkiewicz, Pawel 179*1abe55efSEd Tanous if (ethProperties != nullptr) 180*1abe55efSEd Tanous { 18155c7b7a2SEd Tanous eth_data.autoNeg = extractProperty<bool>(*ethProperties, "AutoNeg"); 182*1abe55efSEd Tanous eth_data.speed = 183*1abe55efSEd Tanous extractProperty<unsigned int>(*ethProperties, "Speed"); 1849391bb9cSRapkiewicz, Pawel } 1859391bb9cSRapkiewicz, Pawel 1869391bb9cSRapkiewicz, Pawel // Extract data that contains network config (HostName and DefaultGW) 18755c7b7a2SEd Tanous const PropertiesMapType *configProperties = extractInterfaceProperties( 1889391bb9cSRapkiewicz, Pawel "/xyz/openbmc_project/network/config", 1899391bb9cSRapkiewicz, Pawel "xyz.openbmc_project.Network.SystemConfiguration", dbus_data); 1909391bb9cSRapkiewicz, Pawel 191*1abe55efSEd Tanous if (configProperties != nullptr) 192*1abe55efSEd Tanous { 1939391bb9cSRapkiewicz, Pawel eth_data.hostname = 19455c7b7a2SEd Tanous extractProperty<std::string>(*configProperties, "HostName"); 195*1abe55efSEd Tanous eth_data.defaultGateway = extractProperty<std::string>( 196*1abe55efSEd Tanous *configProperties, "DefaultGateway"); 1979391bb9cSRapkiewicz, Pawel } 1989391bb9cSRapkiewicz, Pawel } 1999391bb9cSRapkiewicz, Pawel 2009391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 2019391bb9cSRapkiewicz, Pawel // into full dot notation 202*1abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 203*1abe55efSEd Tanous { 2049391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 2059391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 2069391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 2079391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 2089391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 2099391bb9cSRapkiewicz, Pawel return netmask; 2109391bb9cSRapkiewicz, Pawel } 2119391bb9cSRapkiewicz, Pawel 2129391bb9cSRapkiewicz, Pawel // Helper function that extracts data for single ethernet ipv4 address 21355c7b7a2SEd Tanous void extractIPv4Data(const std::string ðifaceId, 2149391bb9cSRapkiewicz, Pawel const GetManagedObjectsType &dbus_data, 215*1abe55efSEd Tanous std::vector<IPv4AddressData> &ipv4_config) 216*1abe55efSEd Tanous { 217179db1d7SKowalski, Kamil const std::string pathStart = 21855c7b7a2SEd Tanous "/xyz/openbmc_project/network/" + ethifaceId + "/ipv4/"; 219179db1d7SKowalski, Kamil 2209391bb9cSRapkiewicz, Pawel // Since there might be several IPv4 configurations aligned with 2219391bb9cSRapkiewicz, Pawel // single ethernet interface, loop over all of them 222*1abe55efSEd Tanous for (auto &objpath : dbus_data) 223*1abe55efSEd Tanous { 224274fad5aSGunnar Mills // Check if proper patter for object path appears 225*1abe55efSEd Tanous if (boost::starts_with( 226*1abe55efSEd Tanous static_cast<const std::string &>(objpath.first), pathStart)) 227*1abe55efSEd Tanous { 2289391bb9cSRapkiewicz, Pawel // and get approrpiate interface 2299391bb9cSRapkiewicz, Pawel const auto &interface = 2309391bb9cSRapkiewicz, Pawel objpath.second.find("xyz.openbmc_project.Network.IP"); 231*1abe55efSEd Tanous if (interface != objpath.second.end()) 232*1abe55efSEd Tanous { 233*1abe55efSEd Tanous // Make a properties 'shortcut', to make everything more 234*1abe55efSEd Tanous // readable 2359391bb9cSRapkiewicz, Pawel const PropertiesMapType &properties = interface->second; 236*1abe55efSEd Tanous // Instance IPv4AddressData structure, and set as 237*1abe55efSEd Tanous // appropriate 23855c7b7a2SEd Tanous IPv4AddressData ipv4Address; 239179db1d7SKowalski, Kamil 240*1abe55efSEd Tanous ipv4Address.id = 241*1abe55efSEd Tanous static_cast<const std::string &>(objpath.first) 242179db1d7SKowalski, Kamil .substr(pathStart.size()); 243179db1d7SKowalski, Kamil 2449391bb9cSRapkiewicz, Pawel // IPv4 address 24555c7b7a2SEd Tanous ipv4Address.address = 2469391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Address"); 2479391bb9cSRapkiewicz, Pawel // IPv4 gateway 24855c7b7a2SEd Tanous ipv4Address.gateway = 2499391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Gateway"); 2509391bb9cSRapkiewicz, Pawel 2519391bb9cSRapkiewicz, Pawel // Origin is kind of DBus object so fetch pointer... 2529391bb9cSRapkiewicz, Pawel const std::string *origin = 2539391bb9cSRapkiewicz, Pawel extractProperty<std::string>(properties, "Origin"); 254*1abe55efSEd Tanous if (origin != nullptr) 255*1abe55efSEd Tanous { 25655c7b7a2SEd Tanous ipv4Address.origin = 257*1abe55efSEd Tanous translateAddressOriginBetweenDBusAndRedfish( 258*1abe55efSEd Tanous origin, true, true); 2599391bb9cSRapkiewicz, Pawel } 2609391bb9cSRapkiewicz, Pawel 2619391bb9cSRapkiewicz, Pawel // Netmask is presented as PrefixLength 2629391bb9cSRapkiewicz, Pawel const auto *mask = 2639391bb9cSRapkiewicz, Pawel extractProperty<uint8_t>(properties, "PrefixLength"); 264*1abe55efSEd Tanous if (mask != nullptr) 265*1abe55efSEd Tanous { 2669391bb9cSRapkiewicz, Pawel // convert it to the string 26755c7b7a2SEd Tanous ipv4Address.netmask = getNetmask(*mask); 2689391bb9cSRapkiewicz, Pawel } 2699391bb9cSRapkiewicz, Pawel 2709391bb9cSRapkiewicz, Pawel // Attach IPv4 only if address is present 271*1abe55efSEd Tanous if (ipv4Address.address != nullptr) 272*1abe55efSEd Tanous { 273a434f2bdSEd Tanous // Check if given address is local, or global 274*1abe55efSEd Tanous if (boost::starts_with(*ipv4Address.address, "169.254")) 275*1abe55efSEd Tanous { 27655c7b7a2SEd Tanous ipv4Address.global = false; 277*1abe55efSEd Tanous } 278*1abe55efSEd Tanous else 279*1abe55efSEd Tanous { 28055c7b7a2SEd Tanous ipv4Address.global = true; 2819391bb9cSRapkiewicz, Pawel } 28255c7b7a2SEd Tanous ipv4_config.emplace_back(std::move(ipv4Address)); 2839391bb9cSRapkiewicz, Pawel } 2849391bb9cSRapkiewicz, Pawel } 2859391bb9cSRapkiewicz, Pawel } 2869391bb9cSRapkiewicz, Pawel } 287179db1d7SKowalski, Kamil 288179db1d7SKowalski, Kamil /** 289179db1d7SKowalski, Kamil * We have to sort this vector and ensure that order of IPv4 addresses 290*1abe55efSEd Tanous * is consistent between GETs to allow modification and deletion in 291*1abe55efSEd Tanous * PATCHes 292179db1d7SKowalski, Kamil */ 293179db1d7SKowalski, Kamil std::sort(ipv4_config.begin(), ipv4_config.end()); 2949391bb9cSRapkiewicz, Pawel } 2959391bb9cSRapkiewicz, Pawel 296179db1d7SKowalski, Kamil static const constexpr int ipV4AddressSectionsCount = 4; 297179db1d7SKowalski, Kamil 2989391bb9cSRapkiewicz, Pawel public: 2999391bb9cSRapkiewicz, Pawel /** 300588c3f0dSKowalski, Kamil * @brief Creates VLAN for given interface with given Id through D-Bus 301588c3f0dSKowalski, Kamil * 302588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of interface for which VLAN will be created 303588c3f0dSKowalski, Kamil * @param[in] inputVlanId ID of the new VLAN 304588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 305588c3f0dSKowalski, Kamil * 306588c3f0dSKowalski, Kamil * @return None. 307588c3f0dSKowalski, Kamil */ 308588c3f0dSKowalski, Kamil template <typename CallbackFunc> 309588c3f0dSKowalski, Kamil void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId, 310*1abe55efSEd Tanous CallbackFunc &&callback) 311*1abe55efSEd Tanous { 31255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 313*1abe55efSEd Tanous callback, "xyz.openbmc_project.Network", 314*1abe55efSEd Tanous "/xyz/openbmc_project/network", 315588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId, 316588c3f0dSKowalski, Kamil static_cast<uint32_t>(inputVlanId)); 317588c3f0dSKowalski, Kamil }; 318588c3f0dSKowalski, Kamil 319588c3f0dSKowalski, Kamil /** 320588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 321588c3f0dSKowalski, Kamil * 322588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 323588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 324588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 325588c3f0dSKowalski, Kamil * 326588c3f0dSKowalski, Kamil * @return None. 327588c3f0dSKowalski, Kamil */ 328588c3f0dSKowalski, Kamil template <typename CallbackFunc> 329e439f0f8SKowalski, Kamil static void changeVlanId(const std::string &ifaceId, 330e439f0f8SKowalski, Kamil const uint32_t &inputVlanId, 331*1abe55efSEd Tanous CallbackFunc &&callback) 332*1abe55efSEd Tanous { 33355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 334588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 335588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 336588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 337588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 338588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 339588c3f0dSKowalski, Kamil }; 340588c3f0dSKowalski, Kamil 341588c3f0dSKowalski, Kamil /** 342179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 343179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 344179db1d7SKowalski, Kamil * bit count for Subnet Mask. 345179db1d7SKowalski, Kamil * 346179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 347179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 348179db1d7SKowalski, Kamil * 349179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 350179db1d7SKowalski, Kamil */ 351179db1d7SKowalski, Kamil bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 352*1abe55efSEd Tanous uint8_t *bits = nullptr) 353*1abe55efSEd Tanous { 354179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 355179db1d7SKowalski, Kamil 356179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 357179db1d7SKowalski, Kamil 358*1abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 359*1abe55efSEd Tanous { 360179db1d7SKowalski, Kamil return false; 361179db1d7SKowalski, Kamil } 362179db1d7SKowalski, Kamil 363*1abe55efSEd Tanous if (bits != nullptr) 364*1abe55efSEd Tanous { 365179db1d7SKowalski, Kamil *bits = 0; 366179db1d7SKowalski, Kamil } 367179db1d7SKowalski, Kamil 368179db1d7SKowalski, Kamil char *endPtr; 369179db1d7SKowalski, Kamil long previousValue = 255; 370179db1d7SKowalski, Kamil bool firstZeroInByteHit; 371*1abe55efSEd Tanous for (const std::string &byte : bytesInMask) 372*1abe55efSEd Tanous { 373*1abe55efSEd Tanous if (byte.empty()) 374*1abe55efSEd Tanous { 3751db9ca37SKowalski, Kamil return false; 3761db9ca37SKowalski, Kamil } 3771db9ca37SKowalski, Kamil 378179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 3791db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 380179db1d7SKowalski, Kamil 381*1abe55efSEd Tanous // endPtr should point to the end of the string, otherwise given 382*1abe55efSEd Tanous // string is not 100% number 383*1abe55efSEd Tanous if (*endPtr != '\0') 384*1abe55efSEd Tanous { 385179db1d7SKowalski, Kamil return false; 386179db1d7SKowalski, Kamil } 387179db1d7SKowalski, Kamil 388179db1d7SKowalski, Kamil // Value should be contained in byte 389*1abe55efSEd Tanous if (value < 0 || value > 255) 390*1abe55efSEd Tanous { 391179db1d7SKowalski, Kamil return false; 392179db1d7SKowalski, Kamil } 393179db1d7SKowalski, Kamil 394*1abe55efSEd Tanous if (bits != nullptr) 395*1abe55efSEd Tanous { 396179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 397*1abe55efSEd Tanous if (previousValue != 255 && value != 0) 398*1abe55efSEd Tanous { 399179db1d7SKowalski, Kamil return false; 400179db1d7SKowalski, Kamil } 401179db1d7SKowalski, Kamil 402179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 403179db1d7SKowalski, Kamil firstZeroInByteHit = false; 404179db1d7SKowalski, Kamil 405179db1d7SKowalski, Kamil // Count bits 406*1abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 407*1abe55efSEd Tanous { 408*1abe55efSEd Tanous if (value & (1 << bitIdx)) 409*1abe55efSEd Tanous { 410*1abe55efSEd Tanous if (firstZeroInByteHit) 411*1abe55efSEd Tanous { 412179db1d7SKowalski, Kamil // Continuity not preserved 413179db1d7SKowalski, Kamil return false; 414*1abe55efSEd Tanous } 415*1abe55efSEd Tanous else 416*1abe55efSEd Tanous { 417179db1d7SKowalski, Kamil (*bits)++; 418179db1d7SKowalski, Kamil } 419*1abe55efSEd Tanous } 420*1abe55efSEd Tanous else 421*1abe55efSEd Tanous { 422179db1d7SKowalski, Kamil firstZeroInByteHit = true; 423179db1d7SKowalski, Kamil } 424179db1d7SKowalski, Kamil } 425179db1d7SKowalski, Kamil } 426179db1d7SKowalski, Kamil 427179db1d7SKowalski, Kamil previousValue = value; 428179db1d7SKowalski, Kamil } 429179db1d7SKowalski, Kamil 430179db1d7SKowalski, Kamil return true; 431179db1d7SKowalski, Kamil } 432179db1d7SKowalski, Kamil 433179db1d7SKowalski, Kamil /** 434179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 435179db1d7SKowalski, Kamil * 436179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 43755c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be modified 438179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 439179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 440179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 441179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 442179db1d7SKowalski, Kamil * 443179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 444179db1d7SKowalski, Kamil * otherwise 445179db1d7SKowalski, Kamil */ 446179db1d7SKowalski, Kamil void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx, 447179db1d7SKowalski, Kamil const std::string &ipHash, 448179db1d7SKowalski, Kamil const std::string &name, 449179db1d7SKowalski, Kamil const std::string &newValue, 450*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 451*1abe55efSEd Tanous { 452*1abe55efSEd Tanous auto callback = [asyncResp, ipIdx{std::move(ipIdx)}, 453*1abe55efSEd Tanous name{std::move(name)}, newValue{std::move(newValue)}]( 454*1abe55efSEd Tanous const boost::system::error_code ec) { 455*1abe55efSEd Tanous if (ec) 456*1abe55efSEd Tanous { 457179db1d7SKowalski, Kamil messages::addMessageToJson( 45855c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 459179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 460*1abe55efSEd Tanous } 461*1abe55efSEd Tanous else 462*1abe55efSEd Tanous { 463*1abe55efSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = 464*1abe55efSEd Tanous newValue; 465179db1d7SKowalski, Kamil } 466179db1d7SKowalski, Kamil }; 467179db1d7SKowalski, Kamil 46855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 469179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 470179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 471179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 472179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 473179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 474179db1d7SKowalski, Kamil }; 475179db1d7SKowalski, Kamil 476179db1d7SKowalski, Kamil /** 477179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 478179db1d7SKowalski, Kamil * 479179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 480*1abe55efSEd Tanous * @param[in] ipIdx index of IP in input array that should be 481*1abe55efSEd Tanous * modified 482179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 483179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 484179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 485179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 486179db1d7SKowalski, Kamil * 487179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 488179db1d7SKowalski, Kamil * otherwise 489179db1d7SKowalski, Kamil */ 490179db1d7SKowalski, Kamil void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 491*1abe55efSEd Tanous const std::string &ipHash, 492*1abe55efSEd Tanous const std::string &newValue, 493179db1d7SKowalski, Kamil const std::string &newValueDbus, 494*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 495*1abe55efSEd Tanous { 496*1abe55efSEd Tanous auto callback = [asyncResp, ipIdx{std::move(ipIdx)}, 497*1abe55efSEd Tanous newValue{std::move(newValue)}]( 498*1abe55efSEd Tanous const boost::system::error_code ec) { 499*1abe55efSEd Tanous if (ec) 500*1abe55efSEd Tanous { 501179db1d7SKowalski, Kamil messages::addMessageToJson( 50255c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 503*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(ipIdx) + 504*1abe55efSEd Tanous "/AddressOrigin"); 505*1abe55efSEd Tanous } 506*1abe55efSEd Tanous else 507*1abe55efSEd Tanous { 508*1abe55efSEd Tanous asyncResp->res 509*1abe55efSEd Tanous .jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 510179db1d7SKowalski, Kamil newValue; 511179db1d7SKowalski, Kamil } 512179db1d7SKowalski, Kamil }; 513179db1d7SKowalski, Kamil 51455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 515179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 516179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 517179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 518179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 519179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 520179db1d7SKowalski, Kamil }; 521179db1d7SKowalski, Kamil 522179db1d7SKowalski, Kamil /** 523179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 524179db1d7SKowalski, Kamil * 525179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 526*1abe55efSEd Tanous * @param[in] ipIdx index of IP in input array that should be 527*1abe55efSEd Tanous * modified 528179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 529179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 530179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 531179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 532179db1d7SKowalski, Kamil * 533179db1d7SKowalski, Kamil * @return None 534179db1d7SKowalski, Kamil */ 535179db1d7SKowalski, Kamil void changeIPv4SubnetMaskProperty( 536179db1d7SKowalski, Kamil const std::string &ifaceId, int ipIdx, const std::string &ipHash, 537179db1d7SKowalski, Kamil const std::string &newValueStr, uint8_t &newValue, 538*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 539*1abe55efSEd Tanous { 540*1abe55efSEd Tanous auto callback = [asyncResp, ipIdx{std::move(ipIdx)}, 541*1abe55efSEd Tanous newValueStr{std::move(newValueStr)}]( 542*1abe55efSEd Tanous const boost::system::error_code ec) { 543*1abe55efSEd Tanous if (ec) 544*1abe55efSEd Tanous { 545179db1d7SKowalski, Kamil messages::addMessageToJson( 54655c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 547179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 548*1abe55efSEd Tanous } 549*1abe55efSEd Tanous else 550*1abe55efSEd Tanous { 55155c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 552179db1d7SKowalski, Kamil newValueStr; 553179db1d7SKowalski, Kamil } 554179db1d7SKowalski, Kamil }; 555179db1d7SKowalski, Kamil 55655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 557179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 558179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 559179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 560179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 561179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 562179db1d7SKowalski, Kamil }; 563179db1d7SKowalski, Kamil 564179db1d7SKowalski, Kamil /** 565588c3f0dSKowalski, Kamil * @brief Disables VLAN with given ifaceId 566588c3f0dSKowalski, Kamil * 567588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be disabled 568588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 569588c3f0dSKowalski, Kamil * 570588c3f0dSKowalski, Kamil * @return None. 571588c3f0dSKowalski, Kamil */ 572588c3f0dSKowalski, Kamil template <typename CallbackFunc> 573*1abe55efSEd Tanous static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) 574*1abe55efSEd Tanous { 57555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 576588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 577588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 578588c3f0dSKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 579588c3f0dSKowalski, Kamil }; 580588c3f0dSKowalski, Kamil 581588c3f0dSKowalski, Kamil /** 582588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 583588c3f0dSKowalski, Kamil * 584588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 585588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 586588c3f0dSKowalski, Kamil * 587588c3f0dSKowalski, Kamil * @return None. 588588c3f0dSKowalski, Kamil */ 589588c3f0dSKowalski, Kamil template <typename CallbackFunc> 590*1abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback) 591*1abe55efSEd Tanous { 59255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 593588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 594588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 595588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 596588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 597588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 598588c3f0dSKowalski, Kamil }; 599588c3f0dSKowalski, Kamil 600588c3f0dSKowalski, Kamil /** 601179db1d7SKowalski, Kamil * @brief Deletes given IPv4 602179db1d7SKowalski, Kamil * 603179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 60455c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 605179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 606179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 607179db1d7SKowalski, Kamil * 608179db1d7SKowalski, Kamil * @return None 609179db1d7SKowalski, Kamil */ 610179db1d7SKowalski, Kamil void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 611179db1d7SKowalski, Kamil unsigned int ipIdx, 612*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 613*1abe55efSEd Tanous { 61455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6158ceb2ecaSEd Tanous [ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)}]( 6168ceb2ecaSEd Tanous const boost::system::error_code ec) { 617*1abe55efSEd Tanous if (ec) 618*1abe55efSEd Tanous { 619179db1d7SKowalski, Kamil messages::addMessageToJson( 62055c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 621179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 622*1abe55efSEd Tanous } 623*1abe55efSEd Tanous else 624*1abe55efSEd Tanous { 62555c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 626179db1d7SKowalski, Kamil } 627179db1d7SKowalski, Kamil }, 628179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 629179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 630179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 631179db1d7SKowalski, Kamil } 632179db1d7SKowalski, Kamil 633179db1d7SKowalski, Kamil /** 634179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 635179db1d7SKowalski, Kamil * 636179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 63755c7b7a2SEd Tanous * @param[in] ipIdx index of IP in input array that should be deleted 638179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 639179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 640179db1d7SKowalski, Kamil * 641179db1d7SKowalski, Kamil * @return None 642179db1d7SKowalski, Kamil */ 643179db1d7SKowalski, Kamil void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 644179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 645179db1d7SKowalski, Kamil const std::string &address, 646*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 647*1abe55efSEd Tanous { 648*1abe55efSEd Tanous auto createIpHandler = [ipIdx{std::move(ipIdx)}, 649*1abe55efSEd Tanous asyncResp{std::move(asyncResp)}]( 650*1abe55efSEd Tanous const boost::system::error_code ec) { 651*1abe55efSEd Tanous if (ec) 652*1abe55efSEd Tanous { 653179db1d7SKowalski, Kamil messages::addMessageToJson( 65455c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 655179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 656179db1d7SKowalski, Kamil } 657179db1d7SKowalski, Kamil }; 658179db1d7SKowalski, Kamil 65955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 660179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 661179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 662179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 663179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 664179db1d7SKowalski, Kamil gateway); 665179db1d7SKowalski, Kamil } 666179db1d7SKowalski, Kamil 667179db1d7SKowalski, Kamil /** 668179db1d7SKowalski, Kamil * @brief Translates Address Origin value from D-Bus to Redfish format and 669179db1d7SKowalski, Kamil * vice-versa 670179db1d7SKowalski, Kamil * 671179db1d7SKowalski, Kamil * @param[in] inputOrigin Input value that should be translated 672179db1d7SKowalski, Kamil * @param[in] isIPv4 True for IPv4 origins, False for IPv6 673*1abe55efSEd Tanous * @param[in] isFromDBus True for DBus->Redfish conversion, false for 674*1abe55efSEd Tanous * reverse 675179db1d7SKowalski, Kamil * 676179db1d7SKowalski, Kamil * @return Empty string in case of failure, translated value otherwise 677179db1d7SKowalski, Kamil */ 678179db1d7SKowalski, Kamil std::string translateAddressOriginBetweenDBusAndRedfish( 679*1abe55efSEd Tanous const std::string *inputOrigin, bool isIPv4, bool isFromDBus) 680*1abe55efSEd Tanous { 681179db1d7SKowalski, Kamil // Invalid pointer 682*1abe55efSEd Tanous if (inputOrigin == nullptr) 683*1abe55efSEd Tanous { 684179db1d7SKowalski, Kamil return ""; 685179db1d7SKowalski, Kamil } 686179db1d7SKowalski, Kamil 687179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv4OnlyIdx = 1; 688179db1d7SKowalski, Kamil static const constexpr unsigned int firstIPv6OnlyIdx = 3; 689179db1d7SKowalski, Kamil 690179db1d7SKowalski, Kamil std::array<std::pair<const char *, const char *>, 6> translationTable{ 691179db1d7SKowalski, Kamil {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"}, 692179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"}, 693179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 694179db1d7SKowalski, Kamil "IPv4LinkLocal"}, 695179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"}, 696179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal", 697179db1d7SKowalski, Kamil "LinkLocal"}, 698179db1d7SKowalski, Kamil {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}}; 699179db1d7SKowalski, Kamil 700*1abe55efSEd Tanous for (unsigned int i = 0; i < translationTable.size(); i++) 701*1abe55efSEd Tanous { 702179db1d7SKowalski, Kamil // Skip unrelated 703*1abe55efSEd Tanous if (isIPv4 && i >= firstIPv6OnlyIdx) 704*1abe55efSEd Tanous break; 705*1abe55efSEd Tanous if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) 706*1abe55efSEd Tanous continue; 707179db1d7SKowalski, Kamil 708179db1d7SKowalski, Kamil // When translating D-Bus to Redfish compare input to first element 709179db1d7SKowalski, Kamil if (isFromDBus && translationTable[i].first == *inputOrigin) 710179db1d7SKowalski, Kamil return translationTable[i].second; 711179db1d7SKowalski, Kamil 712179db1d7SKowalski, Kamil // When translating Redfish to D-Bus compare input to second element 713179db1d7SKowalski, Kamil if (!isFromDBus && translationTable[i].second == *inputOrigin) 714179db1d7SKowalski, Kamil return translationTable[i].first; 715179db1d7SKowalski, Kamil } 716179db1d7SKowalski, Kamil 717179db1d7SKowalski, Kamil // If we are still here, that means that value has not been found 718179db1d7SKowalski, Kamil return ""; 719179db1d7SKowalski, Kamil } 720179db1d7SKowalski, Kamil 721179db1d7SKowalski, Kamil /** 722179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 723179db1d7SKowalski, Kamil * Object 724179db1d7SKowalski, Kamil * from EntityManager Network Manager 72555c7b7a2SEd Tanous * @param ethifaceId a eth interface id to query on DBus 726179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 727179db1d7SKowalski, Kamil * into JSON 728179db1d7SKowalski, Kamil */ 729179db1d7SKowalski, Kamil template <typename CallbackFunc> 73055c7b7a2SEd Tanous void getEthernetIfaceData(const std::string ðifaceId, 731*1abe55efSEd Tanous CallbackFunc &&callback) 732*1abe55efSEd Tanous { 73355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 734*1abe55efSEd Tanous [this, ethifaceId{std::move(ethifaceId)}, 735*1abe55efSEd Tanous callback{std::move(callback)}]( 736*1abe55efSEd Tanous const boost::system::error_code error_code, 737179db1d7SKowalski, Kamil const GetManagedObjectsType &resp) { 73855c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 73955c7b7a2SEd Tanous std::vector<IPv4AddressData> ipv4Data; 74055c7b7a2SEd Tanous ipv4Data.reserve(maxIpV4AddressesPerInterface); 741179db1d7SKowalski, Kamil 742*1abe55efSEd Tanous if (error_code) 743*1abe55efSEd Tanous { 744*1abe55efSEd Tanous // Something wrong on DBus, the error_code is not important 745*1abe55efSEd Tanous // at this moment, just return success=false, and empty 746*1abe55efSEd Tanous // output. Since size of vector may vary depending on 747*1abe55efSEd Tanous // information from Network Manager, and empty output could 748*1abe55efSEd Tanous // not be treated same way as error. 74955c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 750179db1d7SKowalski, Kamil return; 751179db1d7SKowalski, Kamil } 752179db1d7SKowalski, Kamil 753927a505aSKowalski, Kamil // Find interface 75455c7b7a2SEd Tanous if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) == 755*1abe55efSEd Tanous resp.end()) 756*1abe55efSEd Tanous { 757927a505aSKowalski, Kamil // Interface has not been found 75855c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 759927a505aSKowalski, Kamil return; 760927a505aSKowalski, Kamil } 761927a505aSKowalski, Kamil 76255c7b7a2SEd Tanous extractEthernetInterfaceData(ethifaceId, resp, ethData); 76355c7b7a2SEd Tanous extractIPv4Data(ethifaceId, resp, ipv4Data); 764179db1d7SKowalski, Kamil 765179db1d7SKowalski, Kamil // Fix global GW 766*1abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 767*1abe55efSEd Tanous { 768*1abe55efSEd Tanous if ((ipv4.global) && ((ipv4.gateway == nullptr) || 769*1abe55efSEd Tanous (*ipv4.gateway == "0.0.0.0"))) 770*1abe55efSEd Tanous { 77155c7b7a2SEd Tanous ipv4.gateway = ethData.defaultGateway; 772179db1d7SKowalski, Kamil } 773179db1d7SKowalski, Kamil } 774179db1d7SKowalski, Kamil 775a434f2bdSEd Tanous // Finally make a callback with useful data 77655c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 777179db1d7SKowalski, Kamil }, 778179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 779179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 780179db1d7SKowalski, Kamil }; 781179db1d7SKowalski, Kamil 782179db1d7SKowalski, Kamil /** 7839391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7849391bb9cSRapkiewicz, Pawel * Manager 785*1abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 786*1abe55efSEd Tanous * into JSON. 7879391bb9cSRapkiewicz, Pawel */ 7889391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 789*1abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 790*1abe55efSEd Tanous { 79155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7929391bb9cSRapkiewicz, Pawel [this, callback{std::move(callback)}]( 7939391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 794aa2e59c1SEd Tanous GetManagedObjectsType &resp) { 795*1abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 796*1abe55efSEd Tanous // ethernet interfaces 79755c7b7a2SEd Tanous std::vector<std::string> ifaceList; 79855c7b7a2SEd Tanous ifaceList.reserve(resp.size()); 799*1abe55efSEd Tanous if (error_code) 800*1abe55efSEd Tanous { 801*1abe55efSEd Tanous // Something wrong on DBus, the error_code is not important 802*1abe55efSEd Tanous // at this moment, just return success=false, and empty 803*1abe55efSEd Tanous // output. Since size of vector may vary depending on 804*1abe55efSEd Tanous // information from Network Manager, and empty output could 805*1abe55efSEd Tanous // not be treated same way as error. 80655c7b7a2SEd Tanous callback(false, ifaceList); 8079391bb9cSRapkiewicz, Pawel return; 8089391bb9cSRapkiewicz, Pawel } 8099391bb9cSRapkiewicz, Pawel 8109391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 811*1abe55efSEd Tanous for (auto &objpath : resp) 812*1abe55efSEd Tanous { 8139391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 814*1abe55efSEd Tanous for (auto &interface : objpath.second) 815*1abe55efSEd Tanous { 816*1abe55efSEd Tanous // If interface is 817*1abe55efSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this 818*1abe55efSEd Tanous // is what we're looking for. 8199391bb9cSRapkiewicz, Pawel if (interface.first == 820*1abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 821*1abe55efSEd Tanous { 822a434f2bdSEd Tanous // Cut out everything until last "/", ... 82355c7b7a2SEd Tanous const std::string &ifaceId = 824daf36e2eSEd Tanous static_cast<const std::string &>(objpath.first); 82555c7b7a2SEd Tanous std::size_t lastPos = ifaceId.rfind("/"); 826*1abe55efSEd Tanous if (lastPos != std::string::npos) 827*1abe55efSEd Tanous { 8289391bb9cSRapkiewicz, Pawel // and put it into output vector. 829*1abe55efSEd Tanous ifaceList.emplace_back( 830*1abe55efSEd Tanous ifaceId.substr(lastPos + 1)); 8319391bb9cSRapkiewicz, Pawel } 8329391bb9cSRapkiewicz, Pawel } 8339391bb9cSRapkiewicz, Pawel } 8349391bb9cSRapkiewicz, Pawel } 835a434f2bdSEd Tanous // Finally make a callback with useful data 83655c7b7a2SEd Tanous callback(true, ifaceList); 8379391bb9cSRapkiewicz, Pawel }, 838aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 839aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 8409391bb9cSRapkiewicz, Pawel }; 8419391bb9cSRapkiewicz, Pawel }; 8429391bb9cSRapkiewicz, Pawel 8439391bb9cSRapkiewicz, Pawel /** 8449391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 8459391bb9cSRapkiewicz, Pawel */ 846*1abe55efSEd Tanous class EthernetCollection : public Node 847*1abe55efSEd Tanous { 8489391bb9cSRapkiewicz, Pawel public: 849*1abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 850*1abe55efSEd Tanous // one manager called openbmc This shall be generic, but requires to update 8519391bb9cSRapkiewicz, Pawel // GetSubroutes method 852*1abe55efSEd Tanous EthernetCollection(CrowApp &app) : 853*1abe55efSEd Tanous Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") 854*1abe55efSEd Tanous { 8559391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 8569391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 8579391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8589391bb9cSRapkiewicz, Pawel "/redfish/v1/" 8599391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 860*1abe55efSEd Tanous Node::json["@odata.id"] = 861*1abe55efSEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces"; 8629391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 8639391bb9cSRapkiewicz, Pawel Node::json["Description"] = 8649391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 8659391bb9cSRapkiewicz, Pawel 866588c3f0dSKowalski, Kamil entityPrivileges = { 867588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 868e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 869e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 870e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 871e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 872e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8739391bb9cSRapkiewicz, Pawel } 8749391bb9cSRapkiewicz, Pawel 8759391bb9cSRapkiewicz, Pawel private: 8769391bb9cSRapkiewicz, Pawel /** 8779391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 8789391bb9cSRapkiewicz, Pawel */ 87955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 880*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 881*1abe55efSEd Tanous { 882*1abe55efSEd Tanous // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces 883*1abe55efSEd Tanous // for any Manager, not only hardcoded 'openbmc'. 88455c7b7a2SEd Tanous std::string managerId = "openbmc"; 8859391bb9cSRapkiewicz, Pawel 886*1abe55efSEd Tanous // get eth interface list, and call the below callback for JSON 887*1abe55efSEd Tanous // preparation 888*1abe55efSEd Tanous ethernetProvider.getEthernetIfaceList( 889*1abe55efSEd Tanous [&, managerId{std::move(managerId)}]( 890*1abe55efSEd Tanous const bool &success, 891*1abe55efSEd Tanous const std::vector<std::string> &iface_list) { 892*1abe55efSEd Tanous if (success) 893*1abe55efSEd Tanous { 89455c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 895*1abe55efSEd Tanous for (const std::string &ifaceItem : iface_list) 896*1abe55efSEd Tanous { 89755c7b7a2SEd Tanous ifaceArray.push_back( 89855c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + managerId + 899*1abe55efSEd Tanous "/EthernetInterfaces/" + 900*1abe55efSEd Tanous ifaceItem}}); 9019391bb9cSRapkiewicz, Pawel } 90255c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 90355c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 904*1abe55efSEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/" + 905*1abe55efSEd Tanous managerId + "/EthernetInterfaces"; 90655c7b7a2SEd Tanous res.jsonValue = Node::json; 907*1abe55efSEd Tanous } 908*1abe55efSEd Tanous else 909*1abe55efSEd Tanous { 9109391bb9cSRapkiewicz, Pawel // No success, best what we can do is return INTERNALL ERROR 911*1abe55efSEd Tanous res.result( 912*1abe55efSEd Tanous boost::beast::http::status::internal_server_error); 9139391bb9cSRapkiewicz, Pawel } 9149391bb9cSRapkiewicz, Pawel res.end(); 9159391bb9cSRapkiewicz, Pawel }); 9169391bb9cSRapkiewicz, Pawel } 9179391bb9cSRapkiewicz, Pawel 9189391bb9cSRapkiewicz, Pawel // Ethernet Provider object 9199391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 92055c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 9219391bb9cSRapkiewicz, Pawel }; 9229391bb9cSRapkiewicz, Pawel 9239391bb9cSRapkiewicz, Pawel /** 9249391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 9259391bb9cSRapkiewicz, Pawel */ 926*1abe55efSEd Tanous class EthernetInterface : public Node 927*1abe55efSEd Tanous { 9289391bb9cSRapkiewicz, Pawel public: 9299391bb9cSRapkiewicz, Pawel /* 9309391bb9cSRapkiewicz, Pawel * Default Constructor 9319391bb9cSRapkiewicz, Pawel */ 932*1abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 933*1abe55efSEd Tanous // one manager called openbmc This shall be generic, but requires to update 9349391bb9cSRapkiewicz, Pawel // GetSubroutes method 935*1abe55efSEd Tanous EthernetInterface(CrowApp &app) : 936*1abe55efSEd Tanous Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/", 937*1abe55efSEd Tanous std::string()) 938*1abe55efSEd Tanous { 939*1abe55efSEd Tanous Node::json["@odata.type"] = 940*1abe55efSEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 9419391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 9429391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 9439391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 9449391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 9459391bb9cSRapkiewicz, Pawel 946588c3f0dSKowalski, Kamil entityPrivileges = { 947588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 948e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 949e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 950e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 951e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 952e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 9539391bb9cSRapkiewicz, Pawel } 9549391bb9cSRapkiewicz, Pawel 955e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 956e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 957e439f0f8SKowalski, Kamil const nlohmann::json &input, 958588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 959e439f0f8SKowalski, Kamil const std::string &pathPrefix, 960*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 961*1abe55efSEd Tanous { 962*1abe55efSEd Tanous if (!input.is_object()) 963*1abe55efSEd Tanous { 964588c3f0dSKowalski, Kamil messages::addMessageToJson( 96555c7b7a2SEd Tanous asyncResp->res.jsonValue, 966*1abe55efSEd Tanous messages::propertyValueTypeError(input.dump(), "VLAN"), 967*1abe55efSEd Tanous pathPrefix); 968588c3f0dSKowalski, Kamil return; 969588c3f0dSKowalski, Kamil } 970588c3f0dSKowalski, Kamil 971e439f0f8SKowalski, Kamil const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix; 972e439f0f8SKowalski, Kamil nlohmann::json ¶msJson = 973e439f0f8SKowalski, Kamil (pathPrefix == "/") 97455c7b7a2SEd Tanous ? asyncResp->res.jsonValue 975*1abe55efSEd Tanous : asyncResp->res 976*1abe55efSEd Tanous .jsonValue[nlohmann::json_pointer<nlohmann::json>( 977e439f0f8SKowalski, Kamil pathPrefix)]; 978588c3f0dSKowalski, Kamil bool inputVlanEnabled; 979588c3f0dSKowalski, Kamil uint64_t inputVlanId; 980e439f0f8SKowalski, Kamil 981588c3f0dSKowalski, Kamil json_util::Result inputVlanEnabledState = json_util::getBool( 982588c3f0dSKowalski, Kamil "VLANEnable", input, inputVlanEnabled, 983588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 98455c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable")); 985588c3f0dSKowalski, Kamil json_util::Result inputVlanIdState = json_util::getUnsigned( 986588c3f0dSKowalski, Kamil "VLANId", input, inputVlanId, 987588c3f0dSKowalski, Kamil static_cast<int>(json_util::MessageSetting::TYPE_ERROR), 98855c7b7a2SEd Tanous asyncResp->res.jsonValue, std::string(pathStart + "/VLANId")); 989588c3f0dSKowalski, Kamil bool inputInvalid = false; 990588c3f0dSKowalski, Kamil 991588c3f0dSKowalski, Kamil // Do not proceed if fields in VLAN object were of wrong type 992588c3f0dSKowalski, Kamil if (inputVlanEnabledState == json_util::Result::WRONG_TYPE || 993*1abe55efSEd Tanous inputVlanIdState == json_util::Result::WRONG_TYPE) 994*1abe55efSEd Tanous { 995588c3f0dSKowalski, Kamil return; 996588c3f0dSKowalski, Kamil } 997588c3f0dSKowalski, Kamil 998588c3f0dSKowalski, Kamil // Verify input 999*1abe55efSEd Tanous if (eth_data.vlanId == nullptr) 1000*1abe55efSEd Tanous { 1001e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 1002e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 100355c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1004588c3f0dSKowalski, Kamil messages::propertyMissing("VLANEnable"), 1005e439f0f8SKowalski, Kamil pathPrefix); 1006588c3f0dSKowalski, Kamil 1007588c3f0dSKowalski, Kamil inputInvalid = true; 1008*1abe55efSEd Tanous } 1009*1abe55efSEd Tanous else 1010*1abe55efSEd Tanous { 1011588c3f0dSKowalski, Kamil // Load actual data into field values if they were not provided 1012*1abe55efSEd Tanous if (inputVlanEnabledState == json_util::Result::NOT_EXIST) 1013*1abe55efSEd Tanous { 1014588c3f0dSKowalski, Kamil inputVlanEnabled = true; 1015588c3f0dSKowalski, Kamil } 1016588c3f0dSKowalski, Kamil 1017*1abe55efSEd Tanous if (inputVlanIdState == json_util::Result::NOT_EXIST) 1018*1abe55efSEd Tanous { 101955c7b7a2SEd Tanous inputVlanId = *eth_data.vlanId; 1020588c3f0dSKowalski, Kamil } 1021588c3f0dSKowalski, Kamil } 1022588c3f0dSKowalski, Kamil 1023588c3f0dSKowalski, Kamil // Do not proceed if input has not been valid 1024*1abe55efSEd Tanous if (inputInvalid) 1025*1abe55efSEd Tanous { 1026588c3f0dSKowalski, Kamil return; 1027588c3f0dSKowalski, Kamil } 1028588c3f0dSKowalski, Kamil 1029588c3f0dSKowalski, Kamil // VLAN is configured on the interface 1030*1abe55efSEd Tanous if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId) 1031*1abe55efSEd Tanous { 1032588c3f0dSKowalski, Kamil // Change VLAN Id 1033e439f0f8SKowalski, Kamil paramsJson["VLANId"] = inputVlanId; 1034e439f0f8SKowalski, Kamil OnDemandEthernetProvider::changeVlanId( 1035e439f0f8SKowalski, Kamil ifaceId, static_cast<uint32_t>(inputVlanId), 1036e439f0f8SKowalski, Kamil [&, asyncResp, pathPrefx{std::move(pathPrefix)}]( 1037e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 1038*1abe55efSEd Tanous if (ec) 1039*1abe55efSEd Tanous { 104055c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1041*1abe55efSEd Tanous messages::internalError(), 1042*1abe55efSEd Tanous pathPrefix); 1043*1abe55efSEd Tanous } 1044*1abe55efSEd Tanous else 1045*1abe55efSEd Tanous { 1046e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = true; 1047e439f0f8SKowalski, Kamil } 1048e439f0f8SKowalski, Kamil }); 1049*1abe55efSEd Tanous } 1050*1abe55efSEd Tanous else if (inputVlanEnabled == false) 1051*1abe55efSEd Tanous { 1052e439f0f8SKowalski, Kamil // Disable VLAN 1053e439f0f8SKowalski, Kamil OnDemandEthernetProvider::disableVlan( 1054e439f0f8SKowalski, Kamil ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)}]( 1055e439f0f8SKowalski, Kamil const boost::system::error_code ec) { 1056*1abe55efSEd Tanous if (ec) 1057*1abe55efSEd Tanous { 105855c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1059*1abe55efSEd Tanous messages::internalError(), 1060*1abe55efSEd Tanous pathPrefix); 1061*1abe55efSEd Tanous } 1062*1abe55efSEd Tanous else 1063*1abe55efSEd Tanous { 1064e439f0f8SKowalski, Kamil paramsJson["VLANEnable"] = false; 1065588c3f0dSKowalski, Kamil } 1066588c3f0dSKowalski, Kamil }); 1067588c3f0dSKowalski, Kamil } 1068588c3f0dSKowalski, Kamil } 1069588c3f0dSKowalski, Kamil 1070e439f0f8SKowalski, Kamil private: 1071588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 1072588c3f0dSKowalski, Kamil const EthernetInterfaceData ð_data, 1073*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 1074*1abe55efSEd Tanous { 1075*1abe55efSEd Tanous if (input.is_string()) 1076*1abe55efSEd Tanous { 1077588c3f0dSKowalski, Kamil std::string newHostname = input.get<std::string>(); 1078588c3f0dSKowalski, Kamil 1079*1abe55efSEd Tanous if (eth_data.hostname == nullptr || 1080*1abe55efSEd Tanous newHostname != *eth_data.hostname) 1081*1abe55efSEd Tanous { 1082588c3f0dSKowalski, Kamil // Change hostname 108355c7b7a2SEd Tanous ethernetProvider.setHostName( 1084*1abe55efSEd Tanous newHostname, [asyncResp, newHostname]( 1085*1abe55efSEd Tanous const boost::system::error_code ec) { 1086*1abe55efSEd Tanous if (ec) 1087*1abe55efSEd Tanous { 1088*1abe55efSEd Tanous messages::addMessageToJson( 1089*1abe55efSEd Tanous asyncResp->res.jsonValue, 1090*1abe55efSEd Tanous messages::internalError(), "/HostName"); 1091*1abe55efSEd Tanous } 1092*1abe55efSEd Tanous else 1093*1abe55efSEd Tanous { 109455c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 1095588c3f0dSKowalski, Kamil } 1096588c3f0dSKowalski, Kamil }); 1097588c3f0dSKowalski, Kamil } 1098*1abe55efSEd Tanous } 1099*1abe55efSEd Tanous else 1100*1abe55efSEd Tanous { 1101588c3f0dSKowalski, Kamil messages::addMessageToJson( 110255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1103588c3f0dSKowalski, Kamil messages::propertyValueTypeError(input.dump(), "HostName"), 1104588c3f0dSKowalski, Kamil "/HostName"); 1105588c3f0dSKowalski, Kamil } 1106588c3f0dSKowalski, Kamil } 1107588c3f0dSKowalski, Kamil 1108*1abe55efSEd Tanous void handleIPv4Patch(const std::string &ifaceId, 1109*1abe55efSEd Tanous const nlohmann::json &input, 1110179db1d7SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data, 1111*1abe55efSEd Tanous const std::shared_ptr<AsyncResp> &asyncResp) 1112*1abe55efSEd Tanous { 1113*1abe55efSEd Tanous if (!input.is_array()) 1114*1abe55efSEd Tanous { 1115179db1d7SKowalski, Kamil messages::addMessageToJson( 111655c7b7a2SEd Tanous asyncResp->res.jsonValue, 1117179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 1118179db1d7SKowalski, Kamil "/IPv4Addresses"); 1119179db1d7SKowalski, Kamil return; 1120179db1d7SKowalski, Kamil } 1121179db1d7SKowalski, Kamil 1122179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 1123*1abe55efSEd Tanous if (input.size() < ipv4_data.size()) 1124*1abe55efSEd Tanous { 1125*1abe55efSEd Tanous // TODO(kkowalsk) This should be a message indicating that not 1126*1abe55efSEd Tanous // enough data has been provided 112755c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1128*1abe55efSEd Tanous messages::internalError(), 1129*1abe55efSEd Tanous "/IPv4Addresses"); 1130179db1d7SKowalski, Kamil return; 1131179db1d7SKowalski, Kamil } 1132179db1d7SKowalski, Kamil 1133179db1d7SKowalski, Kamil json_util::Result addressFieldState; 1134179db1d7SKowalski, Kamil json_util::Result subnetMaskFieldState; 1135179db1d7SKowalski, Kamil json_util::Result addressOriginFieldState; 1136179db1d7SKowalski, Kamil json_util::Result gatewayFieldState; 1137179db1d7SKowalski, Kamil const std::string *addressFieldValue; 1138179db1d7SKowalski, Kamil const std::string *subnetMaskFieldValue; 1139179db1d7SKowalski, Kamil const std::string *addressOriginFieldValue = nullptr; 1140179db1d7SKowalski, Kamil const std::string *gatewayFieldValue; 1141179db1d7SKowalski, Kamil uint8_t subnetMaskAsPrefixLength; 1142179db1d7SKowalski, Kamil std::string addressOriginInDBusFormat; 1143179db1d7SKowalski, Kamil 1144179db1d7SKowalski, Kamil bool errorDetected = false; 1145*1abe55efSEd Tanous for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) 1146*1abe55efSEd Tanous { 1147179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 1148*1abe55efSEd Tanous if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) 1149*1abe55efSEd Tanous { 1150179db1d7SKowalski, Kamil // Invalid object type 1151179db1d7SKowalski, Kamil messages::addMessageToJson( 115255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1153179db1d7SKowalski, Kamil messages::propertyValueTypeError(input[entryIdx].dump(), 1154179db1d7SKowalski, Kamil "IPv4Address"), 1155179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx)); 1156179db1d7SKowalski, Kamil 1157179db1d7SKowalski, Kamil continue; 1158179db1d7SKowalski, Kamil } 1159179db1d7SKowalski, Kamil 1160179db1d7SKowalski, Kamil // Try to load fields 1161179db1d7SKowalski, Kamil addressFieldState = json_util::getString( 1162179db1d7SKowalski, Kamil "Address", input[entryIdx], addressFieldValue, 1163179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 116455c7b7a2SEd Tanous asyncResp->res.jsonValue, 1165179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1166179db1d7SKowalski, Kamil subnetMaskFieldState = json_util::getString( 1167179db1d7SKowalski, Kamil "SubnetMask", input[entryIdx], subnetMaskFieldValue, 1168179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 116955c7b7a2SEd Tanous asyncResp->res.jsonValue, 1170179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask"); 1171179db1d7SKowalski, Kamil addressOriginFieldState = json_util::getString( 1172179db1d7SKowalski, Kamil "AddressOrigin", input[entryIdx], addressOriginFieldValue, 1173179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 117455c7b7a2SEd Tanous asyncResp->res.jsonValue, 1175*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1176*1abe55efSEd Tanous "/AddressOrigin"); 1177179db1d7SKowalski, Kamil gatewayFieldState = json_util::getString( 1178179db1d7SKowalski, Kamil "Gateway", input[entryIdx], gatewayFieldValue, 1179179db1d7SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 118055c7b7a2SEd Tanous asyncResp->res.jsonValue, 1181179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1182179db1d7SKowalski, Kamil 1183179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::WRONG_TYPE || 1184179db1d7SKowalski, Kamil subnetMaskFieldState == json_util::Result::WRONG_TYPE || 1185179db1d7SKowalski, Kamil addressOriginFieldState == json_util::Result::WRONG_TYPE || 1186*1abe55efSEd Tanous gatewayFieldState == json_util::Result::WRONG_TYPE) 1187*1abe55efSEd Tanous { 1188179db1d7SKowalski, Kamil return; 1189179db1d7SKowalski, Kamil } 1190179db1d7SKowalski, Kamil 1191179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1192*1abe55efSEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount( 1193*1abe55efSEd Tanous *addressFieldValue)) 1194*1abe55efSEd Tanous { 1195179db1d7SKowalski, Kamil errorDetected = true; 1196179db1d7SKowalski, Kamil messages::addMessageToJson( 119755c7b7a2SEd Tanous asyncResp->res.jsonValue, 1198*1abe55efSEd Tanous messages::propertyValueFormatError(*addressFieldValue, 1199*1abe55efSEd Tanous "Address"), 1200179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address"); 1201179db1d7SKowalski, Kamil } 1202179db1d7SKowalski, Kamil 1203179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 120455c7b7a2SEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount( 1205*1abe55efSEd Tanous *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) 1206*1abe55efSEd Tanous { 1207179db1d7SKowalski, Kamil errorDetected = true; 1208179db1d7SKowalski, Kamil messages::addMessageToJson( 120955c7b7a2SEd Tanous asyncResp->res.jsonValue, 1210179db1d7SKowalski, Kamil messages::propertyValueFormatError(*subnetMaskFieldValue, 1211179db1d7SKowalski, Kamil "SubnetMask"), 1212*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1213*1abe55efSEd Tanous "/SubnetMask"); 1214179db1d7SKowalski, Kamil } 1215179db1d7SKowalski, Kamil 121655c7b7a2SEd Tanous // get Address origin in proper format 1217179db1d7SKowalski, Kamil addressOriginInDBusFormat = 121855c7b7a2SEd Tanous ethernetProvider.translateAddressOriginBetweenDBusAndRedfish( 1219179db1d7SKowalski, Kamil addressOriginFieldValue, true, false); 1220179db1d7SKowalski, Kamil 1221179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1222*1abe55efSEd Tanous addressOriginInDBusFormat.empty()) 1223*1abe55efSEd Tanous { 1224179db1d7SKowalski, Kamil errorDetected = true; 1225179db1d7SKowalski, Kamil messages::addMessageToJson( 122655c7b7a2SEd Tanous asyncResp->res.jsonValue, 1227179db1d7SKowalski, Kamil messages::propertyValueNotInList(*addressOriginFieldValue, 1228179db1d7SKowalski, Kamil "AddressOrigin"), 1229*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1230*1abe55efSEd Tanous "/AddressOrigin"); 1231179db1d7SKowalski, Kamil } 1232179db1d7SKowalski, Kamil 1233179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1234*1abe55efSEd Tanous !ethernetProvider.ipv4VerifyIpAndGetBitcount( 1235*1abe55efSEd Tanous *gatewayFieldValue)) 1236*1abe55efSEd Tanous { 1237179db1d7SKowalski, Kamil errorDetected = true; 1238179db1d7SKowalski, Kamil messages::addMessageToJson( 123955c7b7a2SEd Tanous asyncResp->res.jsonValue, 1240*1abe55efSEd Tanous messages::propertyValueFormatError(*gatewayFieldValue, 1241*1abe55efSEd Tanous "Gateway"), 1242179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway"); 1243179db1d7SKowalski, Kamil } 1244179db1d7SKowalski, Kamil 1245*1abe55efSEd Tanous // If any error occured do not proceed with current entry, but do 1246*1abe55efSEd Tanous // not end loop 1247*1abe55efSEd Tanous if (errorDetected) 1248*1abe55efSEd Tanous { 1249179db1d7SKowalski, Kamil errorDetected = false; 1250179db1d7SKowalski, Kamil continue; 1251179db1d7SKowalski, Kamil } 1252179db1d7SKowalski, Kamil 1253*1abe55efSEd Tanous if (entryIdx >= ipv4_data.size()) 1254*1abe55efSEd Tanous { 1255*1abe55efSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 1256*1abe55efSEd Tanous input[entryIdx]; 1257179db1d7SKowalski, Kamil 1258179db1d7SKowalski, Kamil // Verify that all field were provided 1259*1abe55efSEd Tanous if (addressFieldState == json_util::Result::NOT_EXIST) 1260*1abe55efSEd Tanous { 1261179db1d7SKowalski, Kamil errorDetected = true; 1262179db1d7SKowalski, Kamil messages::addMessageToJson( 1263*1abe55efSEd Tanous asyncResp->res.jsonValue, 1264*1abe55efSEd Tanous messages::propertyMissing("Address"), 1265*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1266*1abe55efSEd Tanous "/Address"); 1267179db1d7SKowalski, Kamil } 1268179db1d7SKowalski, Kamil 1269*1abe55efSEd Tanous if (subnetMaskFieldState == json_util::Result::NOT_EXIST) 1270*1abe55efSEd Tanous { 1271179db1d7SKowalski, Kamil errorDetected = true; 1272179db1d7SKowalski, Kamil messages::addMessageToJson( 1273*1abe55efSEd Tanous asyncResp->res.jsonValue, 1274*1abe55efSEd Tanous messages::propertyMissing("SubnetMask"), 1275*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1276*1abe55efSEd Tanous "/SubnetMask"); 1277179db1d7SKowalski, Kamil } 1278179db1d7SKowalski, Kamil 1279*1abe55efSEd Tanous if (addressOriginFieldState == json_util::Result::NOT_EXIST) 1280*1abe55efSEd Tanous { 1281179db1d7SKowalski, Kamil errorDetected = true; 1282179db1d7SKowalski, Kamil messages::addMessageToJson( 128355c7b7a2SEd Tanous asyncResp->res.jsonValue, 1284179db1d7SKowalski, Kamil messages::propertyMissing("AddressOrigin"), 1285*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1286*1abe55efSEd Tanous "/AddressOrigin"); 1287179db1d7SKowalski, Kamil } 1288179db1d7SKowalski, Kamil 1289*1abe55efSEd Tanous if (gatewayFieldState == json_util::Result::NOT_EXIST) 1290*1abe55efSEd Tanous { 1291179db1d7SKowalski, Kamil errorDetected = true; 1292179db1d7SKowalski, Kamil messages::addMessageToJson( 1293*1abe55efSEd Tanous asyncResp->res.jsonValue, 1294*1abe55efSEd Tanous messages::propertyMissing("Gateway"), 1295*1abe55efSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx) + 1296*1abe55efSEd Tanous "/Gateway"); 1297179db1d7SKowalski, Kamil } 1298179db1d7SKowalski, Kamil 1299*1abe55efSEd Tanous // If any error occured do not proceed with current entry, but 1300*1abe55efSEd Tanous // do not end loop 1301*1abe55efSEd Tanous if (errorDetected) 1302*1abe55efSEd Tanous { 1303179db1d7SKowalski, Kamil errorDetected = false; 1304179db1d7SKowalski, Kamil continue; 1305179db1d7SKowalski, Kamil } 1306179db1d7SKowalski, Kamil 1307179db1d7SKowalski, Kamil // Create IPv4 with provided data 1308*1abe55efSEd Tanous ethernetProvider.createIPv4( 1309*1abe55efSEd Tanous ifaceId, entryIdx, subnetMaskAsPrefixLength, 1310*1abe55efSEd Tanous *gatewayFieldValue, *addressFieldValue, asyncResp); 1311*1abe55efSEd Tanous } 1312*1abe55efSEd Tanous else 1313*1abe55efSEd Tanous { 1314*1abe55efSEd Tanous // Existing object that should be modified/deleted/remain 1315*1abe55efSEd Tanous // unchanged 1316*1abe55efSEd Tanous if (input[entryIdx].is_null()) 1317*1abe55efSEd Tanous { 1318179db1d7SKowalski, Kamil // Object should be deleted 1319*1abe55efSEd Tanous ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, 1320*1abe55efSEd Tanous entryIdx, asyncResp); 1321*1abe55efSEd Tanous } 1322*1abe55efSEd Tanous else if (input[entryIdx].is_object()) 1323*1abe55efSEd Tanous { 1324*1abe55efSEd Tanous if (input[entryIdx].size() == 0) 1325*1abe55efSEd Tanous { 1326179db1d7SKowalski, Kamil // Object shall remain unchanged 1327179db1d7SKowalski, Kamil continue; 1328179db1d7SKowalski, Kamil } 1329179db1d7SKowalski, Kamil 1330179db1d7SKowalski, Kamil // Apply changes 1331179db1d7SKowalski, Kamil if (addressFieldState == json_util::Result::SUCCESS && 1332179db1d7SKowalski, Kamil ipv4_data[entryIdx].address != nullptr && 1333*1abe55efSEd Tanous *ipv4_data[entryIdx].address != *addressFieldValue) 1334*1abe55efSEd Tanous { 133555c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1336*1abe55efSEd Tanous ifaceId, entryIdx, ipv4_data[entryIdx].id, 1337*1abe55efSEd Tanous "Address", *addressFieldValue, asyncResp); 1338179db1d7SKowalski, Kamil } 1339179db1d7SKowalski, Kamil 1340179db1d7SKowalski, Kamil if (subnetMaskFieldState == json_util::Result::SUCCESS && 1341*1abe55efSEd Tanous ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) 1342*1abe55efSEd Tanous { 134355c7b7a2SEd Tanous ethernetProvider.changeIPv4SubnetMaskProperty( 1344179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1345*1abe55efSEd Tanous *subnetMaskFieldValue, subnetMaskAsPrefixLength, 1346*1abe55efSEd Tanous asyncResp); 1347179db1d7SKowalski, Kamil } 1348179db1d7SKowalski, Kamil 1349179db1d7SKowalski, Kamil if (addressOriginFieldState == json_util::Result::SUCCESS && 1350*1abe55efSEd Tanous ipv4_data[entryIdx].origin != *addressFieldValue) 1351*1abe55efSEd Tanous { 135255c7b7a2SEd Tanous ethernetProvider.changeIPv4Origin( 1353179db1d7SKowalski, Kamil ifaceId, entryIdx, ipv4_data[entryIdx].id, 1354*1abe55efSEd Tanous *addressOriginFieldValue, addressOriginInDBusFormat, 1355*1abe55efSEd Tanous asyncResp); 1356179db1d7SKowalski, Kamil } 1357179db1d7SKowalski, Kamil 1358179db1d7SKowalski, Kamil if (gatewayFieldState == json_util::Result::SUCCESS && 1359179db1d7SKowalski, Kamil ipv4_data[entryIdx].gateway != nullptr && 1360*1abe55efSEd Tanous *ipv4_data[entryIdx].gateway != *gatewayFieldValue) 1361*1abe55efSEd Tanous { 136255c7b7a2SEd Tanous ethernetProvider.changeIPv4AddressProperty( 1363*1abe55efSEd Tanous ifaceId, entryIdx, ipv4_data[entryIdx].id, 1364*1abe55efSEd Tanous "Gateway", *gatewayFieldValue, asyncResp); 1365179db1d7SKowalski, Kamil } 1366179db1d7SKowalski, Kamil } 1367179db1d7SKowalski, Kamil } 1368179db1d7SKowalski, Kamil } 1369179db1d7SKowalski, Kamil } 1370179db1d7SKowalski, Kamil 1371*1abe55efSEd Tanous nlohmann::json 1372*1abe55efSEd Tanous parseInterfaceData(const std::string &ifaceId, 1373*1abe55efSEd Tanous const EthernetInterfaceData ð_data, 1374*1abe55efSEd Tanous const std::vector<IPv4AddressData> &ipv4_data) 1375*1abe55efSEd Tanous { 1376588c3f0dSKowalski, Kamil // Copy JSON object to avoid race condition 137755c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1378588c3f0dSKowalski, Kamil 1379588c3f0dSKowalski, Kamil // Fill out obvious data... 138055c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 138155c7b7a2SEd Tanous jsonResponse["@odata.id"] = 138255c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId; 1383588c3f0dSKowalski, Kamil 1384588c3f0dSKowalski, Kamil // ... then the one from DBus, regarding eth iface... 1385*1abe55efSEd Tanous if (eth_data.speed != nullptr) 1386*1abe55efSEd Tanous jsonResponse["SpeedMbps"] = *eth_data.speed; 1387588c3f0dSKowalski, Kamil 138855c7b7a2SEd Tanous if (eth_data.macAddress != nullptr) 138955c7b7a2SEd Tanous jsonResponse["MACAddress"] = *eth_data.macAddress; 1390588c3f0dSKowalski, Kamil 1391588c3f0dSKowalski, Kamil if (eth_data.hostname != nullptr) 139255c7b7a2SEd Tanous jsonResponse["HostName"] = *eth_data.hostname; 1393588c3f0dSKowalski, Kamil 1394*1abe55efSEd Tanous if (eth_data.vlanId != nullptr) 1395*1abe55efSEd Tanous { 139655c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLAN"]; 1397588c3f0dSKowalski, Kamil vlanObj["VLANEnable"] = true; 139855c7b7a2SEd Tanous vlanObj["VLANId"] = *eth_data.vlanId; 1399*1abe55efSEd Tanous } 1400*1abe55efSEd Tanous else 1401*1abe55efSEd Tanous { 140255c7b7a2SEd Tanous nlohmann::json &vlanObj = jsonResponse["VLANs"]; 1403eb547730SKowalski, Kamil vlanObj["@odata.id"] = 140455c7b7a2SEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId + 1405eb547730SKowalski, Kamil "/VLANs"; 1406588c3f0dSKowalski, Kamil } 1407588c3f0dSKowalski, Kamil 1408588c3f0dSKowalski, Kamil // ... at last, check if there are IPv4 data and prepare appropriate 1409588c3f0dSKowalski, Kamil // collection 1410*1abe55efSEd Tanous if (ipv4_data.size() > 0) 1411*1abe55efSEd Tanous { 141255c7b7a2SEd Tanous nlohmann::json ipv4Array = nlohmann::json::array(); 1413*1abe55efSEd Tanous for (auto &ipv4Config : ipv4_data) 1414*1abe55efSEd Tanous { 141555c7b7a2SEd Tanous nlohmann::json jsonIpv4; 1416*1abe55efSEd Tanous if (ipv4Config.address != nullptr) 1417*1abe55efSEd Tanous { 141855c7b7a2SEd Tanous jsonIpv4["Address"] = *ipv4Config.address; 141955c7b7a2SEd Tanous if (ipv4Config.gateway != nullptr) 142055c7b7a2SEd Tanous jsonIpv4["Gateway"] = *ipv4Config.gateway; 1421588c3f0dSKowalski, Kamil 142255c7b7a2SEd Tanous jsonIpv4["AddressOrigin"] = ipv4Config.origin; 142355c7b7a2SEd Tanous jsonIpv4["SubnetMask"] = ipv4Config.netmask; 1424588c3f0dSKowalski, Kamil 142555c7b7a2SEd Tanous ipv4Array.push_back(std::move(jsonIpv4)); 1426588c3f0dSKowalski, Kamil } 1427588c3f0dSKowalski, Kamil } 142855c7b7a2SEd Tanous jsonResponse["IPv4Addresses"] = std::move(ipv4Array); 1429588c3f0dSKowalski, Kamil } 1430588c3f0dSKowalski, Kamil 143155c7b7a2SEd Tanous return jsonResponse; 1432588c3f0dSKowalski, Kamil } 1433588c3f0dSKowalski, Kamil 14349391bb9cSRapkiewicz, Pawel /** 14359391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 14369391bb9cSRapkiewicz, Pawel */ 143755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1438*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1439*1abe55efSEd Tanous { 14409391bb9cSRapkiewicz, Pawel // TODO(Pawel) this shall be parametrized call (two params) to get 14419391bb9cSRapkiewicz, Pawel // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 14429391bb9cSRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 14439391bb9cSRapkiewicz, Pawel // impossible. 1444*1abe55efSEd Tanous if (params.size() != 1) 1445*1abe55efSEd Tanous { 1446e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 14479391bb9cSRapkiewicz, Pawel res.end(); 14489391bb9cSRapkiewicz, Pawel return; 14499391bb9cSRapkiewicz, Pawel } 14509391bb9cSRapkiewicz, Pawel 145155c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 14529391bb9cSRapkiewicz, Pawel 145355c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 14549391bb9cSRapkiewicz, Pawel // preparation 145555c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 145655c7b7a2SEd Tanous ifaceId, 1457*1abe55efSEd Tanous [&, ifaceId](const bool &success, 1458*1abe55efSEd Tanous const EthernetInterfaceData ð_data, 14599391bb9cSRapkiewicz, Pawel const std::vector<IPv4AddressData> &ipv4_data) { 1460*1abe55efSEd Tanous if (success) 1461*1abe55efSEd Tanous { 1462*1abe55efSEd Tanous res.jsonValue = 1463*1abe55efSEd Tanous parseInterfaceData(ifaceId, eth_data, ipv4_data); 1464*1abe55efSEd Tanous } 1465*1abe55efSEd Tanous else 1466*1abe55efSEd Tanous { 14679391bb9cSRapkiewicz, Pawel // ... otherwise return error 1468*1abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 1469*1abe55efSEd Tanous // object, and other errors 1470e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1471*1abe55efSEd Tanous res.jsonValue, messages::resourceNotFound( 1472*1abe55efSEd Tanous "EthernetInterface", ifaceId)); 1473e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 14749391bb9cSRapkiewicz, Pawel } 14759391bb9cSRapkiewicz, Pawel res.end(); 14769391bb9cSRapkiewicz, Pawel }); 14779391bb9cSRapkiewicz, Pawel } 14789391bb9cSRapkiewicz, Pawel 147955c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1480*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1481*1abe55efSEd Tanous { 1482588c3f0dSKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1483588c3f0dSKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1484588c3f0dSKowalski, Kamil // Check if there is required param, truly entering this shall be 1485588c3f0dSKowalski, Kamil // impossible. 1486*1abe55efSEd Tanous if (params.size() != 1) 1487*1abe55efSEd Tanous { 1488588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1489588c3f0dSKowalski, Kamil res.end(); 1490588c3f0dSKowalski, Kamil return; 1491588c3f0dSKowalski, Kamil } 1492588c3f0dSKowalski, Kamil 149355c7b7a2SEd Tanous const std::string &ifaceId = params[0]; 1494588c3f0dSKowalski, Kamil 1495179db1d7SKowalski, Kamil nlohmann::json patchReq; 1496588c3f0dSKowalski, Kamil 1497*1abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 1498*1abe55efSEd Tanous { 1499588c3f0dSKowalski, Kamil return; 1500588c3f0dSKowalski, Kamil } 1501588c3f0dSKowalski, Kamil 150255c7b7a2SEd Tanous // get single eth interface data, and call the below callback for JSON 1503588c3f0dSKowalski, Kamil // preparation 150455c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1505*1abe55efSEd Tanous ifaceId, 1506*1abe55efSEd Tanous [&, ifaceId, patchReq = std::move(patchReq)]( 1507588c3f0dSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1508588c3f0dSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1509*1abe55efSEd Tanous if (!success) 1510*1abe55efSEd Tanous { 1511588c3f0dSKowalski, Kamil // ... otherwise return error 1512*1abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 1513*1abe55efSEd Tanous // object, and other errors 1514927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1515*1abe55efSEd Tanous res.jsonValue, messages::resourceNotFound( 1516*1abe55efSEd Tanous "VLAN Network Interface", ifaceId)); 1517588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1518588c3f0dSKowalski, Kamil res.end(); 1519588c3f0dSKowalski, Kamil 1520588c3f0dSKowalski, Kamil return; 1521588c3f0dSKowalski, Kamil } 1522588c3f0dSKowalski, Kamil 1523*1abe55efSEd Tanous res.jsonValue = 1524*1abe55efSEd Tanous parseInterfaceData(ifaceId, eth_data, ipv4_data); 1525588c3f0dSKowalski, Kamil 1526588c3f0dSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1527588c3f0dSKowalski, Kamil std::make_shared<AsyncResp>(res); 1528588c3f0dSKowalski, Kamil 1529*1abe55efSEd Tanous for (auto propertyIt = patchReq.begin(); 1530*1abe55efSEd Tanous propertyIt != patchReq.end(); ++propertyIt) 1531*1abe55efSEd Tanous { 1532*1abe55efSEd Tanous if (propertyIt.key() == "VLAN") 1533*1abe55efSEd Tanous { 1534*1abe55efSEd Tanous handleVlanPatch(ifaceId, propertyIt.value(), eth_data, 1535*1abe55efSEd Tanous "/VLAN", asyncResp); 1536*1abe55efSEd Tanous } 1537*1abe55efSEd Tanous else if (propertyIt.key() == "HostName") 1538*1abe55efSEd Tanous { 1539*1abe55efSEd Tanous handleHostnamePatch(propertyIt.value(), eth_data, 1540588c3f0dSKowalski, Kamil asyncResp); 1541*1abe55efSEd Tanous } 1542*1abe55efSEd Tanous else if (propertyIt.key() == "IPv4Addresses") 1543*1abe55efSEd Tanous { 154455c7b7a2SEd Tanous handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data, 1545179db1d7SKowalski, Kamil asyncResp); 1546*1abe55efSEd Tanous } 1547*1abe55efSEd Tanous else if (propertyIt.key() == "IPv6Addresses") 1548*1abe55efSEd Tanous { 1549179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1550179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 155155c7b7a2SEd Tanous res.jsonValue, 1552179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 1553*1abe55efSEd Tanous } 1554*1abe55efSEd Tanous else 1555*1abe55efSEd Tanous { 1556*1abe55efSEd Tanous auto fieldInJsonIt = 1557*1abe55efSEd Tanous res.jsonValue.find(propertyIt.key()); 1558588c3f0dSKowalski, Kamil 1559*1abe55efSEd Tanous if (fieldInJsonIt == res.jsonValue.end()) 1560*1abe55efSEd Tanous { 1561588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1562588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1563*1abe55efSEd Tanous res.jsonValue, 1564*1abe55efSEd Tanous messages::propertyUnknown(propertyIt.key())); 1565*1abe55efSEd Tanous } 1566*1abe55efSEd Tanous else if (*fieldInJsonIt != *propertyIt) 1567*1abe55efSEd Tanous { 1568588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1569588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1570*1abe55efSEd Tanous res.jsonValue, messages::propertyNotWritable( 1571*1abe55efSEd Tanous propertyIt.key())); 1572588c3f0dSKowalski, Kamil } 1573588c3f0dSKowalski, Kamil } 1574588c3f0dSKowalski, Kamil } 1575588c3f0dSKowalski, Kamil }); 1576588c3f0dSKowalski, Kamil } 1577588c3f0dSKowalski, Kamil 15789391bb9cSRapkiewicz, Pawel // Ethernet Provider object 15799391bb9cSRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 158055c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 15819391bb9cSRapkiewicz, Pawel }; 15829391bb9cSRapkiewicz, Pawel 1583e439f0f8SKowalski, Kamil class VlanNetworkInterfaceCollection; 1584e439f0f8SKowalski, Kamil 1585e439f0f8SKowalski, Kamil /** 1586e439f0f8SKowalski, Kamil * VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema 1587e439f0f8SKowalski, Kamil */ 1588*1abe55efSEd Tanous class VlanNetworkInterface : public Node 1589*1abe55efSEd Tanous { 1590e439f0f8SKowalski, Kamil public: 1591e439f0f8SKowalski, Kamil /* 1592e439f0f8SKowalski, Kamil * Default Constructor 1593e439f0f8SKowalski, Kamil */ 1594e439f0f8SKowalski, Kamil template <typename CrowApp> 1595*1abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 1596*1abe55efSEd Tanous // one manager called openbmc This shall be generic, but requires to update 1597e439f0f8SKowalski, Kamil // GetSubroutes method 1598*1abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 1599*1abe55efSEd Tanous Node( 1600eb547730SKowalski, Kamil app, 1601eb547730SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/<str>", 1602*1abe55efSEd Tanous std::string(), std::string()) 1603*1abe55efSEd Tanous { 1604e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1605e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1606e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1607e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1608e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1609e439f0f8SKowalski, Kamil 1610e439f0f8SKowalski, Kamil entityPrivileges = { 1611e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1612e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1613e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1614e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1615e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1616e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1617e439f0f8SKowalski, Kamil } 1618e439f0f8SKowalski, Kamil 1619e439f0f8SKowalski, Kamil private: 1620*1abe55efSEd Tanous nlohmann::json 1621*1abe55efSEd Tanous parseInterfaceData(const std::string &parent_ifaceId, 1622*1abe55efSEd Tanous const std::string &ifaceId, 1623e439f0f8SKowalski, Kamil const EthernetInterfaceData ð_data, 1624*1abe55efSEd Tanous const std::vector<IPv4AddressData> &ipv4_data) 1625*1abe55efSEd Tanous { 1626e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 162755c7b7a2SEd Tanous nlohmann::json jsonResponse(Node::json); 1628e439f0f8SKowalski, Kamil 1629e439f0f8SKowalski, Kamil // Fill out obvious data... 163055c7b7a2SEd Tanous jsonResponse["Id"] = ifaceId; 163155c7b7a2SEd Tanous jsonResponse["@odata.id"] = 1632*1abe55efSEd Tanous "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + 1633*1abe55efSEd Tanous parent_ifaceId + "/VLANs/" + ifaceId; 1634e439f0f8SKowalski, Kamil 163555c7b7a2SEd Tanous jsonResponse["VLANEnable"] = true; 163655c7b7a2SEd Tanous jsonResponse["VLANId"] = *eth_data.vlanId; 1637e439f0f8SKowalski, Kamil 163855c7b7a2SEd Tanous return jsonResponse; 1639e439f0f8SKowalski, Kamil } 1640e439f0f8SKowalski, Kamil 164155c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 1642*1abe55efSEd Tanous const std::string &iface) 1643*1abe55efSEd Tanous { 1644*1abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 1645*1abe55efSEd Tanous { 1646927a505aSKowalski, Kamil messages::addMessageToErrorJson( 164755c7b7a2SEd Tanous res.jsonValue, 1648927a505aSKowalski, Kamil messages::resourceNotFound("VLAN Network Interface", iface)); 1649927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1650927a505aSKowalski, Kamil res.end(); 1651927a505aSKowalski, Kamil 1652927a505aSKowalski, Kamil return false; 1653*1abe55efSEd Tanous } 1654*1abe55efSEd Tanous else 1655*1abe55efSEd Tanous { 1656927a505aSKowalski, Kamil return true; 1657927a505aSKowalski, Kamil } 1658927a505aSKowalski, Kamil } 1659927a505aSKowalski, Kamil 1660e439f0f8SKowalski, Kamil /** 1661e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1662e439f0f8SKowalski, Kamil */ 166355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1664*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1665*1abe55efSEd Tanous { 1666e439f0f8SKowalski, Kamil // TODO(Pawel) this shall be parametrized call (two params) to get 1667e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1668e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1669e439f0f8SKowalski, Kamil // impossible. 1670*1abe55efSEd Tanous if (params.size() != 2) 1671*1abe55efSEd Tanous { 1672e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1673e439f0f8SKowalski, Kamil res.end(); 1674e439f0f8SKowalski, Kamil return; 1675e439f0f8SKowalski, Kamil } 1676e439f0f8SKowalski, Kamil 167755c7b7a2SEd Tanous const std::string &parentIfaceId = params[0]; 167855c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1679e439f0f8SKowalski, Kamil 1680*1abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 1681*1abe55efSEd Tanous { 1682a434f2bdSEd Tanous return; 1683a434f2bdSEd Tanous } 1684a434f2bdSEd Tanous 1685e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1686e439f0f8SKowalski, Kamil // preparation 168755c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1688*1abe55efSEd Tanous ifaceId, [&, parentIfaceId, 1689*1abe55efSEd Tanous ifaceId](const bool &success, 1690*1abe55efSEd Tanous const EthernetInterfaceData ð_data, 1691e439f0f8SKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1692*1abe55efSEd Tanous if (success && eth_data.vlanId != nullptr) 1693*1abe55efSEd Tanous { 1694*1abe55efSEd Tanous res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId, 1695*1abe55efSEd Tanous eth_data, ipv4_data); 1696*1abe55efSEd Tanous } 1697*1abe55efSEd Tanous else 1698*1abe55efSEd Tanous { 1699e439f0f8SKowalski, Kamil // ... otherwise return error 1700*1abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 1701*1abe55efSEd Tanous // object, and other errors 1702927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1703*1abe55efSEd Tanous res.jsonValue, messages::resourceNotFound( 1704*1abe55efSEd Tanous "VLAN Network Interface", ifaceId)); 1705e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1706e439f0f8SKowalski, Kamil } 1707e439f0f8SKowalski, Kamil res.end(); 1708e439f0f8SKowalski, Kamil }); 1709e439f0f8SKowalski, Kamil } 1710e439f0f8SKowalski, Kamil 171155c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 1712*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1713*1abe55efSEd Tanous { 1714*1abe55efSEd Tanous if (params.size() != 2) 1715*1abe55efSEd Tanous { 1716e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1717e439f0f8SKowalski, Kamil res.end(); 1718e439f0f8SKowalski, Kamil return; 1719e439f0f8SKowalski, Kamil } 1720e439f0f8SKowalski, Kamil 1721d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 172255c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1723927a505aSKowalski, Kamil 1724*1abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 1725*1abe55efSEd Tanous { 1726927a505aSKowalski, Kamil return; 1727927a505aSKowalski, Kamil } 1728927a505aSKowalski, Kamil 1729927a505aSKowalski, Kamil nlohmann::json patchReq; 1730927a505aSKowalski, Kamil 1731*1abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 1732*1abe55efSEd Tanous { 1733927a505aSKowalski, Kamil return; 1734927a505aSKowalski, Kamil } 1735927a505aSKowalski, Kamil 1736927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1737927a505aSKowalski, Kamil // preparation 173855c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1739*1abe55efSEd Tanous ifaceId, 1740*1abe55efSEd Tanous [&, parentIfaceId, ifaceId, patchReq = std::move(patchReq)]( 1741927a505aSKowalski, Kamil const bool &success, const EthernetInterfaceData ð_data, 1742927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1743*1abe55efSEd Tanous if (!success) 1744*1abe55efSEd Tanous { 1745927a505aSKowalski, Kamil // ... otherwise return error 1746*1abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 1747*1abe55efSEd Tanous // object, and other errors 1748927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1749*1abe55efSEd Tanous res.jsonValue, messages::resourceNotFound( 1750*1abe55efSEd Tanous "VLAN Network Interface", ifaceId)); 1751927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1752e439f0f8SKowalski, Kamil res.end(); 1753927a505aSKowalski, Kamil 1754927a505aSKowalski, Kamil return; 1755927a505aSKowalski, Kamil } 1756927a505aSKowalski, Kamil 1757*1abe55efSEd Tanous res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId, 1758*1abe55efSEd Tanous eth_data, ipv4_data); 1759927a505aSKowalski, Kamil 1760927a505aSKowalski, Kamil std::shared_ptr<AsyncResp> asyncResp = 1761927a505aSKowalski, Kamil std::make_shared<AsyncResp>(res); 1762927a505aSKowalski, Kamil 1763*1abe55efSEd Tanous for (auto propertyIt = patchReq.begin(); 1764*1abe55efSEd Tanous propertyIt != patchReq.end(); ++propertyIt) 1765*1abe55efSEd Tanous { 1766927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 1767*1abe55efSEd Tanous propertyIt.key() != "VLANId") 1768*1abe55efSEd Tanous { 1769*1abe55efSEd Tanous auto fieldInJsonIt = 1770*1abe55efSEd Tanous res.jsonValue.find(propertyIt.key()); 1771927a505aSKowalski, Kamil 1772*1abe55efSEd Tanous if (fieldInJsonIt == res.jsonValue.end()) 1773*1abe55efSEd Tanous { 1774927a505aSKowalski, Kamil // Field not in scope of defined fields 1775927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1776*1abe55efSEd Tanous res.jsonValue, 1777*1abe55efSEd Tanous messages::propertyUnknown(propertyIt.key())); 1778*1abe55efSEd Tanous } 1779*1abe55efSEd Tanous else if (*fieldInJsonIt != *propertyIt) 1780*1abe55efSEd Tanous { 1781927a505aSKowalski, Kamil // User attempted to modify non-writable field 1782927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1783*1abe55efSEd Tanous res.jsonValue, messages::propertyNotWritable( 1784*1abe55efSEd Tanous propertyIt.key())); 1785927a505aSKowalski, Kamil } 1786927a505aSKowalski, Kamil } 1787927a505aSKowalski, Kamil } 1788927a505aSKowalski, Kamil 1789*1abe55efSEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data, 1790*1abe55efSEd Tanous "/", asyncResp); 1791927a505aSKowalski, Kamil }); 1792e439f0f8SKowalski, Kamil } 1793e439f0f8SKowalski, Kamil 179455c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 1795*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1796*1abe55efSEd Tanous { 1797*1abe55efSEd Tanous if (params.size() != 2) 1798*1abe55efSEd Tanous { 1799e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1800e439f0f8SKowalski, Kamil res.end(); 1801e439f0f8SKowalski, Kamil return; 1802e439f0f8SKowalski, Kamil } 1803e439f0f8SKowalski, Kamil 1804d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 180555c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1806927a505aSKowalski, Kamil 1807*1abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 1808*1abe55efSEd Tanous { 1809927a505aSKowalski, Kamil return; 1810927a505aSKowalski, Kamil } 1811927a505aSKowalski, Kamil 1812927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1813927a505aSKowalski, Kamil // preparation 181455c7b7a2SEd Tanous ethernetProvider.getEthernetIfaceData( 1815*1abe55efSEd Tanous ifaceId, [&, parentIfaceId, 1816*1abe55efSEd Tanous ifaceId](const bool &success, 1817*1abe55efSEd Tanous const EthernetInterfaceData ð_data, 1818927a505aSKowalski, Kamil const std::vector<IPv4AddressData> &ipv4_data) { 1819*1abe55efSEd Tanous if (success && eth_data.vlanId != nullptr) 1820*1abe55efSEd Tanous { 1821*1abe55efSEd Tanous res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId, 1822*1abe55efSEd Tanous eth_data, ipv4_data); 1823927a505aSKowalski, Kamil 1824927a505aSKowalski, Kamil // Disable VLAN 1825927a505aSKowalski, Kamil OnDemandEthernetProvider::disableVlan( 182655c7b7a2SEd Tanous ifaceId, [&](const boost::system::error_code ec) { 1827*1abe55efSEd Tanous if (ec) 1828*1abe55efSEd Tanous { 182955c7b7a2SEd Tanous res.jsonValue = nlohmann::json::object(); 1830*1abe55efSEd Tanous messages::addMessageToErrorJson( 1831*1abe55efSEd Tanous res.jsonValue, messages::internalError()); 1832*1abe55efSEd Tanous res.result(boost::beast::http::status:: 1833*1abe55efSEd Tanous internal_server_error); 1834927a505aSKowalski, Kamil } 1835e439f0f8SKowalski, Kamil res.end(); 1836927a505aSKowalski, Kamil }); 1837*1abe55efSEd Tanous } 1838*1abe55efSEd Tanous else 1839*1abe55efSEd Tanous { 1840927a505aSKowalski, Kamil // ... otherwise return error 1841*1abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 1842*1abe55efSEd Tanous // object, and other errors 1843927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1844*1abe55efSEd Tanous res.jsonValue, messages::resourceNotFound( 1845*1abe55efSEd Tanous "VLAN Network Interface", ifaceId)); 1846927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1847927a505aSKowalski, Kamil res.end(); 1848927a505aSKowalski, Kamil } 1849927a505aSKowalski, Kamil }); 1850e439f0f8SKowalski, Kamil } 1851e439f0f8SKowalski, Kamil 1852e439f0f8SKowalski, Kamil /** 1853e439f0f8SKowalski, Kamil * This allows VlanNetworkInterfaceCollection to reuse this class' doGet 1854e439f0f8SKowalski, Kamil * method, to maintain consistency of returned data, as Collection's doPost 1855e439f0f8SKowalski, Kamil * should return data for created member which should match member's doGet 1856e439f0f8SKowalski, Kamil * result in 100%. 1857e439f0f8SKowalski, Kamil */ 1858e439f0f8SKowalski, Kamil friend VlanNetworkInterfaceCollection; 1859e439f0f8SKowalski, Kamil 1860e439f0f8SKowalski, Kamil // Ethernet Provider object 1861e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 186255c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 1863e439f0f8SKowalski, Kamil }; 1864e439f0f8SKowalski, Kamil 1865e439f0f8SKowalski, Kamil /** 1866e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1867e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1868e439f0f8SKowalski, Kamil */ 1869*1abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 1870*1abe55efSEd Tanous { 1871e439f0f8SKowalski, Kamil public: 1872e439f0f8SKowalski, Kamil template <typename CrowApp> 1873*1abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 1874*1abe55efSEd Tanous // one manager called openbmc This shall be generic, but requires to update 1875e439f0f8SKowalski, Kamil // GetSubroutes method 1876*1abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 1877*1abe55efSEd Tanous Node(app, 1878e439f0f8SKowalski, Kamil "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/", 1879e439f0f8SKowalski, Kamil std::string()), 1880*1abe55efSEd Tanous memberVlan(app) 1881*1abe55efSEd Tanous { 1882e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1883e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1884e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1885e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1886e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1887e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1888e439f0f8SKowalski, Kamil 1889e439f0f8SKowalski, Kamil entityPrivileges = { 1890e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1891e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1892e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1893e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1894e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1895e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1896e439f0f8SKowalski, Kamil } 1897e439f0f8SKowalski, Kamil 1898e439f0f8SKowalski, Kamil private: 1899e439f0f8SKowalski, Kamil /** 1900e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1901e439f0f8SKowalski, Kamil */ 190255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1903*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1904*1abe55efSEd Tanous { 1905*1abe55efSEd Tanous if (params.size() != 1) 1906*1abe55efSEd Tanous { 1907e439f0f8SKowalski, Kamil // This means there is a problem with the router 1908e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1909e439f0f8SKowalski, Kamil res.end(); 1910e439f0f8SKowalski, Kamil 1911e439f0f8SKowalski, Kamil return; 1912e439f0f8SKowalski, Kamil } 1913e439f0f8SKowalski, Kamil 1914*1abe55efSEd Tanous // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces 1915*1abe55efSEd Tanous // for any Manager, not only hardcoded 'openbmc'. 191655c7b7a2SEd Tanous std::string managerId = "openbmc"; 1917e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 1918e439f0f8SKowalski, Kamil 1919*1abe55efSEd Tanous // get eth interface list, and call the below callback for JSON 1920*1abe55efSEd Tanous // preparation 1921*1abe55efSEd Tanous ethernetProvider.getEthernetIfaceList( 1922*1abe55efSEd Tanous [&, managerId{std::move(managerId)}, 1923*1abe55efSEd Tanous rootInterfaceName{std::move(rootInterfaceName)}]( 1924*1abe55efSEd Tanous const bool &success, 1925*1abe55efSEd Tanous const std::vector<std::string> &iface_list) { 1926*1abe55efSEd Tanous if (success) 1927*1abe55efSEd Tanous { 1928e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 192955c7b7a2SEd Tanous nlohmann::json ifaceArray = nlohmann::json::array(); 1930e439f0f8SKowalski, Kamil 1931*1abe55efSEd Tanous for (const std::string &ifaceItem : iface_list) 1932*1abe55efSEd Tanous { 1933*1abe55efSEd Tanous if (ifaceItem == rootInterfaceName) 1934*1abe55efSEd Tanous { 1935e439f0f8SKowalski, Kamil rootInterfaceFound = true; 1936*1abe55efSEd Tanous } 1937*1abe55efSEd Tanous else if (boost::starts_with(ifaceItem, 1938*1abe55efSEd Tanous rootInterfaceName + "_")) 1939*1abe55efSEd Tanous { 194055c7b7a2SEd Tanous ifaceArray.push_back( 1941*1abe55efSEd Tanous {{"@odata.id", "/redfish/v1/Managers/" + 1942*1abe55efSEd Tanous managerId + 1943*1abe55efSEd Tanous "/EthernetInterfaces/" + 1944*1abe55efSEd Tanous rootInterfaceName + 19458ceb2ecaSEd Tanous "/VLANs/" + ifaceItem}}); 1946e439f0f8SKowalski, Kamil } 1947e439f0f8SKowalski, Kamil } 1948e439f0f8SKowalski, Kamil 1949*1abe55efSEd Tanous if (rootInterfaceFound) 1950*1abe55efSEd Tanous { 195155c7b7a2SEd Tanous Node::json["Members"] = ifaceArray; 195255c7b7a2SEd Tanous Node::json["Members@odata.count"] = ifaceArray.size(); 1953*1abe55efSEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/" + 1954*1abe55efSEd Tanous managerId + 1955*1abe55efSEd Tanous "/EthernetInterfaces/" + 1956*1abe55efSEd Tanous rootInterfaceName + "/VLANs"; 195755c7b7a2SEd Tanous res.jsonValue = Node::json; 1958*1abe55efSEd Tanous } 1959*1abe55efSEd Tanous else 1960*1abe55efSEd Tanous { 1961e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1962*1abe55efSEd Tanous res.jsonValue, 1963*1abe55efSEd Tanous messages::resourceNotFound("EthernetInterface", 1964e439f0f8SKowalski, Kamil rootInterfaceName)); 1965e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 1966e439f0f8SKowalski, Kamil res.end(); 1967e439f0f8SKowalski, Kamil } 1968*1abe55efSEd Tanous } 1969*1abe55efSEd Tanous else 1970*1abe55efSEd Tanous { 1971e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 1972*1abe55efSEd Tanous res.result( 1973*1abe55efSEd Tanous boost::beast::http::status::internal_server_error); 1974e439f0f8SKowalski, Kamil } 1975e439f0f8SKowalski, Kamil res.end(); 1976e439f0f8SKowalski, Kamil }); 1977e439f0f8SKowalski, Kamil } 1978e439f0f8SKowalski, Kamil 197955c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 1980*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1981*1abe55efSEd Tanous { 1982*1abe55efSEd Tanous if (params.size() != 1) 1983*1abe55efSEd Tanous { 1984e439f0f8SKowalski, Kamil // This means there is a problem with the router 1985e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1986e439f0f8SKowalski, Kamil res.end(); 1987e439f0f8SKowalski, Kamil return; 1988e439f0f8SKowalski, Kamil } 1989e439f0f8SKowalski, Kamil 1990e439f0f8SKowalski, Kamil nlohmann::json postReq; 1991e439f0f8SKowalski, Kamil 1992*1abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, postReq)) 1993*1abe55efSEd Tanous { 1994e439f0f8SKowalski, Kamil return; 1995e439f0f8SKowalski, Kamil } 1996e439f0f8SKowalski, Kamil 1997*1abe55efSEd Tanous // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces 1998*1abe55efSEd Tanous // for any Manager, not only hardcoded 'openbmc'. 199955c7b7a2SEd Tanous std::string managerId = "openbmc"; 2000e439f0f8SKowalski, Kamil std::string rootInterfaceName = params[0]; 2001e439f0f8SKowalski, Kamil uint64_t vlanId; 2002e439f0f8SKowalski, Kamil bool errorDetected; 2003e439f0f8SKowalski, Kamil 2004e439f0f8SKowalski, Kamil if (json_util::getUnsigned( 2005e439f0f8SKowalski, Kamil "VLANId", postReq, vlanId, 2006e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::MISSING) | 2007e439f0f8SKowalski, Kamil static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR), 2008*1abe55efSEd Tanous res.jsonValue, "/VLANId") != json_util::Result::SUCCESS) 2009*1abe55efSEd Tanous { 2010e439f0f8SKowalski, Kamil res.end(); 2011e439f0f8SKowalski, Kamil return; 2012e439f0f8SKowalski, Kamil } 2013e439f0f8SKowalski, Kamil 2014*1abe55efSEd Tanous // get eth interface list, and call the below callback for JSON 2015*1abe55efSEd Tanous // preparation 2016*1abe55efSEd Tanous ethernetProvider.getEthernetIfaceList( 2017*1abe55efSEd Tanous [&, managerId{std::move(managerId)}, 2018*1abe55efSEd Tanous rootInterfaceName{std::move(rootInterfaceName)}]( 2019*1abe55efSEd Tanous const bool &success, 2020*1abe55efSEd Tanous const std::vector<std::string> &iface_list) { 2021*1abe55efSEd Tanous if (success) 2022*1abe55efSEd Tanous { 2023e439f0f8SKowalski, Kamil bool rootInterfaceFound = false; 2024e439f0f8SKowalski, Kamil 2025*1abe55efSEd Tanous for (const std::string &ifaceItem : iface_list) 2026*1abe55efSEd Tanous { 2027*1abe55efSEd Tanous if (ifaceItem == rootInterfaceName) 2028*1abe55efSEd Tanous { 2029e439f0f8SKowalski, Kamil rootInterfaceFound = true; 2030e439f0f8SKowalski, Kamil break; 2031e439f0f8SKowalski, Kamil } 2032e439f0f8SKowalski, Kamil } 2033e439f0f8SKowalski, Kamil 2034*1abe55efSEd Tanous if (rootInterfaceFound) 2035*1abe55efSEd Tanous { 203655c7b7a2SEd Tanous ethernetProvider.createVlan( 2037e439f0f8SKowalski, Kamil rootInterfaceName, vlanId, 2038*1abe55efSEd Tanous [&, vlanId, rootInterfaceName, req{std::move(req)}]( 2039*1abe55efSEd Tanous const boost::system::error_code ec) { 2040*1abe55efSEd Tanous if (ec) 2041*1abe55efSEd Tanous { 2042*1abe55efSEd Tanous messages::addMessageToErrorJson( 2043*1abe55efSEd Tanous res.jsonValue, 20448ceb2ecaSEd Tanous messages::internalError()); 2045e439f0f8SKowalski, Kamil res.end(); 2046*1abe55efSEd Tanous } 2047*1abe55efSEd Tanous else 2048*1abe55efSEd Tanous { 2049e439f0f8SKowalski, Kamil memberVlan.doGet( 2050e439f0f8SKowalski, Kamil res, req, 2051e439f0f8SKowalski, Kamil {rootInterfaceName, 2052*1abe55efSEd Tanous rootInterfaceName + "_" + 2053*1abe55efSEd Tanous std::to_string(vlanId)}); 2054e439f0f8SKowalski, Kamil } 2055e439f0f8SKowalski, Kamil }); 2056*1abe55efSEd Tanous } 2057*1abe55efSEd Tanous else 2058*1abe55efSEd Tanous { 2059e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 2060*1abe55efSEd Tanous res.jsonValue, 2061*1abe55efSEd Tanous messages::resourceNotFound("EthernetInterface", 2062e439f0f8SKowalski, Kamil rootInterfaceName)); 2063e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::not_found); 2064e439f0f8SKowalski, Kamil res.end(); 2065e439f0f8SKowalski, Kamil } 2066*1abe55efSEd Tanous } 2067*1abe55efSEd Tanous else 2068*1abe55efSEd Tanous { 2069e439f0f8SKowalski, Kamil // No success, best what we can do is return INTERNALL ERROR 2070*1abe55efSEd Tanous res.result( 2071*1abe55efSEd Tanous boost::beast::http::status::internal_server_error); 2072e439f0f8SKowalski, Kamil res.end(); 2073e439f0f8SKowalski, Kamil } 2074e439f0f8SKowalski, Kamil }); 2075e439f0f8SKowalski, Kamil } 2076e439f0f8SKowalski, Kamil 2077e439f0f8SKowalski, Kamil // Ethernet Provider object 2078e439f0f8SKowalski, Kamil // TODO(Pawel) consider move it to singleton 207955c7b7a2SEd Tanous OnDemandEthernetProvider ethernetProvider; 2080e439f0f8SKowalski, Kamil VlanNetworkInterface memberVlan; 2081e439f0f8SKowalski, Kamil }; 2082e439f0f8SKowalski, Kamil 20839391bb9cSRapkiewicz, Pawel } // namespace redfish 2084