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> 23a24526dcSEd Tanous #include <optional> 24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 25*abf2add6SEd Tanous #include <variant> 269391bb9cSRapkiewicz, Pawel 271abe55efSEd Tanous namespace redfish 281abe55efSEd Tanous { 299391bb9cSRapkiewicz, Pawel 309391bb9cSRapkiewicz, Pawel /** 319391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 329391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 339391bb9cSRapkiewicz, Pawel */ 34aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 35*abf2add6SEd Tanous std::string, std::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< 43*abf2add6SEd Tanous std::string, 44*abf2add6SEd Tanous std::variant<std::string, bool, uint8_t, int16_t, uint16_t, int32_t, 45*abf2add6SEd Tanous 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; 83a24526dcSEd 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 = 174*abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 1754a0cb85cSEd Tanous if (mac != nullptr) 1764a0cb85cSEd Tanous { 1774a0cb85cSEd Tanous ethData.mac_address = *mac; 1784a0cb85cSEd Tanous } 1794a0cb85cSEd Tanous } 1804a0cb85cSEd Tanous } 1814a0cb85cSEd Tanous } 1824a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1834a0cb85cSEd Tanous { 1844a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1854a0cb85cSEd Tanous { 1864a0cb85cSEd Tanous if (propertyPair.first == "Id") 1874a0cb85cSEd Tanous { 1881b6b96c5SEd Tanous const uint32_t *id = 189*abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 1904a0cb85cSEd Tanous if (id != nullptr) 1914a0cb85cSEd Tanous { 1924a0cb85cSEd Tanous ethData.vlan_id = *id; 1934a0cb85cSEd Tanous } 1944a0cb85cSEd Tanous } 1954a0cb85cSEd Tanous } 1964a0cb85cSEd Tanous } 1974a0cb85cSEd Tanous else if (ifacePair.first == 1984a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 1994a0cb85cSEd Tanous { 2004a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2014a0cb85cSEd Tanous { 2024a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 2034a0cb85cSEd Tanous { 2044a0cb85cSEd Tanous const bool *auto_neg = 205*abf2add6SEd Tanous std::get_if<bool>(&propertyPair.second); 2064a0cb85cSEd Tanous if (auto_neg != nullptr) 2074a0cb85cSEd Tanous { 2084a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2094a0cb85cSEd Tanous } 2104a0cb85cSEd Tanous } 2114a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2124a0cb85cSEd Tanous { 2134a0cb85cSEd Tanous const uint32_t *speed = 214*abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 2154a0cb85cSEd Tanous if (speed != nullptr) 2164a0cb85cSEd Tanous { 2174a0cb85cSEd Tanous ethData.speed = *speed; 2184a0cb85cSEd Tanous } 2194a0cb85cSEd Tanous } 2204a0cb85cSEd Tanous } 2214a0cb85cSEd Tanous } 2224a0cb85cSEd Tanous else if (ifacePair.first == 2234a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2244a0cb85cSEd Tanous { 2254a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2264a0cb85cSEd Tanous { 2274a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2284a0cb85cSEd Tanous { 2294a0cb85cSEd Tanous const std::string *hostname = 230*abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 2314a0cb85cSEd Tanous if (hostname != nullptr) 2324a0cb85cSEd Tanous { 2334a0cb85cSEd Tanous ethData.hostname = *hostname; 2344a0cb85cSEd Tanous } 2354a0cb85cSEd Tanous } 2364a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2374a0cb85cSEd Tanous { 2384a0cb85cSEd Tanous const std::string *defaultGateway = 239*abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 2404a0cb85cSEd Tanous if (defaultGateway != nullptr) 2414a0cb85cSEd Tanous { 2424a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2434a0cb85cSEd Tanous } 2444a0cb85cSEd Tanous } 2454a0cb85cSEd Tanous } 2464a0cb85cSEd Tanous } 2474a0cb85cSEd Tanous } 2484a0cb85cSEd Tanous } 2494a0cb85cSEd Tanous } 2504a0cb85cSEd Tanous } 2514a0cb85cSEd Tanous 2524a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2534a0cb85cSEd Tanous inline void 2544a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2554a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2564a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2574a0cb85cSEd Tanous { 2584a0cb85cSEd Tanous const std::string ipv4PathStart = 2594a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 2604a0cb85cSEd Tanous 2614a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 2624a0cb85cSEd Tanous // single ethernet interface, loop over all of them 2634a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 2644a0cb85cSEd Tanous { 2654a0cb85cSEd Tanous // Check if proper pattern for object path appears 2664a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 2674a0cb85cSEd Tanous { 2684a0cb85cSEd Tanous for (auto &interface : objpath.second) 2694a0cb85cSEd Tanous { 2704a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 2714a0cb85cSEd Tanous { 2724a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 2734a0cb85cSEd Tanous // appropriate 2744a0cb85cSEd Tanous std::pair< 2754a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 2764a0cb85cSEd Tanous bool> 2774a0cb85cSEd Tanous it = ipv4_config.insert( 2784a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 2794a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 2804a0cb85cSEd Tanous for (auto &property : interface.second) 2814a0cb85cSEd Tanous { 2824a0cb85cSEd Tanous if (property.first == "Address") 2834a0cb85cSEd Tanous { 2844a0cb85cSEd Tanous const std::string *address = 285*abf2add6SEd Tanous std::get_if<std::string>(&property.second); 2864a0cb85cSEd Tanous if (address != nullptr) 2874a0cb85cSEd Tanous { 2884a0cb85cSEd Tanous ipv4_address.address = *address; 2894a0cb85cSEd Tanous } 2904a0cb85cSEd Tanous } 2914a0cb85cSEd Tanous else if (property.first == "Gateway") 2924a0cb85cSEd Tanous { 2934a0cb85cSEd Tanous const std::string *gateway = 294*abf2add6SEd Tanous std::get_if<std::string>(&property.second); 2954a0cb85cSEd Tanous if (gateway != nullptr) 2964a0cb85cSEd Tanous { 2974a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 2984a0cb85cSEd Tanous } 2994a0cb85cSEd Tanous } 3004a0cb85cSEd Tanous else if (property.first == "Origin") 3014a0cb85cSEd Tanous { 3024a0cb85cSEd Tanous const std::string *origin = 303*abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3044a0cb85cSEd Tanous if (origin != nullptr) 3054a0cb85cSEd Tanous { 3064a0cb85cSEd Tanous ipv4_address.origin = 3074a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3084a0cb85cSEd Tanous true); 3094a0cb85cSEd Tanous } 3104a0cb85cSEd Tanous } 3114a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3124a0cb85cSEd Tanous { 3134a0cb85cSEd Tanous const uint8_t *mask = 314*abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 3154a0cb85cSEd Tanous if (mask != nullptr) 3164a0cb85cSEd Tanous { 3174a0cb85cSEd Tanous // convert it to the string 3184a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3194a0cb85cSEd Tanous } 3204a0cb85cSEd Tanous } 3214a0cb85cSEd Tanous else 3224a0cb85cSEd Tanous { 3234a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3244a0cb85cSEd Tanous << "Got extra property: " << property.first 3254a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3264a0cb85cSEd Tanous } 3274a0cb85cSEd Tanous } 3284a0cb85cSEd Tanous // Check if given address is local, or global 3294a0cb85cSEd Tanous ipv4_address.linktype = 3304a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3314a0cb85cSEd Tanous ? LinkType::Global 3324a0cb85cSEd Tanous : LinkType::Local; 3334a0cb85cSEd Tanous } 3344a0cb85cSEd Tanous } 3354a0cb85cSEd Tanous } 3364a0cb85cSEd Tanous } 3374a0cb85cSEd Tanous } 338588c3f0dSKowalski, Kamil 339588c3f0dSKowalski, Kamil /** 340588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 341588c3f0dSKowalski, Kamil * 342588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 343588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 344588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 345588c3f0dSKowalski, Kamil * 346588c3f0dSKowalski, Kamil * @return None. 347588c3f0dSKowalski, Kamil */ 348588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3494a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3501abe55efSEd Tanous CallbackFunc &&callback) 3511abe55efSEd Tanous { 35255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 353588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 354588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 355588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 356588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 357*abf2add6SEd Tanous std::variant<uint32_t>(inputVlanId)); 3584a0cb85cSEd Tanous } 359588c3f0dSKowalski, Kamil 360588c3f0dSKowalski, Kamil /** 361179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 362179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 363179db1d7SKowalski, Kamil * bit count for Subnet Mask. 364179db1d7SKowalski, Kamil * 365179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 366179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 367179db1d7SKowalski, Kamil * 368179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 369179db1d7SKowalski, Kamil */ 3704a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3711abe55efSEd Tanous uint8_t *bits = nullptr) 3721abe55efSEd Tanous { 373179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 374179db1d7SKowalski, Kamil 375179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 376179db1d7SKowalski, Kamil 3774a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 3781abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 3791abe55efSEd Tanous { 380179db1d7SKowalski, Kamil return false; 381179db1d7SKowalski, Kamil } 382179db1d7SKowalski, Kamil 3831abe55efSEd Tanous if (bits != nullptr) 3841abe55efSEd Tanous { 385179db1d7SKowalski, Kamil *bits = 0; 386179db1d7SKowalski, Kamil } 387179db1d7SKowalski, Kamil 388179db1d7SKowalski, Kamil char *endPtr; 389179db1d7SKowalski, Kamil long previousValue = 255; 390179db1d7SKowalski, Kamil bool firstZeroInByteHit; 3911abe55efSEd Tanous for (const std::string &byte : bytesInMask) 3921abe55efSEd Tanous { 3931abe55efSEd Tanous if (byte.empty()) 3941abe55efSEd Tanous { 3951db9ca37SKowalski, Kamil return false; 3961db9ca37SKowalski, Kamil } 3971db9ca37SKowalski, Kamil 398179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 3991db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 400179db1d7SKowalski, Kamil 4014a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4024a0cb85cSEd Tanous // is not 100% number 4031abe55efSEd Tanous if (*endPtr != '\0') 4041abe55efSEd Tanous { 405179db1d7SKowalski, Kamil return false; 406179db1d7SKowalski, Kamil } 407179db1d7SKowalski, Kamil 408179db1d7SKowalski, Kamil // Value should be contained in byte 4091abe55efSEd Tanous if (value < 0 || value > 255) 4101abe55efSEd Tanous { 411179db1d7SKowalski, Kamil return false; 412179db1d7SKowalski, Kamil } 413179db1d7SKowalski, Kamil 4141abe55efSEd Tanous if (bits != nullptr) 4151abe55efSEd Tanous { 416179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4171abe55efSEd Tanous if (previousValue != 255 && value != 0) 4181abe55efSEd Tanous { 419179db1d7SKowalski, Kamil return false; 420179db1d7SKowalski, Kamil } 421179db1d7SKowalski, Kamil 422179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 423179db1d7SKowalski, Kamil firstZeroInByteHit = false; 424179db1d7SKowalski, Kamil 425179db1d7SKowalski, Kamil // Count bits 4261abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4271abe55efSEd Tanous { 4281abe55efSEd Tanous if (value & (1 << bitIdx)) 4291abe55efSEd Tanous { 4301abe55efSEd Tanous if (firstZeroInByteHit) 4311abe55efSEd Tanous { 432179db1d7SKowalski, Kamil // Continuity not preserved 433179db1d7SKowalski, Kamil return false; 4341abe55efSEd Tanous } 4351abe55efSEd Tanous else 4361abe55efSEd Tanous { 437179db1d7SKowalski, Kamil (*bits)++; 438179db1d7SKowalski, Kamil } 4391abe55efSEd Tanous } 4401abe55efSEd Tanous else 4411abe55efSEd Tanous { 442179db1d7SKowalski, Kamil firstZeroInByteHit = true; 443179db1d7SKowalski, Kamil } 444179db1d7SKowalski, Kamil } 445179db1d7SKowalski, Kamil } 446179db1d7SKowalski, Kamil 447179db1d7SKowalski, Kamil previousValue = value; 448179db1d7SKowalski, Kamil } 449179db1d7SKowalski, Kamil 450179db1d7SKowalski, Kamil return true; 451179db1d7SKowalski, Kamil } 452179db1d7SKowalski, Kamil 453179db1d7SKowalski, Kamil /** 454179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 455179db1d7SKowalski, Kamil * 456179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4574a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 458179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 459179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 460179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 461179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 462179db1d7SKowalski, Kamil * 463179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 464179db1d7SKowalski, Kamil * otherwise 465179db1d7SKowalski, Kamil */ 4664a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 4674a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 4684a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 4694a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4701abe55efSEd Tanous { 4714a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 4724a0cb85cSEd Tanous newValue{std::move(newValue)}]( 4731abe55efSEd Tanous const boost::system::error_code ec) { 4741abe55efSEd Tanous if (ec) 4751abe55efSEd Tanous { 476a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 4771abe55efSEd Tanous } 4781abe55efSEd Tanous else 4791abe55efSEd Tanous { 4804a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 481179db1d7SKowalski, Kamil } 482179db1d7SKowalski, Kamil }; 483179db1d7SKowalski, Kamil 48455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 485179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 486179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 487179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 488179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 489*abf2add6SEd Tanous std::variant<std::string>(newValue)); 4904a0cb85cSEd Tanous } 491179db1d7SKowalski, Kamil 492179db1d7SKowalski, Kamil /** 493179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 494179db1d7SKowalski, Kamil * 495179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4964a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 4971abe55efSEd Tanous * modified 498179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 499179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 500179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 501179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 502179db1d7SKowalski, Kamil * 503179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 504179db1d7SKowalski, Kamil * otherwise 505179db1d7SKowalski, Kamil */ 5064a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5071abe55efSEd Tanous const std::string &ipHash, 5081abe55efSEd Tanous const std::string &newValue, 509179db1d7SKowalski, Kamil const std::string &newValueDbus, 5104a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5111abe55efSEd Tanous { 5124a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5131abe55efSEd Tanous const boost::system::error_code ec) { 5141abe55efSEd Tanous if (ec) 5151abe55efSEd Tanous { 516a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5171abe55efSEd Tanous } 5181abe55efSEd Tanous else 5191abe55efSEd Tanous { 5204a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 521179db1d7SKowalski, Kamil newValue; 522179db1d7SKowalski, Kamil } 523179db1d7SKowalski, Kamil }; 524179db1d7SKowalski, Kamil 52555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 526179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 527179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 528179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 529179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 530*abf2add6SEd Tanous std::variant<std::string>(newValueDbus)); 5314a0cb85cSEd Tanous } 532179db1d7SKowalski, Kamil 533179db1d7SKowalski, Kamil /** 534179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 535179db1d7SKowalski, Kamil * 536179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5374a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5381abe55efSEd Tanous * modified 539179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 540179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 541179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 542179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 543179db1d7SKowalski, Kamil * 544179db1d7SKowalski, Kamil * @return None 545179db1d7SKowalski, Kamil */ 5464a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5474a0cb85cSEd Tanous const std::string &ipHash, 5484a0cb85cSEd Tanous const std::string &newValueStr, 5494a0cb85cSEd Tanous uint8_t &newValue, 5504a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5511abe55efSEd Tanous { 5524a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5531abe55efSEd Tanous const boost::system::error_code ec) { 5541abe55efSEd Tanous if (ec) 5551abe55efSEd Tanous { 556a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5571abe55efSEd Tanous } 5581abe55efSEd Tanous else 5591abe55efSEd Tanous { 56055c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 561179db1d7SKowalski, Kamil newValueStr; 562179db1d7SKowalski, Kamil } 563179db1d7SKowalski, Kamil }; 564179db1d7SKowalski, Kamil 56555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 566179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 567179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 568179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 569179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 570*abf2add6SEd Tanous std::variant<uint8_t>(newValue)); 5714a0cb85cSEd Tanous } 572588c3f0dSKowalski, Kamil 573588c3f0dSKowalski, Kamil /** 574179db1d7SKowalski, Kamil * @brief Deletes given IPv4 575179db1d7SKowalski, Kamil * 576179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 5774a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 578179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 579179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 580179db1d7SKowalski, Kamil * 581179db1d7SKowalski, Kamil * @return None 582179db1d7SKowalski, Kamil */ 5834a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 584179db1d7SKowalski, Kamil unsigned int ipIdx, 5854a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5861abe55efSEd Tanous { 58755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 5884a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 5891abe55efSEd Tanous if (ec) 5901abe55efSEd Tanous { 591a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5921abe55efSEd Tanous } 5931abe55efSEd Tanous else 5941abe55efSEd Tanous { 59555c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 596179db1d7SKowalski, Kamil } 597179db1d7SKowalski, Kamil }, 598179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 599179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 600179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 601179db1d7SKowalski, Kamil } 602179db1d7SKowalski, Kamil 603179db1d7SKowalski, Kamil /** 604179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 605179db1d7SKowalski, Kamil * 606179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6074a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 608179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 609179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 610179db1d7SKowalski, Kamil * 611179db1d7SKowalski, Kamil * @return None 612179db1d7SKowalski, Kamil */ 6134a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 614179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 615179db1d7SKowalski, Kamil const std::string &address, 6164a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6171abe55efSEd Tanous { 6184a0cb85cSEd Tanous auto createIpHandler = [ipIdx, 6194a0cb85cSEd Tanous asyncResp](const boost::system::error_code ec) { 6201abe55efSEd Tanous if (ec) 6211abe55efSEd Tanous { 622a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 623179db1d7SKowalski, Kamil } 624179db1d7SKowalski, Kamil }; 625179db1d7SKowalski, Kamil 62655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 627179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 628179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 629179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 630179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 631179db1d7SKowalski, Kamil gateway); 632179db1d7SKowalski, Kamil } 633179db1d7SKowalski, Kamil 634179db1d7SKowalski, Kamil /** 635179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 636179db1d7SKowalski, Kamil * Object 637179db1d7SKowalski, Kamil * from EntityManager Network Manager 6384a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 639179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 640179db1d7SKowalski, Kamil * into JSON 641179db1d7SKowalski, Kamil */ 642179db1d7SKowalski, Kamil template <typename CallbackFunc> 6434a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 6441abe55efSEd Tanous CallbackFunc &&callback) 6451abe55efSEd Tanous { 64655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6474a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 6481abe55efSEd Tanous const boost::system::error_code error_code, 6494a0cb85cSEd Tanous const GetManagedObjects &resp) { 65055c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 6514a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 652179db1d7SKowalski, Kamil 6531abe55efSEd Tanous if (error_code) 6541abe55efSEd Tanous { 65555c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 656179db1d7SKowalski, Kamil return; 657179db1d7SKowalski, Kamil } 658179db1d7SKowalski, Kamil 6594a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 6604a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 661179db1d7SKowalski, Kamil 662179db1d7SKowalski, Kamil // Fix global GW 6631abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 6641abe55efSEd Tanous { 6654a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 6664a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 6671abe55efSEd Tanous { 6684a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 669179db1d7SKowalski, Kamil } 670179db1d7SKowalski, Kamil } 671179db1d7SKowalski, Kamil 6724a0cb85cSEd Tanous // Finally make a callback with usefull data 67355c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 674179db1d7SKowalski, Kamil }, 675179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 676179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 677179db1d7SKowalski, Kamil }; 678179db1d7SKowalski, Kamil 679179db1d7SKowalski, Kamil /** 6809391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6819391bb9cSRapkiewicz, Pawel * Manager 6821abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 6831abe55efSEd Tanous * into JSON. 6849391bb9cSRapkiewicz, Pawel */ 6859391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 6861abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 6871abe55efSEd Tanous { 68855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6894a0cb85cSEd Tanous [callback{std::move(callback)}]( 6909391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 6914a0cb85cSEd Tanous GetManagedObjects &resp) { 6921abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 6931abe55efSEd Tanous // ethernet interfaces 6944a0cb85cSEd Tanous std::vector<std::string> iface_list; 6954a0cb85cSEd Tanous iface_list.reserve(resp.size()); 6961abe55efSEd Tanous if (error_code) 6971abe55efSEd Tanous { 6984a0cb85cSEd Tanous callback(false, iface_list); 6999391bb9cSRapkiewicz, Pawel return; 7009391bb9cSRapkiewicz, Pawel } 7019391bb9cSRapkiewicz, Pawel 7029391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7034a0cb85cSEd Tanous for (const auto &objpath : resp) 7041abe55efSEd Tanous { 7059391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7064a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7071abe55efSEd Tanous { 7081abe55efSEd Tanous // If interface is 7094a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 7104a0cb85cSEd Tanous // what we're looking for. 7119391bb9cSRapkiewicz, Pawel if (interface.first == 7121abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7131abe55efSEd Tanous { 7144a0cb85cSEd Tanous // Cut out everyting until last "/", ... 7154a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 7164a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 7174a0cb85cSEd Tanous if (last_pos != std::string::npos) 7181abe55efSEd Tanous { 7199391bb9cSRapkiewicz, Pawel // and put it into output vector. 7204a0cb85cSEd Tanous iface_list.emplace_back( 7214a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7229391bb9cSRapkiewicz, Pawel } 7239391bb9cSRapkiewicz, Pawel } 7249391bb9cSRapkiewicz, Pawel } 7259391bb9cSRapkiewicz, Pawel } 726a434f2bdSEd Tanous // Finally make a callback with useful data 7274a0cb85cSEd Tanous callback(true, iface_list); 7289391bb9cSRapkiewicz, Pawel }, 729aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 730aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7319391bb9cSRapkiewicz, Pawel }; 7329391bb9cSRapkiewicz, Pawel 7339391bb9cSRapkiewicz, Pawel /** 7349391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7359391bb9cSRapkiewicz, Pawel */ 7361abe55efSEd Tanous class EthernetCollection : public Node 7371abe55efSEd Tanous { 7389391bb9cSRapkiewicz, Pawel public: 7394a0cb85cSEd Tanous template <typename CrowApp> 7401abe55efSEd Tanous EthernetCollection(CrowApp &app) : 7414a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 7421abe55efSEd Tanous { 743588c3f0dSKowalski, Kamil entityPrivileges = { 744588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 745e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 746e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 747e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 748e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 749e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7509391bb9cSRapkiewicz, Pawel } 7519391bb9cSRapkiewicz, Pawel 7529391bb9cSRapkiewicz, Pawel private: 7539391bb9cSRapkiewicz, Pawel /** 7549391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7559391bb9cSRapkiewicz, Pawel */ 75655c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7571abe55efSEd Tanous const std::vector<std::string> ¶ms) override 7581abe55efSEd Tanous { 7590f74e643SEd Tanous res.jsonValue["@odata.type"] = 7600f74e643SEd Tanous "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7610f74e643SEd Tanous res.jsonValue["@odata.context"] = 7620f74e643SEd Tanous "/redfish/v1/" 7630f74e643SEd Tanous "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7640f74e643SEd Tanous res.jsonValue["@odata.id"] = 7650f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7660f74e643SEd Tanous res.jsonValue["Name"] = "Ethernet Network Interface Collection"; 7670f74e643SEd Tanous res.jsonValue["Description"] = 7680f74e643SEd Tanous "Collection of EthernetInterfaces for this Manager"; 7690f74e643SEd Tanous 7704a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 7711abe55efSEd Tanous // preparation 772f12894f8SJason M. Bills getEthernetIfaceList( 773f12894f8SJason M. Bills [&res](const bool &success, 7741abe55efSEd Tanous const std::vector<std::string> &iface_list) { 7754a0cb85cSEd Tanous if (!success) 7761abe55efSEd Tanous { 777f12894f8SJason M. Bills messages::internalError(res); 7784a0cb85cSEd Tanous res.end(); 7794a0cb85cSEd Tanous return; 7804a0cb85cSEd Tanous } 7814a0cb85cSEd Tanous 7824a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 7834a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 7844a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 7851abe55efSEd Tanous { 7864a0cb85cSEd Tanous iface_array.push_back( 7874a0cb85cSEd Tanous {{"@odata.id", 7884a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 7894a0cb85cSEd Tanous iface_item}}); 7909391bb9cSRapkiewicz, Pawel } 7914a0cb85cSEd Tanous 7924a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 7934a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 7944a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7959391bb9cSRapkiewicz, Pawel res.end(); 7969391bb9cSRapkiewicz, Pawel }); 7979391bb9cSRapkiewicz, Pawel } 7989391bb9cSRapkiewicz, Pawel }; 7999391bb9cSRapkiewicz, Pawel 8009391bb9cSRapkiewicz, Pawel /** 8019391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8029391bb9cSRapkiewicz, Pawel */ 8031abe55efSEd Tanous class EthernetInterface : public Node 8041abe55efSEd Tanous { 8059391bb9cSRapkiewicz, Pawel public: 8069391bb9cSRapkiewicz, Pawel /* 8079391bb9cSRapkiewicz, Pawel * Default Constructor 8089391bb9cSRapkiewicz, Pawel */ 8094a0cb85cSEd Tanous template <typename CrowApp> 8101abe55efSEd Tanous EthernetInterface(CrowApp &app) : 8114a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8121abe55efSEd Tanous std::string()) 8131abe55efSEd Tanous { 814588c3f0dSKowalski, Kamil entityPrivileges = { 815588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 816e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 817e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 818e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 819e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 820e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8219391bb9cSRapkiewicz, Pawel } 8229391bb9cSRapkiewicz, Pawel 823e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 8240627a2c7SEd Tanous static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable, 8250627a2c7SEd Tanous uint64_t vlanId, 8264a0cb85cSEd Tanous const EthernetInterfaceData ðData, 8274a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8281abe55efSEd Tanous { 8294a0cb85cSEd Tanous if (!ethData.vlan_id) 8301abe55efSEd Tanous { 831e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 832e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 833a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, "VLANEnable"); 834588c3f0dSKowalski, Kamil 835588c3f0dSKowalski, Kamil return; 836588c3f0dSKowalski, Kamil } 837588c3f0dSKowalski, Kamil 838588c3f0dSKowalski, Kamil // VLAN is configured on the interface 8390627a2c7SEd Tanous if (vlanEnable == true) 8401abe55efSEd Tanous { 841588c3f0dSKowalski, Kamil // Change VLAN Id 8420627a2c7SEd Tanous asyncResp->res.jsonValue["VLANId"] = vlanId; 8434a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 8441abe55efSEd Tanous if (ec) 8451abe55efSEd Tanous { 846f12894f8SJason M. Bills messages::internalError(asyncResp->res); 8471abe55efSEd Tanous } 8481abe55efSEd Tanous else 8491abe55efSEd Tanous { 8504a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 851e439f0f8SKowalski, Kamil } 8524a0cb85cSEd Tanous }; 8534a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 8544a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 8554a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 8564a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 8574a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 858*abf2add6SEd Tanous std::variant<uint32_t>(vlanId)); 8591abe55efSEd Tanous } 8604a0cb85cSEd Tanous else 8611abe55efSEd Tanous { 8624a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 8631abe55efSEd Tanous if (ec) 8641abe55efSEd Tanous { 865f12894f8SJason M. Bills messages::internalError(asyncResp->res); 8664a0cb85cSEd Tanous return; 8671abe55efSEd Tanous } 8684a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 8694a0cb85cSEd Tanous }; 8704a0cb85cSEd Tanous 8714a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 8724a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 8734a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 8744a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 875588c3f0dSKowalski, Kamil } 876588c3f0dSKowalski, Kamil } 877588c3f0dSKowalski, Kamil 878e439f0f8SKowalski, Kamil private: 879bc0bd6e0SEd Tanous void handleHostnamePatch(const std::string &hostname, 8804a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8811abe55efSEd Tanous { 882bc0bd6e0SEd Tanous asyncResp->res.jsonValue["HostName"] = hostname; 883bc0bd6e0SEd Tanous crow::connections::systemBus->async_method_call( 884bc0bd6e0SEd Tanous [asyncResp](const boost::system::error_code ec) { 8854a0cb85cSEd Tanous if (ec) 8864a0cb85cSEd Tanous { 887a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 8881abe55efSEd Tanous } 889bc0bd6e0SEd Tanous }, 890bc0bd6e0SEd Tanous "xyz.openbmc_project.Network", 891bc0bd6e0SEd Tanous "/xyz/openbmc_project/network/config", 892bc0bd6e0SEd Tanous "org.freedesktop.DBus.Properties", "Set", 893bc0bd6e0SEd Tanous "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 894*abf2add6SEd Tanous std::variant<std::string>(hostname)); 895588c3f0dSKowalski, Kamil } 896588c3f0dSKowalski, Kamil 8974a0cb85cSEd Tanous void handleIPv4Patch( 8984a0cb85cSEd Tanous const std::string &ifaceId, const nlohmann::json &input, 8994a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 9004a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9011abe55efSEd Tanous { 9021abe55efSEd Tanous if (!input.is_array()) 9031abe55efSEd Tanous { 904f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 905a08b46ccSJason M. Bills "IPv4Addresses"); 906179db1d7SKowalski, Kamil return; 907179db1d7SKowalski, Kamil } 908179db1d7SKowalski, Kamil 909179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 9104a0cb85cSEd Tanous if (input.size() < ipv4Data.size()) 9111abe55efSEd Tanous { 912a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, input.dump(), 913a08b46ccSJason M. Bills "IPv4Addresses"); 914179db1d7SKowalski, Kamil return; 915179db1d7SKowalski, Kamil } 916179db1d7SKowalski, Kamil 9174a0cb85cSEd Tanous int entryIdx = 0; 9184a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 9194a0cb85cSEd Tanous ipv4Data.begin(); 9204a0cb85cSEd Tanous for (const nlohmann::json &thisJson : input) 9211abe55efSEd Tanous { 9224a0cb85cSEd Tanous std::string pathString = 923a08b46ccSJason M. Bills "IPv4Addresses/" + std::to_string(entryIdx); 924179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 9254a0cb85cSEd Tanous if (!thisJson.is_object() && !thisJson.is_null()) 9261abe55efSEd Tanous { 927a08b46ccSJason M. Bills messages::propertyValueTypeError(asyncResp->res, 928a08b46ccSJason M. Bills thisJson.dump(), 929a08b46ccSJason M. Bills pathString + "/IPv4Address"); 930179db1d7SKowalski, Kamil 931179db1d7SKowalski, Kamil continue; 932179db1d7SKowalski, Kamil } 933179db1d7SKowalski, Kamil 9344a0cb85cSEd Tanous nlohmann::json::const_iterator addressFieldIt = 9354a0cb85cSEd Tanous thisJson.find("Address"); 9364a0cb85cSEd Tanous const std::string *addressField = nullptr; 9374a0cb85cSEd Tanous if (addressFieldIt != thisJson.end()) 9381abe55efSEd Tanous { 9394a0cb85cSEd Tanous addressField = addressFieldIt->get_ptr<const std::string *>(); 9404a0cb85cSEd Tanous if (addressField == nullptr) 9411abe55efSEd Tanous { 942a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, 943a08b46ccSJason M. Bills addressFieldIt->dump(), 9444a0cb85cSEd Tanous pathString + "/Address"); 945179db1d7SKowalski, Kamil continue; 946179db1d7SKowalski, Kamil } 9471abe55efSEd Tanous else 9481abe55efSEd Tanous { 9494a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*addressField)) 9504a0cb85cSEd Tanous { 951f12894f8SJason M. Bills messages::propertyValueFormatError( 952a08b46ccSJason M. Bills asyncResp->res, *addressField, 9534a0cb85cSEd Tanous pathString + "/Address"); 9544a0cb85cSEd Tanous continue; 9554a0cb85cSEd Tanous } 9564a0cb85cSEd Tanous } 9574a0cb85cSEd Tanous } 9584a0cb85cSEd Tanous 959a24526dcSEd Tanous std::optional<uint8_t> prefixLength; 9604a0cb85cSEd Tanous const std::string *subnetField = nullptr; 9614a0cb85cSEd Tanous nlohmann::json::const_iterator subnetFieldIt = 9624a0cb85cSEd Tanous thisJson.find("SubnetMask"); 9634a0cb85cSEd Tanous if (subnetFieldIt != thisJson.end()) 9644a0cb85cSEd Tanous { 9654a0cb85cSEd Tanous subnetField = subnetFieldIt->get_ptr<const std::string *>(); 9664a0cb85cSEd Tanous if (subnetField == nullptr) 9674a0cb85cSEd Tanous { 968f12894f8SJason M. Bills messages::propertyValueFormatError( 969a08b46ccSJason M. Bills asyncResp->res, *subnetField, 9704a0cb85cSEd Tanous pathString + "/SubnetMask"); 9714a0cb85cSEd Tanous continue; 9724a0cb85cSEd Tanous } 9734a0cb85cSEd Tanous else 9744a0cb85cSEd Tanous { 9754a0cb85cSEd Tanous prefixLength = 0; 9764a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetField, 9774a0cb85cSEd Tanous &*prefixLength)) 9784a0cb85cSEd Tanous { 979f12894f8SJason M. Bills messages::propertyValueFormatError( 980a08b46ccSJason M. Bills asyncResp->res, *subnetField, 9814a0cb85cSEd Tanous pathString + "/SubnetMask"); 9824a0cb85cSEd Tanous continue; 9834a0cb85cSEd Tanous } 9844a0cb85cSEd Tanous } 9854a0cb85cSEd Tanous } 9864a0cb85cSEd Tanous 9874a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 9884a0cb85cSEd Tanous const std::string *addressOriginField = nullptr; 9894a0cb85cSEd Tanous nlohmann::json::const_iterator addressOriginFieldIt = 9904a0cb85cSEd Tanous thisJson.find("AddressOrigin"); 9914a0cb85cSEd Tanous if (addressOriginFieldIt != thisJson.end()) 9924a0cb85cSEd Tanous { 9934a0cb85cSEd Tanous const std::string *addressOriginField = 9944a0cb85cSEd Tanous addressOriginFieldIt->get_ptr<const std::string *>(); 9954a0cb85cSEd Tanous if (addressOriginField == nullptr) 9964a0cb85cSEd Tanous { 997f12894f8SJason M. Bills messages::propertyValueFormatError( 998a08b46ccSJason M. Bills asyncResp->res, *addressOriginField, 9994a0cb85cSEd Tanous pathString + "/AddressOrigin"); 10004a0cb85cSEd Tanous continue; 10014a0cb85cSEd Tanous } 10024a0cb85cSEd Tanous else 10034a0cb85cSEd Tanous { 10044a0cb85cSEd Tanous // Get Address origin in proper format 10054a0cb85cSEd Tanous addressOriginInDBusFormat = 10064a0cb85cSEd Tanous translateAddressOriginRedfishToDbus( 10074a0cb85cSEd Tanous *addressOriginField); 10084a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 10094a0cb85cSEd Tanous { 10104a0cb85cSEd Tanous messages::propertyValueNotInList( 1011f12894f8SJason M. Bills asyncResp->res, *addressOriginField, 1012a08b46ccSJason M. Bills pathString + "/AddressOrigin"); 10134a0cb85cSEd Tanous continue; 10144a0cb85cSEd Tanous } 10154a0cb85cSEd Tanous } 10164a0cb85cSEd Tanous } 10174a0cb85cSEd Tanous 10184a0cb85cSEd Tanous nlohmann::json::const_iterator gatewayFieldIt = 10194a0cb85cSEd Tanous thisJson.find("Gateway"); 10204a0cb85cSEd Tanous const std::string *gatewayField = nullptr; 10214a0cb85cSEd Tanous if (gatewayFieldIt != thisJson.end()) 10224a0cb85cSEd Tanous { 10234a0cb85cSEd Tanous const std::string *gatewayField = 10244a0cb85cSEd Tanous gatewayFieldIt->get_ptr<const std::string *>(); 10254a0cb85cSEd Tanous if (gatewayField == nullptr || 10264a0cb85cSEd Tanous !ipv4VerifyIpAndGetBitcount(*gatewayField)) 10274a0cb85cSEd Tanous { 1028a08b46ccSJason M. Bills messages::propertyValueFormatError( 1029a08b46ccSJason M. Bills asyncResp->res, *gatewayField, pathString + "/Gateway"); 10304a0cb85cSEd Tanous continue; 10314a0cb85cSEd Tanous } 10324a0cb85cSEd Tanous } 10334a0cb85cSEd Tanous 10344a0cb85cSEd Tanous // if a vlan already exists, modify the existing 10354a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 10364a0cb85cSEd Tanous { 10371abe55efSEd Tanous // Existing object that should be modified/deleted/remain 10381abe55efSEd Tanous // unchanged 10394a0cb85cSEd Tanous if (thisJson.is_null()) 10401abe55efSEd Tanous { 10414a0cb85cSEd Tanous auto callback = [entryIdx{std::to_string(entryIdx)}, 10424a0cb85cSEd Tanous asyncResp]( 10434a0cb85cSEd Tanous const boost::system::error_code ec) { 10444a0cb85cSEd Tanous if (ec) 10454a0cb85cSEd Tanous { 1046a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 10474a0cb85cSEd Tanous return; 10481abe55efSEd Tanous } 10494a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 10504a0cb85cSEd Tanous nullptr; 10514a0cb85cSEd Tanous }; 10524a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 10534a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 10544a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 10554a0cb85cSEd Tanous thisData->id, 10564a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 1057179db1d7SKowalski, Kamil } 10584a0cb85cSEd Tanous else if (thisJson.is_object()) 10594a0cb85cSEd Tanous { 1060179db1d7SKowalski, Kamil // Apply changes 10614a0cb85cSEd Tanous if (addressField != nullptr) 10621abe55efSEd Tanous { 10634a0cb85cSEd Tanous auto callback = 10644a0cb85cSEd Tanous [asyncResp, entryIdx, 10654a0cb85cSEd Tanous addressField{std::string(*addressField)}]( 10664a0cb85cSEd Tanous const boost::system::error_code ec) { 10674a0cb85cSEd Tanous if (ec) 10681abe55efSEd Tanous { 1069a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 10704a0cb85cSEd Tanous return; 10714a0cb85cSEd Tanous } 10724a0cb85cSEd Tanous asyncResp->res 10734a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 10744a0cb85cSEd Tanous entryIdx)]["Address"] = addressField; 10754a0cb85cSEd Tanous }; 10764a0cb85cSEd Tanous 10774a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 10784a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 10794a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 10804a0cb85cSEd Tanous "/ipv4/" + thisData->id, 10814a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 10824a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 1083*abf2add6SEd Tanous std::variant<std::string>(*addressField)); 1084179db1d7SKowalski, Kamil } 1085179db1d7SKowalski, Kamil 10864a0cb85cSEd Tanous if (prefixLength && subnetField != nullptr) 10871abe55efSEd Tanous { 10884a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 10894a0cb85cSEd Tanous thisData->id, *subnetField, 10904a0cb85cSEd Tanous *prefixLength, asyncResp); 1091179db1d7SKowalski, Kamil } 1092179db1d7SKowalski, Kamil 10934a0cb85cSEd Tanous if (!addressOriginInDBusFormat.empty() && 10944a0cb85cSEd Tanous addressOriginField != nullptr) 10951abe55efSEd Tanous { 10964a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 10974a0cb85cSEd Tanous *addressOriginField, 10984a0cb85cSEd Tanous addressOriginInDBusFormat, asyncResp); 1099179db1d7SKowalski, Kamil } 1100179db1d7SKowalski, Kamil 11014a0cb85cSEd Tanous if (gatewayField != nullptr) 11021abe55efSEd Tanous { 11034a0cb85cSEd Tanous auto callback = 11044a0cb85cSEd Tanous [asyncResp, entryIdx, 11054a0cb85cSEd Tanous gatewayField{std::string(*gatewayField)}]( 11064a0cb85cSEd Tanous const boost::system::error_code ec) { 11074a0cb85cSEd Tanous if (ec) 11081abe55efSEd Tanous { 1109a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11104a0cb85cSEd Tanous return; 11114a0cb85cSEd Tanous } 11124a0cb85cSEd Tanous asyncResp->res 11134a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 11144a0cb85cSEd Tanous entryIdx)]["Gateway"] = 11154a0cb85cSEd Tanous std::move(gatewayField); 11164a0cb85cSEd Tanous }; 11174a0cb85cSEd Tanous 11184a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11194a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11204a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 11214a0cb85cSEd Tanous "/ipv4/" + thisData->id, 11224a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11234a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 1124*abf2add6SEd Tanous std::variant<std::string>(*gatewayField)); 11254a0cb85cSEd Tanous } 11264a0cb85cSEd Tanous } 11274a0cb85cSEd Tanous thisData++; 11281abe55efSEd Tanous } 11291abe55efSEd Tanous else 11301abe55efSEd Tanous { 11314a0cb85cSEd Tanous // Create IPv4 with provided data 11324a0cb85cSEd Tanous if (gatewayField == nullptr) 11331abe55efSEd Tanous { 1134a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11354a0cb85cSEd Tanous pathString + "/Gateway"); 11364a0cb85cSEd Tanous continue; 11374a0cb85cSEd Tanous } 11384a0cb85cSEd Tanous 11394a0cb85cSEd Tanous if (addressField == nullptr) 11401abe55efSEd Tanous { 1141a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11424a0cb85cSEd Tanous pathString + "/Address"); 11434a0cb85cSEd Tanous continue; 11444a0cb85cSEd Tanous } 11454a0cb85cSEd Tanous 11464a0cb85cSEd Tanous if (!prefixLength) 11471abe55efSEd Tanous { 1148a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11494a0cb85cSEd Tanous pathString + "/SubnetMask"); 11504a0cb85cSEd Tanous continue; 1151588c3f0dSKowalski, Kamil } 1152588c3f0dSKowalski, Kamil 11534a0cb85cSEd Tanous createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField, 11544a0cb85cSEd Tanous *addressField, asyncResp); 11554a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 11564a0cb85cSEd Tanous } 11574a0cb85cSEd Tanous entryIdx++; 11584a0cb85cSEd Tanous } 11594a0cb85cSEd Tanous } 11604a0cb85cSEd Tanous 11610f74e643SEd Tanous void parseInterfaceData( 11620f74e643SEd Tanous nlohmann::json &json_response, const std::string &iface_id, 11630f74e643SEd Tanous const EthernetInterfaceData ðData, 11644a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 11654a0cb85cSEd Tanous { 11664a0cb85cSEd Tanous json_response["Id"] = iface_id; 11674a0cb85cSEd Tanous json_response["@odata.id"] = 11684a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 11694a0cb85cSEd Tanous 11704a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 11714a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 11724a0cb85cSEd Tanous if (!ethData.hostname.empty()) 11734a0cb85cSEd Tanous { 11744a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 11754a0cb85cSEd Tanous } 11764a0cb85cSEd Tanous 11774a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 11784a0cb85cSEd Tanous if (ethData.vlan_id) 11794a0cb85cSEd Tanous { 11804a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 11814a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 11824a0cb85cSEd Tanous } 11834a0cb85cSEd Tanous else 11844a0cb85cSEd Tanous { 11854a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 11864a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 11874a0cb85cSEd Tanous } 11884a0cb85cSEd Tanous 11894a0cb85cSEd Tanous if (ipv4Data.size() > 0) 11904a0cb85cSEd Tanous { 11914a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 11924a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 11934a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 11944a0cb85cSEd Tanous { 11954a0cb85cSEd Tanous if (!ipv4_config.address.empty()) 11964a0cb85cSEd Tanous { 11974a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 11984a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 11994a0cb85cSEd Tanous {"Address", ipv4_config.address}}); 12004a0cb85cSEd Tanous 12014a0cb85cSEd Tanous if (!ipv4_config.gateway.empty()) 12024a0cb85cSEd Tanous { 12034a0cb85cSEd Tanous ipv4_array.back()["Gateway"] = ipv4_config.gateway; 12044a0cb85cSEd Tanous } 12054a0cb85cSEd Tanous } 12064a0cb85cSEd Tanous } 12074a0cb85cSEd Tanous } 1208588c3f0dSKowalski, Kamil } 1209588c3f0dSKowalski, Kamil 12109391bb9cSRapkiewicz, Pawel /** 12119391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12129391bb9cSRapkiewicz, Pawel */ 121355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12141abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12151abe55efSEd Tanous { 12164a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12171abe55efSEd Tanous if (params.size() != 1) 12181abe55efSEd Tanous { 1219f12894f8SJason M. Bills messages::internalError(asyncResp->res); 12209391bb9cSRapkiewicz, Pawel return; 12219391bb9cSRapkiewicz, Pawel } 12229391bb9cSRapkiewicz, Pawel 12234a0cb85cSEd Tanous getEthernetIfaceData( 12244a0cb85cSEd Tanous params[0], 12254a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 12264a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 12274a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 12284a0cb85cSEd Tanous if (!success) 12291abe55efSEd Tanous { 12301abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 12311abe55efSEd Tanous // object, and other errors 1232f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1233f12894f8SJason M. Bills "EthernetInterface", iface_id); 12344a0cb85cSEd Tanous return; 12359391bb9cSRapkiewicz, Pawel } 12360f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 12370f74e643SEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 12380f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 12390f74e643SEd Tanous "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 12400f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; 12410f74e643SEd Tanous asyncResp->res.jsonValue["Description"] = 12420f74e643SEd Tanous "Management Network Interface"; 12430f74e643SEd Tanous 12440f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 12450f74e643SEd Tanous ipv4Data); 12469391bb9cSRapkiewicz, Pawel }); 12479391bb9cSRapkiewicz, Pawel } 12489391bb9cSRapkiewicz, Pawel 124955c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 12501abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12511abe55efSEd Tanous { 12524a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12531abe55efSEd Tanous if (params.size() != 1) 12541abe55efSEd Tanous { 1255f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1256588c3f0dSKowalski, Kamil return; 1257588c3f0dSKowalski, Kamil } 1258588c3f0dSKowalski, Kamil 12594a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1260588c3f0dSKowalski, Kamil 12610627a2c7SEd Tanous std::optional<nlohmann::json> vlan; 1262bc0bd6e0SEd Tanous std::optional<std::string> hostname; 12630627a2c7SEd Tanous std::optional<nlohmann::json> ipv4Addresses; 12640627a2c7SEd Tanous std::optional<nlohmann::json> ipv6Addresses; 12650627a2c7SEd Tanous 12660627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname, 12670627a2c7SEd Tanous "IPv4Addresses", ipv4Addresses, 12680627a2c7SEd Tanous "IPv6Addresses", ipv6Addresses)) 12691abe55efSEd Tanous { 1270588c3f0dSKowalski, Kamil return; 1271588c3f0dSKowalski, Kamil } 12720627a2c7SEd Tanous std::optional<uint64_t> vlanId = 0; 12730627a2c7SEd Tanous std::optional<bool> vlanEnable = false; 12740627a2c7SEd Tanous if (vlan) 12750627a2c7SEd Tanous { 12760627a2c7SEd Tanous if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable, 12770627a2c7SEd Tanous "VLANId", vlanId)) 12780627a2c7SEd Tanous { 12790627a2c7SEd Tanous return; 12800627a2c7SEd Tanous } 12810627a2c7SEd Tanous // Need both vlanId and vlanEnable to service this request 12820627a2c7SEd Tanous if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable)) 12830627a2c7SEd Tanous { 12840627a2c7SEd Tanous if (vlanId) 12850627a2c7SEd Tanous { 12860627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANEnable"); 12870627a2c7SEd Tanous } 12880627a2c7SEd Tanous else 12890627a2c7SEd Tanous { 12900627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANId"); 12910627a2c7SEd Tanous } 12920627a2c7SEd Tanous 12930627a2c7SEd Tanous return; 12940627a2c7SEd Tanous } 12950627a2c7SEd Tanous } 1296588c3f0dSKowalski, Kamil 12974a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1298588c3f0dSKowalski, Kamil // preparation 12994a0cb85cSEd Tanous getEthernetIfaceData( 13004a0cb85cSEd Tanous iface_id, 13010627a2c7SEd Tanous [this, asyncResp, iface_id, vlanId, vlanEnable, 13020627a2c7SEd Tanous hostname = std::move(hostname), 13030627a2c7SEd Tanous ipv4Addresses = std::move(ipv4Addresses), 13040627a2c7SEd Tanous ipv6Addresses = std::move(ipv6Addresses)]( 13054a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13064a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13071abe55efSEd Tanous if (!success) 13081abe55efSEd Tanous { 1309588c3f0dSKowalski, Kamil // ... otherwise return error 13101abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13111abe55efSEd Tanous // object, and other errors 1312f12894f8SJason M. Bills messages::resourceNotFound( 1313f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1314588c3f0dSKowalski, Kamil return; 1315588c3f0dSKowalski, Kamil } 1316588c3f0dSKowalski, Kamil 13170f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13180f74e643SEd Tanous ipv4Data); 1319588c3f0dSKowalski, Kamil 13200627a2c7SEd Tanous if (vlanId && vlanEnable) 13211abe55efSEd Tanous { 13220627a2c7SEd Tanous handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData, 13234a0cb85cSEd Tanous asyncResp); 13241abe55efSEd Tanous } 13250627a2c7SEd Tanous 13260627a2c7SEd Tanous if (hostname) 13271abe55efSEd Tanous { 13280627a2c7SEd Tanous handleHostnamePatch(*hostname, asyncResp); 13291abe55efSEd Tanous } 13300627a2c7SEd Tanous 13310627a2c7SEd Tanous if (ipv4Addresses) 13321abe55efSEd Tanous { 13330627a2c7SEd Tanous handleIPv4Patch(iface_id, *ipv4Addresses, ipv4Data, 1334179db1d7SKowalski, Kamil asyncResp); 13351abe55efSEd Tanous } 13360627a2c7SEd Tanous 13370627a2c7SEd Tanous if (ipv6Addresses) 13381abe55efSEd Tanous { 1339179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1340a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, 13410627a2c7SEd Tanous "IPv6Addresses"); 1342588c3f0dSKowalski, Kamil } 1343588c3f0dSKowalski, Kamil }); 1344588c3f0dSKowalski, Kamil } 13459391bb9cSRapkiewicz, Pawel }; 13469391bb9cSRapkiewicz, Pawel 1347e439f0f8SKowalski, Kamil /** 13484a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 13494a0cb85cSEd Tanous * Schema 1350e439f0f8SKowalski, Kamil */ 13511abe55efSEd Tanous class VlanNetworkInterface : public Node 13521abe55efSEd Tanous { 1353e439f0f8SKowalski, Kamil public: 1354e439f0f8SKowalski, Kamil /* 1355e439f0f8SKowalski, Kamil * Default Constructor 1356e439f0f8SKowalski, Kamil */ 1357e439f0f8SKowalski, Kamil template <typename CrowApp> 13581abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 13594a0cb85cSEd Tanous Node(app, 13600f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>", 13611abe55efSEd Tanous std::string(), std::string()) 13621abe55efSEd Tanous { 1363e439f0f8SKowalski, Kamil entityPrivileges = { 1364e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1365e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1366e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1367e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1368e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1369e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1370e439f0f8SKowalski, Kamil } 1371e439f0f8SKowalski, Kamil 1372e439f0f8SKowalski, Kamil private: 13730f74e643SEd Tanous void parseInterfaceData( 13740f74e643SEd Tanous nlohmann::json &json_response, const std::string &parent_iface_id, 13750f74e643SEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 13764a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 13771abe55efSEd Tanous { 1378e439f0f8SKowalski, Kamil // Fill out obvious data... 13794a0cb85cSEd Tanous json_response["Id"] = iface_id; 13804a0cb85cSEd Tanous json_response["@odata.id"] = 13814a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 13824a0cb85cSEd Tanous "/VLANs/" + iface_id; 1383e439f0f8SKowalski, Kamil 13844a0cb85cSEd Tanous json_response["VLANEnable"] = true; 13854a0cb85cSEd Tanous if (ethData.vlan_id) 13864a0cb85cSEd Tanous { 13874a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 13884a0cb85cSEd Tanous } 1389e439f0f8SKowalski, Kamil } 1390e439f0f8SKowalski, Kamil 139155c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 13921abe55efSEd Tanous const std::string &iface) 13931abe55efSEd Tanous { 1394f12894f8SJason M. Bills std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13951abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 13961abe55efSEd Tanous { 1397f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1398f12894f8SJason M. Bills iface); 1399927a505aSKowalski, Kamil return false; 14001abe55efSEd Tanous } 14011abe55efSEd Tanous else 14021abe55efSEd Tanous { 1403927a505aSKowalski, Kamil return true; 1404927a505aSKowalski, Kamil } 1405927a505aSKowalski, Kamil } 1406927a505aSKowalski, Kamil 1407e439f0f8SKowalski, Kamil /** 1408e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1409e439f0f8SKowalski, Kamil */ 141055c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 14111abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14121abe55efSEd Tanous { 14134a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14144a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1415e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1416e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1417e439f0f8SKowalski, Kamil // impossible. 14181abe55efSEd Tanous if (params.size() != 2) 14191abe55efSEd Tanous { 1420f12894f8SJason M. Bills messages::internalError(res); 1421e439f0f8SKowalski, Kamil res.end(); 1422e439f0f8SKowalski, Kamil return; 1423e439f0f8SKowalski, Kamil } 1424e439f0f8SKowalski, Kamil 14254a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 14264a0cb85cSEd Tanous const std::string &iface_id = params[1]; 14270f74e643SEd Tanous res.jsonValue["@odata.type"] = 14280f74e643SEd Tanous "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 14290f74e643SEd Tanous res.jsonValue["@odata.context"] = 14300f74e643SEd Tanous "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 14310f74e643SEd Tanous res.jsonValue["Name"] = "VLAN Network Interface"; 1432e439f0f8SKowalski, Kamil 14334a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 14341abe55efSEd Tanous { 1435a434f2bdSEd Tanous return; 1436a434f2bdSEd Tanous } 1437a434f2bdSEd Tanous 1438e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1439e439f0f8SKowalski, Kamil // preparation 14404a0cb85cSEd Tanous getEthernetIfaceData( 14414a0cb85cSEd Tanous iface_id, 14424a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 14434a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 14444a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 14454a0cb85cSEd Tanous if (success && ethData.vlan_id) 14461abe55efSEd Tanous { 14470f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, 14480f74e643SEd Tanous parent_iface_id, iface_id, ethData, 14490f74e643SEd Tanous ipv4Data); 14501abe55efSEd Tanous } 14511abe55efSEd Tanous else 14521abe55efSEd Tanous { 1453e439f0f8SKowalski, Kamil // ... otherwise return error 14541abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 14551abe55efSEd Tanous // object, and other errors 1456f12894f8SJason M. Bills messages::resourceNotFound( 1457f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1458e439f0f8SKowalski, Kamil } 1459e439f0f8SKowalski, Kamil }); 1460e439f0f8SKowalski, Kamil } 1461e439f0f8SKowalski, Kamil 146255c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 14631abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14641abe55efSEd Tanous { 14654a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14661abe55efSEd Tanous if (params.size() != 2) 14671abe55efSEd Tanous { 1468f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1469e439f0f8SKowalski, Kamil return; 1470e439f0f8SKowalski, Kamil } 1471e439f0f8SKowalski, Kamil 1472d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 147355c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1474927a505aSKowalski, Kamil 14751abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 14761abe55efSEd Tanous { 1477927a505aSKowalski, Kamil return; 1478927a505aSKowalski, Kamil } 1479927a505aSKowalski, Kamil 14800627a2c7SEd Tanous bool vlanEnable = false; 14810627a2c7SEd Tanous uint64_t vlanId = 0; 14820627a2c7SEd Tanous 14830627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId", 14840627a2c7SEd Tanous vlanId)) 14851abe55efSEd Tanous { 1486927a505aSKowalski, Kamil return; 1487927a505aSKowalski, Kamil } 1488927a505aSKowalski, Kamil 1489927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1490927a505aSKowalski, Kamil // preparation 14914a0cb85cSEd Tanous getEthernetIfaceData( 14921abe55efSEd Tanous ifaceId, 14930627a2c7SEd Tanous [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId]( 14944a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 14954a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 14961abe55efSEd Tanous if (!success) 14971abe55efSEd Tanous { 14981abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 14991abe55efSEd Tanous // object, and other errors 1500f12894f8SJason M. Bills messages::resourceNotFound( 1501f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1502927a505aSKowalski, Kamil 1503927a505aSKowalski, Kamil return; 1504927a505aSKowalski, Kamil } 1505927a505aSKowalski, Kamil 15060f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15070f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1508927a505aSKowalski, Kamil 15090627a2c7SEd Tanous EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable, 15100627a2c7SEd Tanous ethData, asyncResp); 1511927a505aSKowalski, Kamil }); 1512e439f0f8SKowalski, Kamil } 1513e439f0f8SKowalski, Kamil 151455c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 15151abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15161abe55efSEd Tanous { 15174a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15181abe55efSEd Tanous if (params.size() != 2) 15191abe55efSEd Tanous { 1520f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1521e439f0f8SKowalski, Kamil return; 1522e439f0f8SKowalski, Kamil } 1523e439f0f8SKowalski, Kamil 1524d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 152555c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1526927a505aSKowalski, Kamil 15274a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 15281abe55efSEd Tanous { 1529927a505aSKowalski, Kamil return; 1530927a505aSKowalski, Kamil } 1531927a505aSKowalski, Kamil 1532927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1533927a505aSKowalski, Kamil // preparation 1534f12894f8SJason M. Bills getEthernetIfaceData( 1535f12894f8SJason M. Bills ifaceId, 1536f12894f8SJason M. Bills [this, asyncResp, parentIfaceId{std::string(parentIfaceId)}, 15374a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1538f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1539f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15404a0cb85cSEd Tanous if (success && ethData.vlan_id) 15411abe55efSEd Tanous { 15420f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15430f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1544927a505aSKowalski, Kamil 1545f12894f8SJason M. Bills auto callback = 1546f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 15471abe55efSEd Tanous if (ec) 15481abe55efSEd Tanous { 1549f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1550927a505aSKowalski, Kamil } 15514a0cb85cSEd Tanous }; 15524a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 15534a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 15544a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 15554a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 15561abe55efSEd Tanous } 15571abe55efSEd Tanous else 15581abe55efSEd Tanous { 1559927a505aSKowalski, Kamil // ... otherwise return error 1560f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1561f12894f8SJason M. Bills // object, and other errors 1562f12894f8SJason M. Bills messages::resourceNotFound( 1563f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1564927a505aSKowalski, Kamil } 1565927a505aSKowalski, Kamil }); 1566e439f0f8SKowalski, Kamil } 1567e439f0f8SKowalski, Kamil }; 1568e439f0f8SKowalski, Kamil 1569e439f0f8SKowalski, Kamil /** 1570e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1571e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1572e439f0f8SKowalski, Kamil */ 15731abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 15741abe55efSEd Tanous { 1575e439f0f8SKowalski, Kamil public: 1576e439f0f8SKowalski, Kamil template <typename CrowApp> 15771abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 15784a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 15794a0cb85cSEd Tanous std::string()) 15801abe55efSEd Tanous { 1581e439f0f8SKowalski, Kamil entityPrivileges = { 1582e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1583e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1584e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1585e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1586e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1587e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1588e439f0f8SKowalski, Kamil } 1589e439f0f8SKowalski, Kamil 1590e439f0f8SKowalski, Kamil private: 1591e439f0f8SKowalski, Kamil /** 1592e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1593e439f0f8SKowalski, Kamil */ 159455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 15951abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15961abe55efSEd Tanous { 15974a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15981abe55efSEd Tanous if (params.size() != 1) 15991abe55efSEd Tanous { 1600e439f0f8SKowalski, Kamil // This means there is a problem with the router 1601f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1602e439f0f8SKowalski, Kamil return; 1603e439f0f8SKowalski, Kamil } 1604e439f0f8SKowalski, Kamil 16054a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1606e439f0f8SKowalski, Kamil 16074a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 16081abe55efSEd Tanous // preparation 1609f12894f8SJason M. Bills getEthernetIfaceList( 1610f12894f8SJason M. Bills [this, asyncResp, 1611f12894f8SJason M. Bills rootInterfaceName{std::string(rootInterfaceName)}]( 16121abe55efSEd Tanous const bool &success, 16131abe55efSEd Tanous const std::vector<std::string> &iface_list) { 16144a0cb85cSEd Tanous if (!success) 16151abe55efSEd Tanous { 1616f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16174a0cb85cSEd Tanous return; 16181abe55efSEd Tanous } 16190f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 16200f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 16210f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 16220f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 16230f74e643SEd Tanous "/redfish/v1/$metadata" 16240f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 16250f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 16260f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = 16270f74e643SEd Tanous "VLAN Network Interface Collection"; 16284a0cb85cSEd Tanous 16294a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 16304a0cb85cSEd Tanous 16314a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 16321abe55efSEd Tanous { 16334a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 16344a0cb85cSEd Tanous { 16354a0cb85cSEd Tanous iface_array.push_back( 16364a0cb85cSEd Tanous {{"@odata.id", 16374a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 16384a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1639e439f0f8SKowalski, Kamil } 1640e439f0f8SKowalski, Kamil } 1641e439f0f8SKowalski, Kamil 16424a0cb85cSEd Tanous if (iface_array.empty()) 16431abe55efSEd Tanous { 1644f12894f8SJason M. Bills messages::resourceNotFound( 1645f12894f8SJason M. Bills asyncResp->res, "EthernetInterface", rootInterfaceName); 16464a0cb85cSEd Tanous return; 1647e439f0f8SKowalski, Kamil } 16484a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 16494a0cb85cSEd Tanous iface_array.size(); 16504a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 16514a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 16524a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 16534a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1654e439f0f8SKowalski, Kamil }); 1655e439f0f8SKowalski, Kamil } 1656e439f0f8SKowalski, Kamil 165755c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 16581abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16591abe55efSEd Tanous { 16604a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16611abe55efSEd Tanous if (params.size() != 1) 16621abe55efSEd Tanous { 1663f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1664e439f0f8SKowalski, Kamil return; 1665e439f0f8SKowalski, Kamil } 1666e439f0f8SKowalski, Kamil 16670627a2c7SEd Tanous uint32_t vlanId = 0; 16680627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANId", vlanId)) 16691abe55efSEd Tanous { 16704a0cb85cSEd Tanous return; 1671e439f0f8SKowalski, Kamil } 16724a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 16734a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 16741abe55efSEd Tanous if (ec) 16751abe55efSEd Tanous { 16764a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 16774a0cb85cSEd Tanous // phosphor-network responses 1678f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16794a0cb85cSEd Tanous return; 16801abe55efSEd Tanous } 1681f12894f8SJason M. Bills messages::created(asyncResp->res); 1682e439f0f8SKowalski, Kamil }; 16834a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 16844a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 16854a0cb85cSEd Tanous "/xyz/openbmc_project/network", 16864a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 16870627a2c7SEd Tanous rootInterfaceName, vlanId); 16884a0cb85cSEd Tanous } 16894a0cb85cSEd Tanous }; 16909391bb9cSRapkiewicz, Pawel } // namespace redfish 1691