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 181abe55efSEd Tanous #include <boost/container/flat_map.hpp> 194a0cb85cSEd Tanous #include <boost/container/flat_set.hpp> 20179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 21588c3f0dSKowalski, Kamil #include <error_messages.hpp> 22179db1d7SKowalski, Kamil #include <node.hpp> 23*a24526dcSEd Tanous #include <optional> 24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 259391bb9cSRapkiewicz, Pawel 261abe55efSEd Tanous namespace redfish 271abe55efSEd Tanous { 289391bb9cSRapkiewicz, Pawel 299391bb9cSRapkiewicz, Pawel /** 309391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 319391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 329391bb9cSRapkiewicz, Pawel */ 33aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 34aa2e59c1SEd Tanous std::string, 35aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 36aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 379391bb9cSRapkiewicz, Pawel 384a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair< 39aa2e59c1SEd Tanous sdbusplus::message::object_path, 404a0cb85cSEd Tanous std::vector<std::pair< 41aa2e59c1SEd Tanous std::string, 42aa2e59c1SEd Tanous boost::container::flat_map< 43aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 44aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 454a0cb85cSEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>>>>>; 464a0cb85cSEd Tanous 474a0cb85cSEd Tanous enum class LinkType 484a0cb85cSEd Tanous { 494a0cb85cSEd Tanous Local, 504a0cb85cSEd Tanous Global 514a0cb85cSEd Tanous }; 529391bb9cSRapkiewicz, Pawel 539391bb9cSRapkiewicz, Pawel /** 549391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 559391bb9cSRapkiewicz, Pawel */ 561abe55efSEd Tanous struct IPv4AddressData 571abe55efSEd Tanous { 58179db1d7SKowalski, Kamil std::string id; 594a0cb85cSEd Tanous std::string address; 604a0cb85cSEd Tanous std::string domain; 614a0cb85cSEd Tanous std::string gateway; 629391bb9cSRapkiewicz, Pawel std::string netmask; 639391bb9cSRapkiewicz, Pawel std::string origin; 644a0cb85cSEd Tanous LinkType linktype; 654a0cb85cSEd Tanous 661abe55efSEd Tanous bool operator<(const IPv4AddressData &obj) const 671abe55efSEd Tanous { 684a0cb85cSEd Tanous return id < obj.id; 691abe55efSEd Tanous } 709391bb9cSRapkiewicz, Pawel }; 719391bb9cSRapkiewicz, Pawel 729391bb9cSRapkiewicz, Pawel /** 739391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 749391bb9cSRapkiewicz, Pawel * available from DBus 759391bb9cSRapkiewicz, Pawel */ 761abe55efSEd Tanous struct EthernetInterfaceData 771abe55efSEd Tanous { 784a0cb85cSEd Tanous uint32_t speed; 794a0cb85cSEd Tanous bool auto_neg; 804a0cb85cSEd Tanous std::string hostname; 814a0cb85cSEd Tanous std::string default_gateway; 824a0cb85cSEd Tanous std::string mac_address; 83*a24526dcSEd Tanous std::optional<uint32_t> vlan_id; 849391bb9cSRapkiewicz, Pawel }; 859391bb9cSRapkiewicz, Pawel 869391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 879391bb9cSRapkiewicz, Pawel // into full dot notation 881abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 891abe55efSEd Tanous { 909391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 919391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 929391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 939391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 949391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 959391bb9cSRapkiewicz, Pawel return netmask; 969391bb9cSRapkiewicz, Pawel } 979391bb9cSRapkiewicz, Pawel 984a0cb85cSEd Tanous inline std::string 994a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(const std::string &inputOrigin, 1004a0cb85cSEd Tanous bool isIPv4) 1011abe55efSEd Tanous { 1024a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 1031abe55efSEd Tanous { 1044a0cb85cSEd Tanous return "Static"; 1059391bb9cSRapkiewicz, Pawel } 1064a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal") 1071abe55efSEd Tanous { 1084a0cb85cSEd Tanous if (isIPv4) 1091abe55efSEd Tanous { 1104a0cb85cSEd Tanous return "IPv4LinkLocal"; 1111abe55efSEd Tanous } 1121abe55efSEd Tanous else 1131abe55efSEd Tanous { 1144a0cb85cSEd Tanous return "LinkLocal"; 1159391bb9cSRapkiewicz, Pawel } 1169391bb9cSRapkiewicz, Pawel } 1174a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1181abe55efSEd Tanous { 1194a0cb85cSEd Tanous if (isIPv4) 1204a0cb85cSEd Tanous { 1214a0cb85cSEd Tanous return "DHCP"; 1224a0cb85cSEd Tanous } 1234a0cb85cSEd Tanous else 1244a0cb85cSEd Tanous { 1254a0cb85cSEd Tanous return "DHCPv6"; 1264a0cb85cSEd Tanous } 1274a0cb85cSEd Tanous } 1284a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC") 1294a0cb85cSEd Tanous { 1304a0cb85cSEd Tanous return "SLAAC"; 1314a0cb85cSEd Tanous } 1324a0cb85cSEd Tanous return ""; 1334a0cb85cSEd Tanous } 1344a0cb85cSEd Tanous 1354a0cb85cSEd Tanous inline std::string 1364a0cb85cSEd Tanous translateAddressOriginRedfishToDbus(const std::string &inputOrigin) 1374a0cb85cSEd Tanous { 1384a0cb85cSEd Tanous if (inputOrigin == "Static") 1394a0cb85cSEd Tanous { 1404a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 1414a0cb85cSEd Tanous } 1424a0cb85cSEd Tanous if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6") 1434a0cb85cSEd Tanous { 1444a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 1454a0cb85cSEd Tanous } 1464a0cb85cSEd Tanous if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal") 1474a0cb85cSEd Tanous { 1484a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal"; 1494a0cb85cSEd Tanous } 1504a0cb85cSEd Tanous if (inputOrigin == "SLAAC") 1514a0cb85cSEd Tanous { 1524a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC"; 1534a0cb85cSEd Tanous } 1544a0cb85cSEd Tanous return ""; 1554a0cb85cSEd Tanous } 1564a0cb85cSEd Tanous 1574a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string ðiface_id, 1584a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 1594a0cb85cSEd Tanous EthernetInterfaceData ðData) 1604a0cb85cSEd Tanous { 1614a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 1624a0cb85cSEd Tanous { 1634a0cb85cSEd Tanous if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id) 1644a0cb85cSEd Tanous { 1654a0cb85cSEd Tanous for (const auto &ifacePair : objpath.second) 1664a0cb85cSEd Tanous { 1674a0cb85cSEd Tanous if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 1684a0cb85cSEd Tanous { 1694a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1704a0cb85cSEd Tanous { 1714a0cb85cSEd Tanous if (propertyPair.first == "MACAddress") 1724a0cb85cSEd Tanous { 1734a0cb85cSEd Tanous const std::string *mac = 1741b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 1751b6b96c5SEd Tanous std::string>(&propertyPair.second); 1764a0cb85cSEd Tanous if (mac != nullptr) 1774a0cb85cSEd Tanous { 1784a0cb85cSEd Tanous ethData.mac_address = *mac; 1794a0cb85cSEd Tanous } 1804a0cb85cSEd Tanous } 1814a0cb85cSEd Tanous } 1824a0cb85cSEd Tanous } 1834a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1844a0cb85cSEd Tanous { 1854a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1864a0cb85cSEd Tanous { 1874a0cb85cSEd Tanous if (propertyPair.first == "Id") 1884a0cb85cSEd Tanous { 1891b6b96c5SEd Tanous const uint32_t *id = 1901b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 1911b6b96c5SEd Tanous uint32_t>(&propertyPair.second); 1924a0cb85cSEd Tanous if (id != nullptr) 1934a0cb85cSEd Tanous { 1944a0cb85cSEd Tanous ethData.vlan_id = *id; 1954a0cb85cSEd Tanous } 1964a0cb85cSEd Tanous } 1974a0cb85cSEd Tanous } 1984a0cb85cSEd Tanous } 1994a0cb85cSEd Tanous else if (ifacePair.first == 2004a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 2014a0cb85cSEd Tanous { 2024a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2034a0cb85cSEd Tanous { 2044a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 2054a0cb85cSEd Tanous { 2064a0cb85cSEd Tanous const bool *auto_neg = 2071b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if<bool>( 2081b6b96c5SEd Tanous &propertyPair.second); 2094a0cb85cSEd Tanous if (auto_neg != nullptr) 2104a0cb85cSEd Tanous { 2114a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2124a0cb85cSEd Tanous } 2134a0cb85cSEd Tanous } 2144a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2154a0cb85cSEd Tanous { 2164a0cb85cSEd Tanous const uint32_t *speed = 2171b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 2181b6b96c5SEd Tanous uint32_t>(&propertyPair.second); 2194a0cb85cSEd Tanous if (speed != nullptr) 2204a0cb85cSEd Tanous { 2214a0cb85cSEd Tanous ethData.speed = *speed; 2224a0cb85cSEd Tanous } 2234a0cb85cSEd Tanous } 2244a0cb85cSEd Tanous } 2254a0cb85cSEd Tanous } 2264a0cb85cSEd Tanous else if (ifacePair.first == 2274a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2284a0cb85cSEd Tanous { 2294a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2304a0cb85cSEd Tanous { 2314a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2324a0cb85cSEd Tanous { 2334a0cb85cSEd Tanous const std::string *hostname = 2341b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 2351b6b96c5SEd Tanous std::string>(&propertyPair.second); 2364a0cb85cSEd Tanous if (hostname != nullptr) 2374a0cb85cSEd Tanous { 2384a0cb85cSEd Tanous ethData.hostname = *hostname; 2394a0cb85cSEd Tanous } 2404a0cb85cSEd Tanous } 2414a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2424a0cb85cSEd Tanous { 2434a0cb85cSEd Tanous const std::string *defaultGateway = 2441b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 2451b6b96c5SEd Tanous std::string>(&propertyPair.second); 2464a0cb85cSEd Tanous if (defaultGateway != nullptr) 2474a0cb85cSEd Tanous { 2484a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2494a0cb85cSEd Tanous } 2504a0cb85cSEd Tanous } 2514a0cb85cSEd Tanous } 2524a0cb85cSEd Tanous } 2534a0cb85cSEd Tanous } 2544a0cb85cSEd Tanous } 2554a0cb85cSEd Tanous } 2564a0cb85cSEd Tanous } 2574a0cb85cSEd Tanous 2584a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2594a0cb85cSEd Tanous inline void 2604a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2614a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2624a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2634a0cb85cSEd Tanous { 2644a0cb85cSEd Tanous const std::string ipv4PathStart = 2654a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 2664a0cb85cSEd Tanous 2674a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 2684a0cb85cSEd Tanous // single ethernet interface, loop over all of them 2694a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 2704a0cb85cSEd Tanous { 2714a0cb85cSEd Tanous // Check if proper pattern for object path appears 2724a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 2734a0cb85cSEd Tanous { 2744a0cb85cSEd Tanous for (auto &interface : objpath.second) 2754a0cb85cSEd Tanous { 2764a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 2774a0cb85cSEd Tanous { 2784a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 2794a0cb85cSEd Tanous // appropriate 2804a0cb85cSEd Tanous std::pair< 2814a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 2824a0cb85cSEd Tanous bool> 2834a0cb85cSEd Tanous it = ipv4_config.insert( 2844a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 2854a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 2864a0cb85cSEd Tanous for (auto &property : interface.second) 2874a0cb85cSEd Tanous { 2884a0cb85cSEd Tanous if (property.first == "Address") 2894a0cb85cSEd Tanous { 2904a0cb85cSEd Tanous const std::string *address = 2911b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 2921b6b96c5SEd Tanous std::string>(&property.second); 2934a0cb85cSEd Tanous if (address != nullptr) 2944a0cb85cSEd Tanous { 2954a0cb85cSEd Tanous ipv4_address.address = *address; 2964a0cb85cSEd Tanous } 2974a0cb85cSEd Tanous } 2984a0cb85cSEd Tanous else if (property.first == "Gateway") 2994a0cb85cSEd Tanous { 3004a0cb85cSEd Tanous const std::string *gateway = 3011b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 3021b6b96c5SEd Tanous std::string>(&property.second); 3034a0cb85cSEd Tanous if (gateway != nullptr) 3044a0cb85cSEd Tanous { 3054a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 3064a0cb85cSEd Tanous } 3074a0cb85cSEd Tanous } 3084a0cb85cSEd Tanous else if (property.first == "Origin") 3094a0cb85cSEd Tanous { 3104a0cb85cSEd Tanous const std::string *origin = 3111b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if< 3121b6b96c5SEd Tanous std::string>(&property.second); 3134a0cb85cSEd Tanous if (origin != nullptr) 3144a0cb85cSEd Tanous { 3154a0cb85cSEd Tanous ipv4_address.origin = 3164a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3174a0cb85cSEd Tanous true); 3184a0cb85cSEd Tanous } 3194a0cb85cSEd Tanous } 3204a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3214a0cb85cSEd Tanous { 3224a0cb85cSEd Tanous const uint8_t *mask = 3231b6b96c5SEd Tanous sdbusplus::message::variant_ns::get_if<uint8_t>( 3241b6b96c5SEd Tanous &property.second); 3254a0cb85cSEd Tanous if (mask != nullptr) 3264a0cb85cSEd Tanous { 3274a0cb85cSEd Tanous // convert it to the string 3284a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3294a0cb85cSEd Tanous } 3304a0cb85cSEd Tanous } 3314a0cb85cSEd Tanous else 3324a0cb85cSEd Tanous { 3334a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3344a0cb85cSEd Tanous << "Got extra property: " << property.first 3354a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3364a0cb85cSEd Tanous } 3374a0cb85cSEd Tanous } 3384a0cb85cSEd Tanous // Check if given address is local, or global 3394a0cb85cSEd Tanous ipv4_address.linktype = 3404a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3414a0cb85cSEd Tanous ? LinkType::Global 3424a0cb85cSEd Tanous : LinkType::Local; 3434a0cb85cSEd Tanous } 3444a0cb85cSEd Tanous } 3454a0cb85cSEd Tanous } 3464a0cb85cSEd Tanous } 3474a0cb85cSEd Tanous } 348588c3f0dSKowalski, Kamil 349588c3f0dSKowalski, Kamil /** 350588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 351588c3f0dSKowalski, Kamil * 352588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 353588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 354588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 355588c3f0dSKowalski, Kamil * 356588c3f0dSKowalski, Kamil * @return None. 357588c3f0dSKowalski, Kamil */ 358588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3594a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3601abe55efSEd Tanous CallbackFunc &&callback) 3611abe55efSEd Tanous { 36255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 363588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 364588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 365588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 366588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 367588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 3684a0cb85cSEd Tanous } 369588c3f0dSKowalski, Kamil 370588c3f0dSKowalski, Kamil /** 371179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 372179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 373179db1d7SKowalski, Kamil * bit count for Subnet Mask. 374179db1d7SKowalski, Kamil * 375179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 376179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 377179db1d7SKowalski, Kamil * 378179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 379179db1d7SKowalski, Kamil */ 3804a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3811abe55efSEd Tanous uint8_t *bits = nullptr) 3821abe55efSEd Tanous { 383179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 384179db1d7SKowalski, Kamil 385179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 386179db1d7SKowalski, Kamil 3874a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 3881abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 3891abe55efSEd Tanous { 390179db1d7SKowalski, Kamil return false; 391179db1d7SKowalski, Kamil } 392179db1d7SKowalski, Kamil 3931abe55efSEd Tanous if (bits != nullptr) 3941abe55efSEd Tanous { 395179db1d7SKowalski, Kamil *bits = 0; 396179db1d7SKowalski, Kamil } 397179db1d7SKowalski, Kamil 398179db1d7SKowalski, Kamil char *endPtr; 399179db1d7SKowalski, Kamil long previousValue = 255; 400179db1d7SKowalski, Kamil bool firstZeroInByteHit; 4011abe55efSEd Tanous for (const std::string &byte : bytesInMask) 4021abe55efSEd Tanous { 4031abe55efSEd Tanous if (byte.empty()) 4041abe55efSEd Tanous { 4051db9ca37SKowalski, Kamil return false; 4061db9ca37SKowalski, Kamil } 4071db9ca37SKowalski, Kamil 408179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4091db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 410179db1d7SKowalski, Kamil 4114a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4124a0cb85cSEd Tanous // is not 100% number 4131abe55efSEd Tanous if (*endPtr != '\0') 4141abe55efSEd Tanous { 415179db1d7SKowalski, Kamil return false; 416179db1d7SKowalski, Kamil } 417179db1d7SKowalski, Kamil 418179db1d7SKowalski, Kamil // Value should be contained in byte 4191abe55efSEd Tanous if (value < 0 || value > 255) 4201abe55efSEd Tanous { 421179db1d7SKowalski, Kamil return false; 422179db1d7SKowalski, Kamil } 423179db1d7SKowalski, Kamil 4241abe55efSEd Tanous if (bits != nullptr) 4251abe55efSEd Tanous { 426179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4271abe55efSEd Tanous if (previousValue != 255 && value != 0) 4281abe55efSEd Tanous { 429179db1d7SKowalski, Kamil return false; 430179db1d7SKowalski, Kamil } 431179db1d7SKowalski, Kamil 432179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 433179db1d7SKowalski, Kamil firstZeroInByteHit = false; 434179db1d7SKowalski, Kamil 435179db1d7SKowalski, Kamil // Count bits 4361abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4371abe55efSEd Tanous { 4381abe55efSEd Tanous if (value & (1 << bitIdx)) 4391abe55efSEd Tanous { 4401abe55efSEd Tanous if (firstZeroInByteHit) 4411abe55efSEd Tanous { 442179db1d7SKowalski, Kamil // Continuity not preserved 443179db1d7SKowalski, Kamil return false; 4441abe55efSEd Tanous } 4451abe55efSEd Tanous else 4461abe55efSEd Tanous { 447179db1d7SKowalski, Kamil (*bits)++; 448179db1d7SKowalski, Kamil } 4491abe55efSEd Tanous } 4501abe55efSEd Tanous else 4511abe55efSEd Tanous { 452179db1d7SKowalski, Kamil firstZeroInByteHit = true; 453179db1d7SKowalski, Kamil } 454179db1d7SKowalski, Kamil } 455179db1d7SKowalski, Kamil } 456179db1d7SKowalski, Kamil 457179db1d7SKowalski, Kamil previousValue = value; 458179db1d7SKowalski, Kamil } 459179db1d7SKowalski, Kamil 460179db1d7SKowalski, Kamil return true; 461179db1d7SKowalski, Kamil } 462179db1d7SKowalski, Kamil 463179db1d7SKowalski, Kamil /** 464179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 465179db1d7SKowalski, Kamil * 466179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4674a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 468179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 469179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 470179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 471179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 472179db1d7SKowalski, Kamil * 473179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 474179db1d7SKowalski, Kamil * otherwise 475179db1d7SKowalski, Kamil */ 4764a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 4774a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 4784a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 4794a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4801abe55efSEd Tanous { 4814a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 4824a0cb85cSEd Tanous newValue{std::move(newValue)}]( 4831abe55efSEd Tanous const boost::system::error_code ec) { 4841abe55efSEd Tanous if (ec) 4851abe55efSEd Tanous { 486a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 4871abe55efSEd Tanous } 4881abe55efSEd Tanous else 4891abe55efSEd Tanous { 4904a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 491179db1d7SKowalski, Kamil } 492179db1d7SKowalski, Kamil }; 493179db1d7SKowalski, Kamil 49455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 495179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 496179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 497179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 498179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 499179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 5004a0cb85cSEd Tanous } 501179db1d7SKowalski, Kamil 502179db1d7SKowalski, Kamil /** 503179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 504179db1d7SKowalski, Kamil * 505179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5064a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5071abe55efSEd Tanous * modified 508179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 509179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 510179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 511179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 512179db1d7SKowalski, Kamil * 513179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 514179db1d7SKowalski, Kamil * otherwise 515179db1d7SKowalski, Kamil */ 5164a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5171abe55efSEd Tanous const std::string &ipHash, 5181abe55efSEd Tanous const std::string &newValue, 519179db1d7SKowalski, Kamil const std::string &newValueDbus, 5204a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5211abe55efSEd Tanous { 5224a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5231abe55efSEd Tanous const boost::system::error_code ec) { 5241abe55efSEd Tanous if (ec) 5251abe55efSEd Tanous { 526a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5271abe55efSEd Tanous } 5281abe55efSEd Tanous else 5291abe55efSEd Tanous { 5304a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 531179db1d7SKowalski, Kamil newValue; 532179db1d7SKowalski, Kamil } 533179db1d7SKowalski, Kamil }; 534179db1d7SKowalski, Kamil 53555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 536179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 537179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 538179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 539179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 540179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 5414a0cb85cSEd Tanous } 542179db1d7SKowalski, Kamil 543179db1d7SKowalski, Kamil /** 544179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 545179db1d7SKowalski, Kamil * 546179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5474a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5481abe55efSEd Tanous * modified 549179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 550179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 551179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 552179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 553179db1d7SKowalski, Kamil * 554179db1d7SKowalski, Kamil * @return None 555179db1d7SKowalski, Kamil */ 5564a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5574a0cb85cSEd Tanous const std::string &ipHash, 5584a0cb85cSEd Tanous const std::string &newValueStr, 5594a0cb85cSEd Tanous uint8_t &newValue, 5604a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5611abe55efSEd Tanous { 5624a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5631abe55efSEd Tanous const boost::system::error_code ec) { 5641abe55efSEd Tanous if (ec) 5651abe55efSEd Tanous { 566a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5671abe55efSEd Tanous } 5681abe55efSEd Tanous else 5691abe55efSEd Tanous { 57055c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 571179db1d7SKowalski, Kamil newValueStr; 572179db1d7SKowalski, Kamil } 573179db1d7SKowalski, Kamil }; 574179db1d7SKowalski, Kamil 57555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 576179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 577179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 578179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 579179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 580179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 5814a0cb85cSEd Tanous } 582588c3f0dSKowalski, Kamil 583588c3f0dSKowalski, Kamil /** 584588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 585588c3f0dSKowalski, Kamil * 586588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 587588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 588588c3f0dSKowalski, Kamil * 589588c3f0dSKowalski, Kamil * @return None. 590588c3f0dSKowalski, Kamil */ 591588c3f0dSKowalski, Kamil template <typename CallbackFunc> 5921abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback) 5931abe55efSEd Tanous { 59455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 595588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 596588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 597588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 598588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 599588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 6004a0cb85cSEd Tanous } 601588c3f0dSKowalski, Kamil 602588c3f0dSKowalski, Kamil /** 603179db1d7SKowalski, Kamil * @brief Deletes given IPv4 604179db1d7SKowalski, Kamil * 605179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6064a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 607179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 608179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 609179db1d7SKowalski, Kamil * 610179db1d7SKowalski, Kamil * @return None 611179db1d7SKowalski, Kamil */ 6124a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 613179db1d7SKowalski, Kamil unsigned int ipIdx, 6144a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6151abe55efSEd Tanous { 61655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6174a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6181abe55efSEd Tanous if (ec) 6191abe55efSEd Tanous { 620a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 6211abe55efSEd Tanous } 6221abe55efSEd Tanous else 6231abe55efSEd Tanous { 62455c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 625179db1d7SKowalski, Kamil } 626179db1d7SKowalski, Kamil }, 627179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 628179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 629179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 630179db1d7SKowalski, Kamil } 631179db1d7SKowalski, Kamil 632179db1d7SKowalski, Kamil /** 633179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 634179db1d7SKowalski, Kamil * 635179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6364a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 637179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 638179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 639179db1d7SKowalski, Kamil * 640179db1d7SKowalski, Kamil * @return None 641179db1d7SKowalski, Kamil */ 6424a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 643179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 644179db1d7SKowalski, Kamil const std::string &address, 6454a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6461abe55efSEd Tanous { 6474a0cb85cSEd Tanous auto createIpHandler = [ipIdx, 6484a0cb85cSEd Tanous asyncResp](const boost::system::error_code ec) { 6491abe55efSEd Tanous if (ec) 6501abe55efSEd Tanous { 651a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 652179db1d7SKowalski, Kamil } 653179db1d7SKowalski, Kamil }; 654179db1d7SKowalski, Kamil 65555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 656179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 657179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 658179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 659179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 660179db1d7SKowalski, Kamil gateway); 661179db1d7SKowalski, Kamil } 662179db1d7SKowalski, Kamil 663179db1d7SKowalski, Kamil /** 664179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 665179db1d7SKowalski, Kamil * Object 666179db1d7SKowalski, Kamil * from EntityManager Network Manager 6674a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 668179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 669179db1d7SKowalski, Kamil * into JSON 670179db1d7SKowalski, Kamil */ 671179db1d7SKowalski, Kamil template <typename CallbackFunc> 6724a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 6731abe55efSEd Tanous CallbackFunc &&callback) 6741abe55efSEd Tanous { 67555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6764a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 6771abe55efSEd Tanous const boost::system::error_code error_code, 6784a0cb85cSEd Tanous const GetManagedObjects &resp) { 67955c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 6804a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 681179db1d7SKowalski, Kamil 6821abe55efSEd Tanous if (error_code) 6831abe55efSEd Tanous { 68455c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 685179db1d7SKowalski, Kamil return; 686179db1d7SKowalski, Kamil } 687179db1d7SKowalski, Kamil 6884a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 6894a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 690179db1d7SKowalski, Kamil 691179db1d7SKowalski, Kamil // Fix global GW 6921abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 6931abe55efSEd Tanous { 6944a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 6954a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 6961abe55efSEd Tanous { 6974a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 698179db1d7SKowalski, Kamil } 699179db1d7SKowalski, Kamil } 700179db1d7SKowalski, Kamil 7014a0cb85cSEd Tanous // Finally make a callback with usefull data 70255c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 703179db1d7SKowalski, Kamil }, 704179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 705179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 706179db1d7SKowalski, Kamil }; 707179db1d7SKowalski, Kamil 708179db1d7SKowalski, Kamil /** 7099391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7109391bb9cSRapkiewicz, Pawel * Manager 7111abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7121abe55efSEd Tanous * into JSON. 7139391bb9cSRapkiewicz, Pawel */ 7149391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7151abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7161abe55efSEd Tanous { 71755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7184a0cb85cSEd Tanous [callback{std::move(callback)}]( 7199391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 7204a0cb85cSEd Tanous GetManagedObjects &resp) { 7211abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7221abe55efSEd Tanous // ethernet interfaces 7234a0cb85cSEd Tanous std::vector<std::string> iface_list; 7244a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7251abe55efSEd Tanous if (error_code) 7261abe55efSEd Tanous { 7274a0cb85cSEd Tanous callback(false, iface_list); 7289391bb9cSRapkiewicz, Pawel return; 7299391bb9cSRapkiewicz, Pawel } 7309391bb9cSRapkiewicz, Pawel 7319391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7324a0cb85cSEd Tanous for (const auto &objpath : resp) 7331abe55efSEd Tanous { 7349391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7354a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7361abe55efSEd Tanous { 7371abe55efSEd Tanous // If interface is 7384a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 7394a0cb85cSEd Tanous // what we're looking for. 7409391bb9cSRapkiewicz, Pawel if (interface.first == 7411abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7421abe55efSEd Tanous { 7434a0cb85cSEd Tanous // Cut out everyting until last "/", ... 7444a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 7454a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 7464a0cb85cSEd Tanous if (last_pos != std::string::npos) 7471abe55efSEd Tanous { 7489391bb9cSRapkiewicz, Pawel // and put it into output vector. 7494a0cb85cSEd Tanous iface_list.emplace_back( 7504a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7519391bb9cSRapkiewicz, Pawel } 7529391bb9cSRapkiewicz, Pawel } 7539391bb9cSRapkiewicz, Pawel } 7549391bb9cSRapkiewicz, Pawel } 755a434f2bdSEd Tanous // Finally make a callback with useful data 7564a0cb85cSEd Tanous callback(true, iface_list); 7579391bb9cSRapkiewicz, Pawel }, 758aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 759aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7609391bb9cSRapkiewicz, Pawel }; 7619391bb9cSRapkiewicz, Pawel 7629391bb9cSRapkiewicz, Pawel /** 7639391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7649391bb9cSRapkiewicz, Pawel */ 7651abe55efSEd Tanous class EthernetCollection : public Node 7661abe55efSEd Tanous { 7679391bb9cSRapkiewicz, Pawel public: 7684a0cb85cSEd Tanous template <typename CrowApp> 7691abe55efSEd Tanous EthernetCollection(CrowApp &app) : 7704a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 7711abe55efSEd Tanous { 772588c3f0dSKowalski, Kamil entityPrivileges = { 773588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 774e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 775e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 776e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 777e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 778e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7799391bb9cSRapkiewicz, Pawel } 7809391bb9cSRapkiewicz, Pawel 7819391bb9cSRapkiewicz, Pawel private: 7829391bb9cSRapkiewicz, Pawel /** 7839391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7849391bb9cSRapkiewicz, Pawel */ 78555c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7861abe55efSEd Tanous const std::vector<std::string> ¶ms) override 7871abe55efSEd Tanous { 7880f74e643SEd Tanous res.jsonValue["@odata.type"] = 7890f74e643SEd Tanous "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7900f74e643SEd Tanous res.jsonValue["@odata.context"] = 7910f74e643SEd Tanous "/redfish/v1/" 7920f74e643SEd Tanous "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7930f74e643SEd Tanous res.jsonValue["@odata.id"] = 7940f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7950f74e643SEd Tanous res.jsonValue["Name"] = "Ethernet Network Interface Collection"; 7960f74e643SEd Tanous res.jsonValue["Description"] = 7970f74e643SEd Tanous "Collection of EthernetInterfaces for this Manager"; 7980f74e643SEd Tanous 7994a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 8001abe55efSEd Tanous // preparation 801f12894f8SJason M. Bills getEthernetIfaceList( 802f12894f8SJason M. Bills [&res](const bool &success, 8031abe55efSEd Tanous const std::vector<std::string> &iface_list) { 8044a0cb85cSEd Tanous if (!success) 8051abe55efSEd Tanous { 806f12894f8SJason M. Bills messages::internalError(res); 8074a0cb85cSEd Tanous res.end(); 8084a0cb85cSEd Tanous return; 8094a0cb85cSEd Tanous } 8104a0cb85cSEd Tanous 8114a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 8124a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 8134a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8141abe55efSEd Tanous { 8154a0cb85cSEd Tanous iface_array.push_back( 8164a0cb85cSEd Tanous {{"@odata.id", 8174a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 8184a0cb85cSEd Tanous iface_item}}); 8199391bb9cSRapkiewicz, Pawel } 8204a0cb85cSEd Tanous 8214a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 8224a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 8234a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8249391bb9cSRapkiewicz, Pawel res.end(); 8259391bb9cSRapkiewicz, Pawel }); 8269391bb9cSRapkiewicz, Pawel } 8279391bb9cSRapkiewicz, Pawel }; 8289391bb9cSRapkiewicz, Pawel 8299391bb9cSRapkiewicz, Pawel /** 8309391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8319391bb9cSRapkiewicz, Pawel */ 8321abe55efSEd Tanous class EthernetInterface : public Node 8331abe55efSEd Tanous { 8349391bb9cSRapkiewicz, Pawel public: 8359391bb9cSRapkiewicz, Pawel /* 8369391bb9cSRapkiewicz, Pawel * Default Constructor 8379391bb9cSRapkiewicz, Pawel */ 8384a0cb85cSEd Tanous template <typename CrowApp> 8391abe55efSEd Tanous EthernetInterface(CrowApp &app) : 8404a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8411abe55efSEd Tanous std::string()) 8421abe55efSEd Tanous { 843588c3f0dSKowalski, Kamil entityPrivileges = { 844588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 845e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 846e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 847e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 848e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 849e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8509391bb9cSRapkiewicz, Pawel } 8519391bb9cSRapkiewicz, Pawel 852e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 853e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 854e439f0f8SKowalski, Kamil const nlohmann::json &input, 8554a0cb85cSEd Tanous const EthernetInterfaceData ðData, 8564a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8571abe55efSEd Tanous { 8581abe55efSEd Tanous if (!input.is_object()) 8591abe55efSEd Tanous { 860f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 861a08b46ccSJason M. Bills "VLAN"); 862588c3f0dSKowalski, Kamil return; 863588c3f0dSKowalski, Kamil } 864588c3f0dSKowalski, Kamil 8654a0cb85cSEd Tanous nlohmann::json::const_iterator vlanEnable = input.find("VLANEnable"); 8664a0cb85cSEd Tanous if (vlanEnable == input.end()) 8671abe55efSEd Tanous { 868a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, "VLANEnable"); 8694a0cb85cSEd Tanous return; 8704a0cb85cSEd Tanous } 8714a0cb85cSEd Tanous const bool *vlanEnableBool = vlanEnable->get_ptr<const bool *>(); 8724a0cb85cSEd Tanous if (vlanEnableBool == nullptr) 8734a0cb85cSEd Tanous { 874f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanEnable->dump(), 875a08b46ccSJason M. Bills "VLANEnable"); 876588c3f0dSKowalski, Kamil return; 877588c3f0dSKowalski, Kamil } 878588c3f0dSKowalski, Kamil 8794a0cb85cSEd Tanous nlohmann::json::const_iterator vlanId = input.find("VLANId"); 8804a0cb85cSEd Tanous if (vlanId == input.end()) 8814a0cb85cSEd Tanous { 882a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, "VLANId"); 8834a0cb85cSEd Tanous return; 8844a0cb85cSEd Tanous } 8854a0cb85cSEd Tanous const uint64_t *vlanIdUint = vlanId->get_ptr<const uint64_t *>(); 8864a0cb85cSEd Tanous if (vlanIdUint == nullptr) 8874a0cb85cSEd Tanous { 888f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanId->dump(), 889a08b46ccSJason M. Bills "VLANId"); 8904a0cb85cSEd Tanous return; 8914a0cb85cSEd Tanous } 8924a0cb85cSEd Tanous 8934a0cb85cSEd Tanous if (!ethData.vlan_id) 8941abe55efSEd Tanous { 895e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 896e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 897a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, "VLANEnable"); 898588c3f0dSKowalski, Kamil 899588c3f0dSKowalski, Kamil return; 900588c3f0dSKowalski, Kamil } 901588c3f0dSKowalski, Kamil 902588c3f0dSKowalski, Kamil // VLAN is configured on the interface 9034a0cb85cSEd Tanous if (*vlanEnableBool == true) 9041abe55efSEd Tanous { 905588c3f0dSKowalski, Kamil // Change VLAN Id 9064a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANId"] = *vlanIdUint; 9074a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9081abe55efSEd Tanous if (ec) 9091abe55efSEd Tanous { 910f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9111abe55efSEd Tanous } 9121abe55efSEd Tanous else 9131abe55efSEd Tanous { 9144a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 915e439f0f8SKowalski, Kamil } 9164a0cb85cSEd Tanous }; 9174a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9184a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9194a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9204a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 9214a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 9224a0cb85cSEd Tanous sdbusplus::message::variant<uint32_t>(*vlanIdUint)); 9231abe55efSEd Tanous } 9244a0cb85cSEd Tanous else 9251abe55efSEd Tanous { 9264a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9271abe55efSEd Tanous if (ec) 9281abe55efSEd Tanous { 929f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9304a0cb85cSEd Tanous return; 9311abe55efSEd Tanous } 9324a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 9334a0cb85cSEd Tanous }; 9344a0cb85cSEd Tanous 9354a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9364a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9374a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9384a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 939588c3f0dSKowalski, Kamil } 940588c3f0dSKowalski, Kamil } 941588c3f0dSKowalski, Kamil 942e439f0f8SKowalski, Kamil private: 943588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 9444a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9451abe55efSEd Tanous { 9464a0cb85cSEd Tanous const std::string *newHostname = input.get_ptr<const std::string *>(); 9474a0cb85cSEd Tanous if (newHostname == nullptr) 9481abe55efSEd Tanous { 949f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 950a08b46ccSJason M. Bills "HostName"); 9514a0cb85cSEd Tanous return; 9524a0cb85cSEd Tanous } 9534a0cb85cSEd Tanous 9544a0cb85cSEd Tanous // Change hostname 955a08b46ccSJason M. Bills setHostName(*newHostname, 956a08b46ccSJason M. Bills [asyncResp, newHostname{std::string(*newHostname)}]( 9574a0cb85cSEd Tanous const boost::system::error_code ec) { 9584a0cb85cSEd Tanous if (ec) 9594a0cb85cSEd Tanous { 960a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 9611abe55efSEd Tanous } 9621abe55efSEd Tanous else 9631abe55efSEd Tanous { 96455c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 965588c3f0dSKowalski, Kamil } 966588c3f0dSKowalski, Kamil }); 967588c3f0dSKowalski, Kamil } 968588c3f0dSKowalski, Kamil 9694a0cb85cSEd Tanous void handleIPv4Patch( 9704a0cb85cSEd Tanous const std::string &ifaceId, const nlohmann::json &input, 9714a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 9724a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9731abe55efSEd Tanous { 9741abe55efSEd Tanous if (!input.is_array()) 9751abe55efSEd Tanous { 976f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 977a08b46ccSJason M. Bills "IPv4Addresses"); 978179db1d7SKowalski, Kamil return; 979179db1d7SKowalski, Kamil } 980179db1d7SKowalski, Kamil 981179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 9824a0cb85cSEd Tanous if (input.size() < ipv4Data.size()) 9831abe55efSEd Tanous { 984a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, input.dump(), 985a08b46ccSJason M. Bills "IPv4Addresses"); 986179db1d7SKowalski, Kamil return; 987179db1d7SKowalski, Kamil } 988179db1d7SKowalski, Kamil 9894a0cb85cSEd Tanous int entryIdx = 0; 9904a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 9914a0cb85cSEd Tanous ipv4Data.begin(); 9924a0cb85cSEd Tanous for (const nlohmann::json &thisJson : input) 9931abe55efSEd Tanous { 9944a0cb85cSEd Tanous std::string pathString = 995a08b46ccSJason M. Bills "IPv4Addresses/" + std::to_string(entryIdx); 996179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 9974a0cb85cSEd Tanous if (!thisJson.is_object() && !thisJson.is_null()) 9981abe55efSEd Tanous { 999a08b46ccSJason M. Bills messages::propertyValueTypeError(asyncResp->res, 1000a08b46ccSJason M. Bills thisJson.dump(), 1001a08b46ccSJason M. Bills pathString + "/IPv4Address"); 1002179db1d7SKowalski, Kamil 1003179db1d7SKowalski, Kamil continue; 1004179db1d7SKowalski, Kamil } 1005179db1d7SKowalski, Kamil 10064a0cb85cSEd Tanous nlohmann::json::const_iterator addressFieldIt = 10074a0cb85cSEd Tanous thisJson.find("Address"); 10084a0cb85cSEd Tanous const std::string *addressField = nullptr; 10094a0cb85cSEd Tanous if (addressFieldIt != thisJson.end()) 10101abe55efSEd Tanous { 10114a0cb85cSEd Tanous addressField = addressFieldIt->get_ptr<const std::string *>(); 10124a0cb85cSEd Tanous if (addressField == nullptr) 10131abe55efSEd Tanous { 1014a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, 1015a08b46ccSJason M. Bills addressFieldIt->dump(), 10164a0cb85cSEd Tanous pathString + "/Address"); 1017179db1d7SKowalski, Kamil continue; 1018179db1d7SKowalski, Kamil } 10191abe55efSEd Tanous else 10201abe55efSEd Tanous { 10214a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*addressField)) 10224a0cb85cSEd Tanous { 1023f12894f8SJason M. Bills messages::propertyValueFormatError( 1024a08b46ccSJason M. Bills asyncResp->res, *addressField, 10254a0cb85cSEd Tanous pathString + "/Address"); 10264a0cb85cSEd Tanous continue; 10274a0cb85cSEd Tanous } 10284a0cb85cSEd Tanous } 10294a0cb85cSEd Tanous } 10304a0cb85cSEd Tanous 1031*a24526dcSEd Tanous std::optional<uint8_t> prefixLength; 10324a0cb85cSEd Tanous const std::string *subnetField = nullptr; 10334a0cb85cSEd Tanous nlohmann::json::const_iterator subnetFieldIt = 10344a0cb85cSEd Tanous thisJson.find("SubnetMask"); 10354a0cb85cSEd Tanous if (subnetFieldIt != thisJson.end()) 10364a0cb85cSEd Tanous { 10374a0cb85cSEd Tanous subnetField = subnetFieldIt->get_ptr<const std::string *>(); 10384a0cb85cSEd Tanous if (subnetField == nullptr) 10394a0cb85cSEd Tanous { 1040f12894f8SJason M. Bills messages::propertyValueFormatError( 1041a08b46ccSJason M. Bills asyncResp->res, *subnetField, 10424a0cb85cSEd Tanous pathString + "/SubnetMask"); 10434a0cb85cSEd Tanous continue; 10444a0cb85cSEd Tanous } 10454a0cb85cSEd Tanous else 10464a0cb85cSEd Tanous { 10474a0cb85cSEd Tanous prefixLength = 0; 10484a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetField, 10494a0cb85cSEd Tanous &*prefixLength)) 10504a0cb85cSEd Tanous { 1051f12894f8SJason M. Bills messages::propertyValueFormatError( 1052a08b46ccSJason M. Bills asyncResp->res, *subnetField, 10534a0cb85cSEd Tanous pathString + "/SubnetMask"); 10544a0cb85cSEd Tanous continue; 10554a0cb85cSEd Tanous } 10564a0cb85cSEd Tanous } 10574a0cb85cSEd Tanous } 10584a0cb85cSEd Tanous 10594a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 10604a0cb85cSEd Tanous const std::string *addressOriginField = nullptr; 10614a0cb85cSEd Tanous nlohmann::json::const_iterator addressOriginFieldIt = 10624a0cb85cSEd Tanous thisJson.find("AddressOrigin"); 10634a0cb85cSEd Tanous if (addressOriginFieldIt != thisJson.end()) 10644a0cb85cSEd Tanous { 10654a0cb85cSEd Tanous const std::string *addressOriginField = 10664a0cb85cSEd Tanous addressOriginFieldIt->get_ptr<const std::string *>(); 10674a0cb85cSEd Tanous if (addressOriginField == nullptr) 10684a0cb85cSEd Tanous { 1069f12894f8SJason M. Bills messages::propertyValueFormatError( 1070a08b46ccSJason M. Bills asyncResp->res, *addressOriginField, 10714a0cb85cSEd Tanous pathString + "/AddressOrigin"); 10724a0cb85cSEd Tanous continue; 10734a0cb85cSEd Tanous } 10744a0cb85cSEd Tanous else 10754a0cb85cSEd Tanous { 10764a0cb85cSEd Tanous // Get Address origin in proper format 10774a0cb85cSEd Tanous addressOriginInDBusFormat = 10784a0cb85cSEd Tanous translateAddressOriginRedfishToDbus( 10794a0cb85cSEd Tanous *addressOriginField); 10804a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 10814a0cb85cSEd Tanous { 10824a0cb85cSEd Tanous messages::propertyValueNotInList( 1083f12894f8SJason M. Bills asyncResp->res, *addressOriginField, 1084a08b46ccSJason M. Bills pathString + "/AddressOrigin"); 10854a0cb85cSEd Tanous continue; 10864a0cb85cSEd Tanous } 10874a0cb85cSEd Tanous } 10884a0cb85cSEd Tanous } 10894a0cb85cSEd Tanous 10904a0cb85cSEd Tanous nlohmann::json::const_iterator gatewayFieldIt = 10914a0cb85cSEd Tanous thisJson.find("Gateway"); 10924a0cb85cSEd Tanous const std::string *gatewayField = nullptr; 10934a0cb85cSEd Tanous if (gatewayFieldIt != thisJson.end()) 10944a0cb85cSEd Tanous { 10954a0cb85cSEd Tanous const std::string *gatewayField = 10964a0cb85cSEd Tanous gatewayFieldIt->get_ptr<const std::string *>(); 10974a0cb85cSEd Tanous if (gatewayField == nullptr || 10984a0cb85cSEd Tanous !ipv4VerifyIpAndGetBitcount(*gatewayField)) 10994a0cb85cSEd Tanous { 1100a08b46ccSJason M. Bills messages::propertyValueFormatError( 1101a08b46ccSJason M. Bills asyncResp->res, *gatewayField, pathString + "/Gateway"); 11024a0cb85cSEd Tanous continue; 11034a0cb85cSEd Tanous } 11044a0cb85cSEd Tanous } 11054a0cb85cSEd Tanous 11064a0cb85cSEd Tanous // if a vlan already exists, modify the existing 11074a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 11084a0cb85cSEd Tanous { 11091abe55efSEd Tanous // Existing object that should be modified/deleted/remain 11101abe55efSEd Tanous // unchanged 11114a0cb85cSEd Tanous if (thisJson.is_null()) 11121abe55efSEd Tanous { 11134a0cb85cSEd Tanous auto callback = [entryIdx{std::to_string(entryIdx)}, 11144a0cb85cSEd Tanous asyncResp]( 11154a0cb85cSEd Tanous const boost::system::error_code ec) { 11164a0cb85cSEd Tanous if (ec) 11174a0cb85cSEd Tanous { 1118a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11194a0cb85cSEd Tanous return; 11201abe55efSEd Tanous } 11214a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 11224a0cb85cSEd Tanous nullptr; 11234a0cb85cSEd Tanous }; 11244a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11254a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11264a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 11274a0cb85cSEd Tanous thisData->id, 11284a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 1129179db1d7SKowalski, Kamil } 11304a0cb85cSEd Tanous else if (thisJson.is_object()) 11314a0cb85cSEd Tanous { 1132179db1d7SKowalski, Kamil // Apply changes 11334a0cb85cSEd Tanous if (addressField != nullptr) 11341abe55efSEd Tanous { 11354a0cb85cSEd Tanous auto callback = 11364a0cb85cSEd Tanous [asyncResp, entryIdx, 11374a0cb85cSEd Tanous addressField{std::string(*addressField)}]( 11384a0cb85cSEd Tanous const boost::system::error_code ec) { 11394a0cb85cSEd Tanous if (ec) 11401abe55efSEd Tanous { 1141a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11424a0cb85cSEd Tanous return; 11434a0cb85cSEd Tanous } 11444a0cb85cSEd Tanous asyncResp->res 11454a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 11464a0cb85cSEd Tanous entryIdx)]["Address"] = addressField; 11474a0cb85cSEd Tanous }; 11484a0cb85cSEd Tanous 11494a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11504a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11514a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 11524a0cb85cSEd Tanous "/ipv4/" + thisData->id, 11534a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11544a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 11554a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 11564a0cb85cSEd Tanous *addressField)); 1157179db1d7SKowalski, Kamil } 1158179db1d7SKowalski, Kamil 11594a0cb85cSEd Tanous if (prefixLength && subnetField != nullptr) 11601abe55efSEd Tanous { 11614a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 11624a0cb85cSEd Tanous thisData->id, *subnetField, 11634a0cb85cSEd Tanous *prefixLength, asyncResp); 1164179db1d7SKowalski, Kamil } 1165179db1d7SKowalski, Kamil 11664a0cb85cSEd Tanous if (!addressOriginInDBusFormat.empty() && 11674a0cb85cSEd Tanous addressOriginField != nullptr) 11681abe55efSEd Tanous { 11694a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 11704a0cb85cSEd Tanous *addressOriginField, 11714a0cb85cSEd Tanous addressOriginInDBusFormat, asyncResp); 1172179db1d7SKowalski, Kamil } 1173179db1d7SKowalski, Kamil 11744a0cb85cSEd Tanous if (gatewayField != nullptr) 11751abe55efSEd Tanous { 11764a0cb85cSEd Tanous auto callback = 11774a0cb85cSEd Tanous [asyncResp, entryIdx, 11784a0cb85cSEd Tanous gatewayField{std::string(*gatewayField)}]( 11794a0cb85cSEd Tanous const boost::system::error_code ec) { 11804a0cb85cSEd Tanous if (ec) 11811abe55efSEd Tanous { 1182a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11834a0cb85cSEd Tanous return; 11844a0cb85cSEd Tanous } 11854a0cb85cSEd Tanous asyncResp->res 11864a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 11874a0cb85cSEd Tanous entryIdx)]["Gateway"] = 11884a0cb85cSEd Tanous std::move(gatewayField); 11894a0cb85cSEd Tanous }; 11904a0cb85cSEd Tanous 11914a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11924a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11934a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 11944a0cb85cSEd Tanous "/ipv4/" + thisData->id, 11954a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11964a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 11974a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 11984a0cb85cSEd Tanous *gatewayField)); 11994a0cb85cSEd Tanous } 12004a0cb85cSEd Tanous } 12014a0cb85cSEd Tanous thisData++; 12021abe55efSEd Tanous } 12031abe55efSEd Tanous else 12041abe55efSEd Tanous { 12054a0cb85cSEd Tanous // Create IPv4 with provided data 12064a0cb85cSEd Tanous if (gatewayField == nullptr) 12071abe55efSEd Tanous { 1208a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12094a0cb85cSEd Tanous pathString + "/Gateway"); 12104a0cb85cSEd Tanous continue; 12114a0cb85cSEd Tanous } 12124a0cb85cSEd Tanous 12134a0cb85cSEd Tanous if (addressField == nullptr) 12141abe55efSEd Tanous { 1215a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12164a0cb85cSEd Tanous pathString + "/Address"); 12174a0cb85cSEd Tanous continue; 12184a0cb85cSEd Tanous } 12194a0cb85cSEd Tanous 12204a0cb85cSEd Tanous if (!prefixLength) 12211abe55efSEd Tanous { 1222a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12234a0cb85cSEd Tanous pathString + "/SubnetMask"); 12244a0cb85cSEd Tanous continue; 1225588c3f0dSKowalski, Kamil } 1226588c3f0dSKowalski, Kamil 12274a0cb85cSEd Tanous createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField, 12284a0cb85cSEd Tanous *addressField, asyncResp); 12294a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 12304a0cb85cSEd Tanous } 12314a0cb85cSEd Tanous entryIdx++; 12324a0cb85cSEd Tanous } 12334a0cb85cSEd Tanous } 12344a0cb85cSEd Tanous 12350f74e643SEd Tanous void parseInterfaceData( 12360f74e643SEd Tanous nlohmann::json &json_response, const std::string &iface_id, 12370f74e643SEd Tanous const EthernetInterfaceData ðData, 12384a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 12394a0cb85cSEd Tanous { 12404a0cb85cSEd Tanous json_response["Id"] = iface_id; 12414a0cb85cSEd Tanous json_response["@odata.id"] = 12424a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 12434a0cb85cSEd Tanous 12444a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 12454a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 12464a0cb85cSEd Tanous if (!ethData.hostname.empty()) 12474a0cb85cSEd Tanous { 12484a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 12494a0cb85cSEd Tanous } 12504a0cb85cSEd Tanous 12514a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 12524a0cb85cSEd Tanous if (ethData.vlan_id) 12534a0cb85cSEd Tanous { 12544a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 12554a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 12564a0cb85cSEd Tanous } 12574a0cb85cSEd Tanous else 12584a0cb85cSEd Tanous { 12594a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 12604a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 12614a0cb85cSEd Tanous } 12624a0cb85cSEd Tanous 12634a0cb85cSEd Tanous if (ipv4Data.size() > 0) 12644a0cb85cSEd Tanous { 12654a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 12664a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 12674a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 12684a0cb85cSEd Tanous { 12694a0cb85cSEd Tanous if (!ipv4_config.address.empty()) 12704a0cb85cSEd Tanous { 12714a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 12724a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 12734a0cb85cSEd Tanous {"Address", ipv4_config.address}}); 12744a0cb85cSEd Tanous 12754a0cb85cSEd Tanous if (!ipv4_config.gateway.empty()) 12764a0cb85cSEd Tanous { 12774a0cb85cSEd Tanous ipv4_array.back()["Gateway"] = ipv4_config.gateway; 12784a0cb85cSEd Tanous } 12794a0cb85cSEd Tanous } 12804a0cb85cSEd Tanous } 12814a0cb85cSEd Tanous } 1282588c3f0dSKowalski, Kamil } 1283588c3f0dSKowalski, Kamil 12849391bb9cSRapkiewicz, Pawel /** 12859391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12869391bb9cSRapkiewicz, Pawel */ 128755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12881abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12891abe55efSEd Tanous { 12904a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12911abe55efSEd Tanous if (params.size() != 1) 12921abe55efSEd Tanous { 1293f12894f8SJason M. Bills messages::internalError(asyncResp->res); 12949391bb9cSRapkiewicz, Pawel return; 12959391bb9cSRapkiewicz, Pawel } 12969391bb9cSRapkiewicz, Pawel 12974a0cb85cSEd Tanous getEthernetIfaceData( 12984a0cb85cSEd Tanous params[0], 12994a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 13004a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13014a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13024a0cb85cSEd Tanous if (!success) 13031abe55efSEd Tanous { 13041abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13051abe55efSEd Tanous // object, and other errors 1306f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1307f12894f8SJason M. Bills "EthernetInterface", iface_id); 13084a0cb85cSEd Tanous return; 13099391bb9cSRapkiewicz, Pawel } 13100f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 13110f74e643SEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 13120f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 13130f74e643SEd Tanous "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 13140f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; 13150f74e643SEd Tanous asyncResp->res.jsonValue["Description"] = 13160f74e643SEd Tanous "Management Network Interface"; 13170f74e643SEd Tanous 13180f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13190f74e643SEd Tanous ipv4Data); 13209391bb9cSRapkiewicz, Pawel }); 13219391bb9cSRapkiewicz, Pawel } 13229391bb9cSRapkiewicz, Pawel 132355c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 13241abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13251abe55efSEd Tanous { 13264a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13271abe55efSEd Tanous if (params.size() != 1) 13281abe55efSEd Tanous { 1329f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1330588c3f0dSKowalski, Kamil return; 1331588c3f0dSKowalski, Kamil } 1332588c3f0dSKowalski, Kamil 13334a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1334588c3f0dSKowalski, Kamil 1335179db1d7SKowalski, Kamil nlohmann::json patchReq; 13361abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 13371abe55efSEd Tanous { 1338588c3f0dSKowalski, Kamil return; 1339588c3f0dSKowalski, Kamil } 1340588c3f0dSKowalski, Kamil 13414a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1342588c3f0dSKowalski, Kamil // preparation 13434a0cb85cSEd Tanous getEthernetIfaceData( 13444a0cb85cSEd Tanous iface_id, 13454a0cb85cSEd Tanous [this, asyncResp, iface_id, patchReq = std::move(patchReq)]( 13464a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13474a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13481abe55efSEd Tanous if (!success) 13491abe55efSEd Tanous { 1350588c3f0dSKowalski, Kamil // ... otherwise return error 13511abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13521abe55efSEd Tanous // object, and other errors 1353f12894f8SJason M. Bills messages::resourceNotFound( 1354f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1355588c3f0dSKowalski, Kamil return; 1356588c3f0dSKowalski, Kamil } 1357588c3f0dSKowalski, Kamil 13580f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13590f74e643SEd Tanous ipv4Data); 1360588c3f0dSKowalski, Kamil 13614a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 13621abe55efSEd Tanous { 13631abe55efSEd Tanous if (propertyIt.key() == "VLAN") 13641abe55efSEd Tanous { 13654a0cb85cSEd Tanous handleVlanPatch(iface_id, propertyIt.value(), ethData, 13664a0cb85cSEd Tanous asyncResp); 13671abe55efSEd Tanous } 13681abe55efSEd Tanous else if (propertyIt.key() == "HostName") 13691abe55efSEd Tanous { 13704a0cb85cSEd Tanous handleHostnamePatch(propertyIt.value(), asyncResp); 13711abe55efSEd Tanous } 13721abe55efSEd Tanous else if (propertyIt.key() == "IPv4Addresses") 13731abe55efSEd Tanous { 13744a0cb85cSEd Tanous handleIPv4Patch(iface_id, propertyIt.value(), ipv4Data, 1375179db1d7SKowalski, Kamil asyncResp); 13761abe55efSEd Tanous } 13771abe55efSEd Tanous else if (propertyIt.key() == "IPv6Addresses") 13781abe55efSEd Tanous { 1379179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1380a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, 1381a08b46ccSJason M. Bills propertyIt.key()); 13821abe55efSEd Tanous } 13831abe55efSEd Tanous else 13841abe55efSEd Tanous { 13851abe55efSEd Tanous auto fieldInJsonIt = 13864a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 1387588c3f0dSKowalski, Kamil 13884a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 13891abe55efSEd Tanous { 1390588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1391f12894f8SJason M. Bills messages::propertyUnknown(asyncResp->res, 1392f12894f8SJason M. Bills propertyIt.key()); 13931abe55efSEd Tanous } 13944a0cb85cSEd Tanous else 13951abe55efSEd Tanous { 1396588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1397f12894f8SJason M. Bills messages::propertyNotWritable(asyncResp->res, 1398f12894f8SJason M. Bills propertyIt.key()); 1399588c3f0dSKowalski, Kamil } 1400588c3f0dSKowalski, Kamil } 1401588c3f0dSKowalski, Kamil } 1402588c3f0dSKowalski, Kamil }); 1403588c3f0dSKowalski, Kamil } 14049391bb9cSRapkiewicz, Pawel }; 14059391bb9cSRapkiewicz, Pawel 1406e439f0f8SKowalski, Kamil /** 14074a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 14084a0cb85cSEd Tanous * Schema 1409e439f0f8SKowalski, Kamil */ 14101abe55efSEd Tanous class VlanNetworkInterface : public Node 14111abe55efSEd Tanous { 1412e439f0f8SKowalski, Kamil public: 1413e439f0f8SKowalski, Kamil /* 1414e439f0f8SKowalski, Kamil * Default Constructor 1415e439f0f8SKowalski, Kamil */ 1416e439f0f8SKowalski, Kamil template <typename CrowApp> 14171abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 14184a0cb85cSEd Tanous Node(app, 14190f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>", 14201abe55efSEd Tanous std::string(), std::string()) 14211abe55efSEd Tanous { 1422e439f0f8SKowalski, Kamil entityPrivileges = { 1423e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1424e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1425e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1426e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1427e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1428e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1429e439f0f8SKowalski, Kamil } 1430e439f0f8SKowalski, Kamil 1431e439f0f8SKowalski, Kamil private: 14320f74e643SEd Tanous void parseInterfaceData( 14330f74e643SEd Tanous nlohmann::json &json_response, const std::string &parent_iface_id, 14340f74e643SEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 14354a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 14361abe55efSEd Tanous { 1437e439f0f8SKowalski, Kamil // Fill out obvious data... 14384a0cb85cSEd Tanous json_response["Id"] = iface_id; 14394a0cb85cSEd Tanous json_response["@odata.id"] = 14404a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 14414a0cb85cSEd Tanous "/VLANs/" + iface_id; 1442e439f0f8SKowalski, Kamil 14434a0cb85cSEd Tanous json_response["VLANEnable"] = true; 14444a0cb85cSEd Tanous if (ethData.vlan_id) 14454a0cb85cSEd Tanous { 14464a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 14474a0cb85cSEd Tanous } 1448e439f0f8SKowalski, Kamil } 1449e439f0f8SKowalski, Kamil 145055c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 14511abe55efSEd Tanous const std::string &iface) 14521abe55efSEd Tanous { 1453f12894f8SJason M. Bills std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14541abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 14551abe55efSEd Tanous { 1456f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1457f12894f8SJason M. Bills iface); 1458927a505aSKowalski, Kamil return false; 14591abe55efSEd Tanous } 14601abe55efSEd Tanous else 14611abe55efSEd Tanous { 1462927a505aSKowalski, Kamil return true; 1463927a505aSKowalski, Kamil } 1464927a505aSKowalski, Kamil } 1465927a505aSKowalski, Kamil 1466e439f0f8SKowalski, Kamil /** 1467e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1468e439f0f8SKowalski, Kamil */ 146955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 14701abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14711abe55efSEd Tanous { 14724a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14734a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1474e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1475e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1476e439f0f8SKowalski, Kamil // impossible. 14771abe55efSEd Tanous if (params.size() != 2) 14781abe55efSEd Tanous { 1479f12894f8SJason M. Bills messages::internalError(res); 1480e439f0f8SKowalski, Kamil res.end(); 1481e439f0f8SKowalski, Kamil return; 1482e439f0f8SKowalski, Kamil } 1483e439f0f8SKowalski, Kamil 14844a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 14854a0cb85cSEd Tanous const std::string &iface_id = params[1]; 14860f74e643SEd Tanous res.jsonValue["@odata.type"] = 14870f74e643SEd Tanous "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 14880f74e643SEd Tanous res.jsonValue["@odata.context"] = 14890f74e643SEd Tanous "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 14900f74e643SEd Tanous res.jsonValue["Name"] = "VLAN Network Interface"; 1491e439f0f8SKowalski, Kamil 14924a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 14931abe55efSEd Tanous { 1494a434f2bdSEd Tanous return; 1495a434f2bdSEd Tanous } 1496a434f2bdSEd Tanous 1497e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1498e439f0f8SKowalski, Kamil // preparation 14994a0cb85cSEd Tanous getEthernetIfaceData( 15004a0cb85cSEd Tanous iface_id, 15014a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 15024a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15034a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15044a0cb85cSEd Tanous if (success && ethData.vlan_id) 15051abe55efSEd Tanous { 15060f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, 15070f74e643SEd Tanous parent_iface_id, iface_id, ethData, 15080f74e643SEd Tanous ipv4Data); 15091abe55efSEd Tanous } 15101abe55efSEd Tanous else 15111abe55efSEd Tanous { 1512e439f0f8SKowalski, Kamil // ... otherwise return error 15131abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15141abe55efSEd Tanous // object, and other errors 1515f12894f8SJason M. Bills messages::resourceNotFound( 1516f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1517e439f0f8SKowalski, Kamil } 1518e439f0f8SKowalski, Kamil }); 1519e439f0f8SKowalski, Kamil } 1520e439f0f8SKowalski, Kamil 152155c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 15221abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15231abe55efSEd Tanous { 15244a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15251abe55efSEd Tanous if (params.size() != 2) 15261abe55efSEd Tanous { 1527f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1528e439f0f8SKowalski, Kamil return; 1529e439f0f8SKowalski, Kamil } 1530e439f0f8SKowalski, Kamil 1531d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 153255c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1533927a505aSKowalski, Kamil 15341abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 15351abe55efSEd Tanous { 1536927a505aSKowalski, Kamil return; 1537927a505aSKowalski, Kamil } 1538927a505aSKowalski, Kamil 1539927a505aSKowalski, Kamil nlohmann::json patchReq; 15401abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 15411abe55efSEd Tanous { 1542927a505aSKowalski, Kamil return; 1543927a505aSKowalski, Kamil } 1544927a505aSKowalski, Kamil 1545927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1546927a505aSKowalski, Kamil // preparation 15474a0cb85cSEd Tanous getEthernetIfaceData( 15481abe55efSEd Tanous ifaceId, 15494a0cb85cSEd Tanous [this, asyncResp, parentIfaceId, ifaceId, 15504a0cb85cSEd Tanous patchReq{std::move(patchReq)}]( 15514a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15524a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15531abe55efSEd Tanous if (!success) 15541abe55efSEd Tanous { 15551abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15561abe55efSEd Tanous // object, and other errors 1557f12894f8SJason M. Bills messages::resourceNotFound( 1558f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1559927a505aSKowalski, Kamil 1560927a505aSKowalski, Kamil return; 1561927a505aSKowalski, Kamil } 1562927a505aSKowalski, Kamil 15630f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15640f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1565927a505aSKowalski, Kamil 15664a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 15671abe55efSEd Tanous { 1568927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 15691abe55efSEd Tanous propertyIt.key() != "VLANId") 15701abe55efSEd Tanous { 15711abe55efSEd Tanous auto fieldInJsonIt = 15724a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 15734a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 15741abe55efSEd Tanous { 1575927a505aSKowalski, Kamil // Field not in scope of defined fields 1576f12894f8SJason M. Bills messages::propertyUnknown(asyncResp->res, 1577f12894f8SJason M. Bills propertyIt.key()); 15781abe55efSEd Tanous } 15794a0cb85cSEd Tanous else 15801abe55efSEd Tanous { 1581927a505aSKowalski, Kamil // User attempted to modify non-writable field 1582f12894f8SJason M. Bills messages::propertyNotWritable(asyncResp->res, 1583f12894f8SJason M. Bills propertyIt.key()); 1584927a505aSKowalski, Kamil } 1585927a505aSKowalski, Kamil } 1586927a505aSKowalski, Kamil } 1587927a505aSKowalski, Kamil 15884a0cb85cSEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, ethData, 15894a0cb85cSEd Tanous asyncResp); 1590927a505aSKowalski, Kamil }); 1591e439f0f8SKowalski, Kamil } 1592e439f0f8SKowalski, Kamil 159355c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 15941abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15951abe55efSEd Tanous { 15964a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15971abe55efSEd Tanous if (params.size() != 2) 15981abe55efSEd Tanous { 1599f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1600e439f0f8SKowalski, Kamil return; 1601e439f0f8SKowalski, Kamil } 1602e439f0f8SKowalski, Kamil 1603d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 160455c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1605927a505aSKowalski, Kamil 16064a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 16071abe55efSEd Tanous { 1608927a505aSKowalski, Kamil return; 1609927a505aSKowalski, Kamil } 1610927a505aSKowalski, Kamil 1611927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1612927a505aSKowalski, Kamil // preparation 1613f12894f8SJason M. Bills getEthernetIfaceData( 1614f12894f8SJason M. Bills ifaceId, 1615f12894f8SJason M. Bills [this, asyncResp, parentIfaceId{std::string(parentIfaceId)}, 16164a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1617f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1618f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 16194a0cb85cSEd Tanous if (success && ethData.vlan_id) 16201abe55efSEd Tanous { 16210f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 16220f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1623927a505aSKowalski, Kamil 1624f12894f8SJason M. Bills auto callback = 1625f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 16261abe55efSEd Tanous if (ec) 16271abe55efSEd Tanous { 1628f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1629927a505aSKowalski, Kamil } 16304a0cb85cSEd Tanous }; 16314a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 16324a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 16334a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 16344a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 16351abe55efSEd Tanous } 16361abe55efSEd Tanous else 16371abe55efSEd Tanous { 1638927a505aSKowalski, Kamil // ... otherwise return error 1639f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1640f12894f8SJason M. Bills // object, and other errors 1641f12894f8SJason M. Bills messages::resourceNotFound( 1642f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1643927a505aSKowalski, Kamil } 1644927a505aSKowalski, Kamil }); 1645e439f0f8SKowalski, Kamil } 1646e439f0f8SKowalski, Kamil }; 1647e439f0f8SKowalski, Kamil 1648e439f0f8SKowalski, Kamil /** 1649e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1650e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1651e439f0f8SKowalski, Kamil */ 16521abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 16531abe55efSEd Tanous { 1654e439f0f8SKowalski, Kamil public: 1655e439f0f8SKowalski, Kamil template <typename CrowApp> 16561abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 16574a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 16584a0cb85cSEd Tanous std::string()) 16591abe55efSEd Tanous { 1660e439f0f8SKowalski, Kamil entityPrivileges = { 1661e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1662e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1663e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1664e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1665e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1666e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1667e439f0f8SKowalski, Kamil } 1668e439f0f8SKowalski, Kamil 1669e439f0f8SKowalski, Kamil private: 1670e439f0f8SKowalski, Kamil /** 1671e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1672e439f0f8SKowalski, Kamil */ 167355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 16741abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16751abe55efSEd Tanous { 16764a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16771abe55efSEd Tanous if (params.size() != 1) 16781abe55efSEd Tanous { 1679e439f0f8SKowalski, Kamil // This means there is a problem with the router 1680f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1681e439f0f8SKowalski, Kamil return; 1682e439f0f8SKowalski, Kamil } 1683e439f0f8SKowalski, Kamil 16844a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1685e439f0f8SKowalski, Kamil 16864a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 16871abe55efSEd Tanous // preparation 1688f12894f8SJason M. Bills getEthernetIfaceList( 1689f12894f8SJason M. Bills [this, asyncResp, 1690f12894f8SJason M. Bills rootInterfaceName{std::string(rootInterfaceName)}]( 16911abe55efSEd Tanous const bool &success, 16921abe55efSEd Tanous const std::vector<std::string> &iface_list) { 16934a0cb85cSEd Tanous if (!success) 16941abe55efSEd Tanous { 1695f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16964a0cb85cSEd Tanous return; 16971abe55efSEd Tanous } 16980f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 16990f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 17000f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 17010f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 17020f74e643SEd Tanous "/redfish/v1/$metadata" 17030f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 17040f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 17050f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = 17060f74e643SEd Tanous "VLAN Network Interface Collection"; 17074a0cb85cSEd Tanous 17084a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 17094a0cb85cSEd Tanous 17104a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 17111abe55efSEd Tanous { 17124a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 17134a0cb85cSEd Tanous { 17144a0cb85cSEd Tanous iface_array.push_back( 17154a0cb85cSEd Tanous {{"@odata.id", 17164a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17174a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1718e439f0f8SKowalski, Kamil } 1719e439f0f8SKowalski, Kamil } 1720e439f0f8SKowalski, Kamil 17214a0cb85cSEd Tanous if (iface_array.empty()) 17221abe55efSEd Tanous { 1723f12894f8SJason M. Bills messages::resourceNotFound( 1724f12894f8SJason M. Bills asyncResp->res, "EthernetInterface", rootInterfaceName); 17254a0cb85cSEd Tanous return; 1726e439f0f8SKowalski, Kamil } 17274a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 17284a0cb85cSEd Tanous iface_array.size(); 17294a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 17304a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17314a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17324a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1733e439f0f8SKowalski, Kamil }); 1734e439f0f8SKowalski, Kamil } 1735e439f0f8SKowalski, Kamil 173655c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 17371abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17381abe55efSEd Tanous { 17394a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17401abe55efSEd Tanous if (params.size() != 1) 17411abe55efSEd Tanous { 1742f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1743e439f0f8SKowalski, Kamil return; 1744e439f0f8SKowalski, Kamil } 1745e439f0f8SKowalski, Kamil nlohmann::json postReq; 17461abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, postReq)) 17471abe55efSEd Tanous { 1748e439f0f8SKowalski, Kamil return; 1749e439f0f8SKowalski, Kamil } 1750e439f0f8SKowalski, Kamil 17510f74e643SEd Tanous auto vlanIdJson = postReq.find("VLANId"); 17521b6b96c5SEd Tanous 17530f74e643SEd Tanous if (vlanIdJson == postReq.end()) 17541abe55efSEd Tanous { 1755a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, "VLANId"); 1756e439f0f8SKowalski, Kamil return; 1757e439f0f8SKowalski, Kamil } 1758e439f0f8SKowalski, Kamil 17594a0cb85cSEd Tanous const uint64_t *vlanId = vlanIdJson->get_ptr<const uint64_t *>(); 17604a0cb85cSEd Tanous if (vlanId == nullptr) 17611abe55efSEd Tanous { 1762f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanIdJson->dump(), 1763a08b46ccSJason M. Bills "VLANId"); 17644a0cb85cSEd Tanous return; 1765e439f0f8SKowalski, Kamil } 17664a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1767e439f0f8SKowalski, Kamil 17684a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 17691abe55efSEd Tanous if (ec) 17701abe55efSEd Tanous { 17714a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 17724a0cb85cSEd Tanous // phosphor-network responses 1773f12894f8SJason M. Bills messages::internalError(asyncResp->res); 17744a0cb85cSEd Tanous return; 17751abe55efSEd Tanous } 1776f12894f8SJason M. Bills messages::created(asyncResp->res); 1777e439f0f8SKowalski, Kamil }; 17784a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 17794a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 17804a0cb85cSEd Tanous "/xyz/openbmc_project/network", 17814a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 17824a0cb85cSEd Tanous rootInterfaceName, static_cast<uint32_t>(*vlanId)); 17834a0cb85cSEd Tanous } 17844a0cb85cSEd Tanous }; 17859391bb9cSRapkiewicz, Pawel } // namespace redfish 1786