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> 25abf2add6SEd 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< 35abf2add6SEd 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*029573d4SEd Tanous std::string, sdbusplus::message::variant< 44*029573d4SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 45*029573d4SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double, 46*029573d4SEd Tanous std::vector<std::string>>>>>>>; 474a0cb85cSEd Tanous 484a0cb85cSEd Tanous enum class LinkType 494a0cb85cSEd Tanous { 504a0cb85cSEd Tanous Local, 514a0cb85cSEd Tanous Global 524a0cb85cSEd Tanous }; 539391bb9cSRapkiewicz, Pawel 549391bb9cSRapkiewicz, Pawel /** 559391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 569391bb9cSRapkiewicz, Pawel */ 571abe55efSEd Tanous struct IPv4AddressData 581abe55efSEd Tanous { 59179db1d7SKowalski, Kamil std::string id; 604a0cb85cSEd Tanous std::string address; 614a0cb85cSEd Tanous std::string domain; 624a0cb85cSEd Tanous std::string gateway; 639391bb9cSRapkiewicz, Pawel std::string netmask; 649391bb9cSRapkiewicz, Pawel std::string origin; 654a0cb85cSEd Tanous LinkType linktype; 664a0cb85cSEd Tanous 671abe55efSEd Tanous bool operator<(const IPv4AddressData &obj) const 681abe55efSEd Tanous { 694a0cb85cSEd Tanous return id < obj.id; 701abe55efSEd Tanous } 719391bb9cSRapkiewicz, Pawel }; 729391bb9cSRapkiewicz, Pawel 739391bb9cSRapkiewicz, Pawel /** 749391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 759391bb9cSRapkiewicz, Pawel * available from DBus 769391bb9cSRapkiewicz, Pawel */ 771abe55efSEd Tanous struct EthernetInterfaceData 781abe55efSEd Tanous { 794a0cb85cSEd Tanous uint32_t speed; 804a0cb85cSEd Tanous bool auto_neg; 814a0cb85cSEd Tanous std::string hostname; 824a0cb85cSEd Tanous std::string default_gateway; 834a0cb85cSEd Tanous std::string mac_address; 84a24526dcSEd Tanous std::optional<uint32_t> vlan_id; 85*029573d4SEd Tanous std::vector<std::string> nameservers; 869391bb9cSRapkiewicz, Pawel }; 879391bb9cSRapkiewicz, Pawel 889391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 899391bb9cSRapkiewicz, Pawel // into full dot notation 901abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 911abe55efSEd Tanous { 929391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 939391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 949391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 959391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 969391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 979391bb9cSRapkiewicz, Pawel return netmask; 989391bb9cSRapkiewicz, Pawel } 999391bb9cSRapkiewicz, Pawel 1004a0cb85cSEd Tanous inline std::string 1014a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(const std::string &inputOrigin, 1024a0cb85cSEd Tanous bool isIPv4) 1031abe55efSEd Tanous { 1044a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 1051abe55efSEd Tanous { 1064a0cb85cSEd Tanous return "Static"; 1079391bb9cSRapkiewicz, Pawel } 1084a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal") 1091abe55efSEd Tanous { 1104a0cb85cSEd Tanous if (isIPv4) 1111abe55efSEd Tanous { 1124a0cb85cSEd Tanous return "IPv4LinkLocal"; 1131abe55efSEd Tanous } 1141abe55efSEd Tanous else 1151abe55efSEd Tanous { 1164a0cb85cSEd Tanous return "LinkLocal"; 1179391bb9cSRapkiewicz, Pawel } 1189391bb9cSRapkiewicz, Pawel } 1194a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1201abe55efSEd Tanous { 1214a0cb85cSEd Tanous if (isIPv4) 1224a0cb85cSEd Tanous { 1234a0cb85cSEd Tanous return "DHCP"; 1244a0cb85cSEd Tanous } 1254a0cb85cSEd Tanous else 1264a0cb85cSEd Tanous { 1274a0cb85cSEd Tanous return "DHCPv6"; 1284a0cb85cSEd Tanous } 1294a0cb85cSEd Tanous } 1304a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC") 1314a0cb85cSEd Tanous { 1324a0cb85cSEd Tanous return "SLAAC"; 1334a0cb85cSEd Tanous } 1344a0cb85cSEd Tanous return ""; 1354a0cb85cSEd Tanous } 1364a0cb85cSEd Tanous 1374a0cb85cSEd Tanous inline std::string 1384a0cb85cSEd Tanous translateAddressOriginRedfishToDbus(const std::string &inputOrigin) 1394a0cb85cSEd Tanous { 1404a0cb85cSEd Tanous if (inputOrigin == "Static") 1414a0cb85cSEd Tanous { 1424a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 1434a0cb85cSEd Tanous } 1444a0cb85cSEd Tanous if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6") 1454a0cb85cSEd Tanous { 1464a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 1474a0cb85cSEd Tanous } 1484a0cb85cSEd Tanous if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal") 1494a0cb85cSEd Tanous { 1504a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal"; 1514a0cb85cSEd Tanous } 1524a0cb85cSEd Tanous if (inputOrigin == "SLAAC") 1534a0cb85cSEd Tanous { 1544a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC"; 1554a0cb85cSEd Tanous } 1564a0cb85cSEd Tanous return ""; 1574a0cb85cSEd Tanous } 1584a0cb85cSEd Tanous 1594a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string ðiface_id, 1604a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 1614a0cb85cSEd Tanous EthernetInterfaceData ðData) 1624a0cb85cSEd Tanous { 1634a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 1644a0cb85cSEd Tanous { 1654a0cb85cSEd Tanous for (const auto &ifacePair : objpath.second) 1664a0cb85cSEd Tanous { 167*029573d4SEd Tanous if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id) 168*029573d4SEd Tanous { 1694a0cb85cSEd Tanous if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 1704a0cb85cSEd Tanous { 1714a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1724a0cb85cSEd Tanous { 1734a0cb85cSEd Tanous if (propertyPair.first == "MACAddress") 1744a0cb85cSEd Tanous { 1754a0cb85cSEd Tanous const std::string *mac = 176abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 1774a0cb85cSEd Tanous if (mac != nullptr) 1784a0cb85cSEd Tanous { 1794a0cb85cSEd Tanous ethData.mac_address = *mac; 1804a0cb85cSEd Tanous } 1814a0cb85cSEd Tanous } 1824a0cb85cSEd Tanous } 1834a0cb85cSEd Tanous } 1844a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1854a0cb85cSEd Tanous { 1864a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1874a0cb85cSEd Tanous { 1884a0cb85cSEd Tanous if (propertyPair.first == "Id") 1894a0cb85cSEd Tanous { 1901b6b96c5SEd Tanous const uint32_t *id = 191abf2add6SEd Tanous std::get_if<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 = 207abf2add6SEd Tanous std::get_if<bool>(&propertyPair.second); 2084a0cb85cSEd Tanous if (auto_neg != nullptr) 2094a0cb85cSEd Tanous { 2104a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2114a0cb85cSEd Tanous } 2124a0cb85cSEd Tanous } 2134a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2144a0cb85cSEd Tanous { 2154a0cb85cSEd Tanous const uint32_t *speed = 216abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 2174a0cb85cSEd Tanous if (speed != nullptr) 2184a0cb85cSEd Tanous { 2194a0cb85cSEd Tanous ethData.speed = *speed; 2204a0cb85cSEd Tanous } 2214a0cb85cSEd Tanous } 222*029573d4SEd Tanous else if (propertyPair.first == "NameServers") 223*029573d4SEd Tanous { 224*029573d4SEd Tanous const std::vector<std::string> *nameservers = 225*029573d4SEd Tanous sdbusplus::message::variant_ns::get_if< 226*029573d4SEd Tanous std::vector<std::string>>( 227*029573d4SEd Tanous &propertyPair.second); 228*029573d4SEd Tanous if (nameservers != nullptr) 229*029573d4SEd Tanous { 230*029573d4SEd Tanous ethData.nameservers = std::move(*nameservers); 2314a0cb85cSEd Tanous } 2324a0cb85cSEd Tanous } 233*029573d4SEd Tanous } 234*029573d4SEd Tanous } 235*029573d4SEd Tanous } 236*029573d4SEd Tanous // System configuration shows up in the global namespace, so no need 237*029573d4SEd Tanous // to check eth number 238*029573d4SEd Tanous if (ifacePair.first == 2394a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2404a0cb85cSEd Tanous { 2414a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2424a0cb85cSEd Tanous { 2434a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2444a0cb85cSEd Tanous { 2454a0cb85cSEd Tanous const std::string *hostname = 246*029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 247*029573d4SEd Tanous &propertyPair.second); 2484a0cb85cSEd Tanous if (hostname != nullptr) 2494a0cb85cSEd Tanous { 2504a0cb85cSEd Tanous ethData.hostname = *hostname; 2514a0cb85cSEd Tanous } 2524a0cb85cSEd Tanous } 2534a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2544a0cb85cSEd Tanous { 2554a0cb85cSEd Tanous const std::string *defaultGateway = 256*029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 257*029573d4SEd Tanous &propertyPair.second); 2584a0cb85cSEd Tanous if (defaultGateway != nullptr) 2594a0cb85cSEd Tanous { 2604a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2614a0cb85cSEd Tanous } 2624a0cb85cSEd Tanous } 2634a0cb85cSEd Tanous } 2644a0cb85cSEd Tanous } 2654a0cb85cSEd Tanous } 2664a0cb85cSEd Tanous } 2674a0cb85cSEd Tanous } 2684a0cb85cSEd Tanous 2694a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2704a0cb85cSEd Tanous inline void 2714a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2724a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2734a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2744a0cb85cSEd Tanous { 2754a0cb85cSEd Tanous const std::string ipv4PathStart = 2764a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 2774a0cb85cSEd Tanous 2784a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 2794a0cb85cSEd Tanous // single ethernet interface, loop over all of them 2804a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 2814a0cb85cSEd Tanous { 2824a0cb85cSEd Tanous // Check if proper pattern for object path appears 2834a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 2844a0cb85cSEd Tanous { 2854a0cb85cSEd Tanous for (auto &interface : objpath.second) 2864a0cb85cSEd Tanous { 2874a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 2884a0cb85cSEd Tanous { 2894a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 2904a0cb85cSEd Tanous // appropriate 2914a0cb85cSEd Tanous std::pair< 2924a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 2934a0cb85cSEd Tanous bool> 2944a0cb85cSEd Tanous it = ipv4_config.insert( 2954a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 2964a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 2974a0cb85cSEd Tanous for (auto &property : interface.second) 2984a0cb85cSEd Tanous { 2994a0cb85cSEd Tanous if (property.first == "Address") 3004a0cb85cSEd Tanous { 3014a0cb85cSEd Tanous const std::string *address = 302abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3034a0cb85cSEd Tanous if (address != nullptr) 3044a0cb85cSEd Tanous { 3054a0cb85cSEd Tanous ipv4_address.address = *address; 3064a0cb85cSEd Tanous } 3074a0cb85cSEd Tanous } 3084a0cb85cSEd Tanous else if (property.first == "Gateway") 3094a0cb85cSEd Tanous { 3104a0cb85cSEd Tanous const std::string *gateway = 311abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3124a0cb85cSEd Tanous if (gateway != nullptr) 3134a0cb85cSEd Tanous { 3144a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 3154a0cb85cSEd Tanous } 3164a0cb85cSEd Tanous } 3174a0cb85cSEd Tanous else if (property.first == "Origin") 3184a0cb85cSEd Tanous { 3194a0cb85cSEd Tanous const std::string *origin = 320abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3214a0cb85cSEd Tanous if (origin != nullptr) 3224a0cb85cSEd Tanous { 3234a0cb85cSEd Tanous ipv4_address.origin = 3244a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3254a0cb85cSEd Tanous true); 3264a0cb85cSEd Tanous } 3274a0cb85cSEd Tanous } 3284a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3294a0cb85cSEd Tanous { 3304a0cb85cSEd Tanous const uint8_t *mask = 331abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 3324a0cb85cSEd Tanous if (mask != nullptr) 3334a0cb85cSEd Tanous { 3344a0cb85cSEd Tanous // convert it to the string 3354a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3364a0cb85cSEd Tanous } 3374a0cb85cSEd Tanous } 3384a0cb85cSEd Tanous else 3394a0cb85cSEd Tanous { 3404a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3414a0cb85cSEd Tanous << "Got extra property: " << property.first 3424a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3434a0cb85cSEd Tanous } 3444a0cb85cSEd Tanous } 3454a0cb85cSEd Tanous // Check if given address is local, or global 3464a0cb85cSEd Tanous ipv4_address.linktype = 3474a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3484a0cb85cSEd Tanous ? LinkType::Global 3494a0cb85cSEd Tanous : LinkType::Local; 3504a0cb85cSEd Tanous } 3514a0cb85cSEd Tanous } 3524a0cb85cSEd Tanous } 3534a0cb85cSEd Tanous } 3544a0cb85cSEd Tanous } 355588c3f0dSKowalski, Kamil 356588c3f0dSKowalski, Kamil /** 357588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 358588c3f0dSKowalski, Kamil * 359588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 360588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 361588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 362588c3f0dSKowalski, Kamil * 363588c3f0dSKowalski, Kamil * @return None. 364588c3f0dSKowalski, Kamil */ 365588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3664a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3671abe55efSEd Tanous CallbackFunc &&callback) 3681abe55efSEd Tanous { 36955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 370588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 371588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 372588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 373588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 374abf2add6SEd Tanous std::variant<uint32_t>(inputVlanId)); 3754a0cb85cSEd Tanous } 376588c3f0dSKowalski, Kamil 377588c3f0dSKowalski, Kamil /** 378179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 379179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 380179db1d7SKowalski, Kamil * bit count for Subnet Mask. 381179db1d7SKowalski, Kamil * 382179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 383179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 384179db1d7SKowalski, Kamil * 385179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 386179db1d7SKowalski, Kamil */ 3874a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3881abe55efSEd Tanous uint8_t *bits = nullptr) 3891abe55efSEd Tanous { 390179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 391179db1d7SKowalski, Kamil 392179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 393179db1d7SKowalski, Kamil 3944a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 3951abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 3961abe55efSEd Tanous { 397179db1d7SKowalski, Kamil return false; 398179db1d7SKowalski, Kamil } 399179db1d7SKowalski, Kamil 4001abe55efSEd Tanous if (bits != nullptr) 4011abe55efSEd Tanous { 402179db1d7SKowalski, Kamil *bits = 0; 403179db1d7SKowalski, Kamil } 404179db1d7SKowalski, Kamil 405179db1d7SKowalski, Kamil char *endPtr; 406179db1d7SKowalski, Kamil long previousValue = 255; 407179db1d7SKowalski, Kamil bool firstZeroInByteHit; 4081abe55efSEd Tanous for (const std::string &byte : bytesInMask) 4091abe55efSEd Tanous { 4101abe55efSEd Tanous if (byte.empty()) 4111abe55efSEd Tanous { 4121db9ca37SKowalski, Kamil return false; 4131db9ca37SKowalski, Kamil } 4141db9ca37SKowalski, Kamil 415179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4161db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 417179db1d7SKowalski, Kamil 4184a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4194a0cb85cSEd Tanous // is not 100% number 4201abe55efSEd Tanous if (*endPtr != '\0') 4211abe55efSEd Tanous { 422179db1d7SKowalski, Kamil return false; 423179db1d7SKowalski, Kamil } 424179db1d7SKowalski, Kamil 425179db1d7SKowalski, Kamil // Value should be contained in byte 4261abe55efSEd Tanous if (value < 0 || value > 255) 4271abe55efSEd Tanous { 428179db1d7SKowalski, Kamil return false; 429179db1d7SKowalski, Kamil } 430179db1d7SKowalski, Kamil 4311abe55efSEd Tanous if (bits != nullptr) 4321abe55efSEd Tanous { 433179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4341abe55efSEd Tanous if (previousValue != 255 && value != 0) 4351abe55efSEd Tanous { 436179db1d7SKowalski, Kamil return false; 437179db1d7SKowalski, Kamil } 438179db1d7SKowalski, Kamil 439179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 440179db1d7SKowalski, Kamil firstZeroInByteHit = false; 441179db1d7SKowalski, Kamil 442179db1d7SKowalski, Kamil // Count bits 4431abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4441abe55efSEd Tanous { 4451abe55efSEd Tanous if (value & (1 << bitIdx)) 4461abe55efSEd Tanous { 4471abe55efSEd Tanous if (firstZeroInByteHit) 4481abe55efSEd Tanous { 449179db1d7SKowalski, Kamil // Continuity not preserved 450179db1d7SKowalski, Kamil return false; 4511abe55efSEd Tanous } 4521abe55efSEd Tanous else 4531abe55efSEd Tanous { 454179db1d7SKowalski, Kamil (*bits)++; 455179db1d7SKowalski, Kamil } 4561abe55efSEd Tanous } 4571abe55efSEd Tanous else 4581abe55efSEd Tanous { 459179db1d7SKowalski, Kamil firstZeroInByteHit = true; 460179db1d7SKowalski, Kamil } 461179db1d7SKowalski, Kamil } 462179db1d7SKowalski, Kamil } 463179db1d7SKowalski, Kamil 464179db1d7SKowalski, Kamil previousValue = value; 465179db1d7SKowalski, Kamil } 466179db1d7SKowalski, Kamil 467179db1d7SKowalski, Kamil return true; 468179db1d7SKowalski, Kamil } 469179db1d7SKowalski, Kamil 470179db1d7SKowalski, Kamil /** 471179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 472179db1d7SKowalski, Kamil * 473179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4744a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 475179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 476179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 477179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 478179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 479179db1d7SKowalski, Kamil * 480179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 481179db1d7SKowalski, Kamil * otherwise 482179db1d7SKowalski, Kamil */ 4834a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 4844a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 4854a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 4864a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4871abe55efSEd Tanous { 4884a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 4894a0cb85cSEd Tanous newValue{std::move(newValue)}]( 4901abe55efSEd Tanous const boost::system::error_code ec) { 4911abe55efSEd Tanous if (ec) 4921abe55efSEd Tanous { 493a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 4941abe55efSEd Tanous } 4951abe55efSEd Tanous else 4961abe55efSEd Tanous { 4974a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 498179db1d7SKowalski, Kamil } 499179db1d7SKowalski, Kamil }; 500179db1d7SKowalski, Kamil 50155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 502179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 503179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 504179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 505179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 506abf2add6SEd Tanous std::variant<std::string>(newValue)); 5074a0cb85cSEd Tanous } 508179db1d7SKowalski, Kamil 509179db1d7SKowalski, Kamil /** 510179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 511179db1d7SKowalski, Kamil * 512179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5134a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5141abe55efSEd Tanous * modified 515179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 516179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 517179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 518179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 519179db1d7SKowalski, Kamil * 520179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 521179db1d7SKowalski, Kamil * otherwise 522179db1d7SKowalski, Kamil */ 5234a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5241abe55efSEd Tanous const std::string &ipHash, 5251abe55efSEd Tanous const std::string &newValue, 526179db1d7SKowalski, Kamil const std::string &newValueDbus, 5274a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5281abe55efSEd Tanous { 5294a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5301abe55efSEd Tanous const boost::system::error_code ec) { 5311abe55efSEd Tanous if (ec) 5321abe55efSEd Tanous { 533a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5341abe55efSEd Tanous } 5351abe55efSEd Tanous else 5361abe55efSEd Tanous { 5374a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 538179db1d7SKowalski, Kamil newValue; 539179db1d7SKowalski, Kamil } 540179db1d7SKowalski, Kamil }; 541179db1d7SKowalski, Kamil 54255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 543179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 544179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 545179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 546179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 547abf2add6SEd Tanous std::variant<std::string>(newValueDbus)); 5484a0cb85cSEd Tanous } 549179db1d7SKowalski, Kamil 550179db1d7SKowalski, Kamil /** 551179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 552179db1d7SKowalski, Kamil * 553179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5544a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5551abe55efSEd Tanous * modified 556179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 557179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 558179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 559179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 560179db1d7SKowalski, Kamil * 561179db1d7SKowalski, Kamil * @return None 562179db1d7SKowalski, Kamil */ 5634a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5644a0cb85cSEd Tanous const std::string &ipHash, 5654a0cb85cSEd Tanous const std::string &newValueStr, 5664a0cb85cSEd Tanous uint8_t &newValue, 5674a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5681abe55efSEd Tanous { 5694a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5701abe55efSEd Tanous const boost::system::error_code ec) { 5711abe55efSEd Tanous if (ec) 5721abe55efSEd Tanous { 573a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5741abe55efSEd Tanous } 5751abe55efSEd Tanous else 5761abe55efSEd Tanous { 57755c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 578179db1d7SKowalski, Kamil newValueStr; 579179db1d7SKowalski, Kamil } 580179db1d7SKowalski, Kamil }; 581179db1d7SKowalski, Kamil 58255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 583179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 584179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 585179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 586179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 587abf2add6SEd Tanous std::variant<uint8_t>(newValue)); 5884a0cb85cSEd Tanous } 589588c3f0dSKowalski, Kamil 590588c3f0dSKowalski, Kamil /** 591179db1d7SKowalski, Kamil * @brief Deletes given IPv4 592179db1d7SKowalski, Kamil * 593179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 5944a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 595179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 596179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 597179db1d7SKowalski, Kamil * 598179db1d7SKowalski, Kamil * @return None 599179db1d7SKowalski, Kamil */ 6004a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 601179db1d7SKowalski, Kamil unsigned int ipIdx, 6024a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6031abe55efSEd Tanous { 60455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6054a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6061abe55efSEd Tanous if (ec) 6071abe55efSEd Tanous { 608a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 6091abe55efSEd Tanous } 6101abe55efSEd Tanous else 6111abe55efSEd Tanous { 61255c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 613179db1d7SKowalski, Kamil } 614179db1d7SKowalski, Kamil }, 615179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 616179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 617179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 618179db1d7SKowalski, Kamil } 619179db1d7SKowalski, Kamil 620179db1d7SKowalski, Kamil /** 621179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 622179db1d7SKowalski, Kamil * 623179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6244a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 625179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 626179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 627179db1d7SKowalski, Kamil * 628179db1d7SKowalski, Kamil * @return None 629179db1d7SKowalski, Kamil */ 6304a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 631179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 632179db1d7SKowalski, Kamil const std::string &address, 6334a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6341abe55efSEd Tanous { 6354a0cb85cSEd Tanous auto createIpHandler = [ipIdx, 6364a0cb85cSEd Tanous asyncResp](const boost::system::error_code ec) { 6371abe55efSEd Tanous if (ec) 6381abe55efSEd Tanous { 639a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 640179db1d7SKowalski, Kamil } 641179db1d7SKowalski, Kamil }; 642179db1d7SKowalski, Kamil 64355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 644179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 645179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 646179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 647179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 648179db1d7SKowalski, Kamil gateway); 649179db1d7SKowalski, Kamil } 650179db1d7SKowalski, Kamil 651179db1d7SKowalski, Kamil /** 652179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 653179db1d7SKowalski, Kamil * Object 654179db1d7SKowalski, Kamil * from EntityManager Network Manager 6554a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 656179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 657179db1d7SKowalski, Kamil * into JSON 658179db1d7SKowalski, Kamil */ 659179db1d7SKowalski, Kamil template <typename CallbackFunc> 6604a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 6611abe55efSEd Tanous CallbackFunc &&callback) 6621abe55efSEd Tanous { 66355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6644a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 6651abe55efSEd Tanous const boost::system::error_code error_code, 6664a0cb85cSEd Tanous const GetManagedObjects &resp) { 66755c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 6684a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 669179db1d7SKowalski, Kamil 6701abe55efSEd Tanous if (error_code) 6711abe55efSEd Tanous { 67255c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 673179db1d7SKowalski, Kamil return; 674179db1d7SKowalski, Kamil } 675179db1d7SKowalski, Kamil 6764a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 6774a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 678179db1d7SKowalski, Kamil 679179db1d7SKowalski, Kamil // Fix global GW 6801abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 6811abe55efSEd Tanous { 6824a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 6834a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 6841abe55efSEd Tanous { 6854a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 686179db1d7SKowalski, Kamil } 687179db1d7SKowalski, Kamil } 688179db1d7SKowalski, Kamil 6894a0cb85cSEd Tanous // Finally make a callback with usefull data 69055c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 691179db1d7SKowalski, Kamil }, 692179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 693179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 694179db1d7SKowalski, Kamil }; 695179db1d7SKowalski, Kamil 696179db1d7SKowalski, Kamil /** 6979391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 6989391bb9cSRapkiewicz, Pawel * Manager 6991abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7001abe55efSEd Tanous * into JSON. 7019391bb9cSRapkiewicz, Pawel */ 7029391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7031abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7041abe55efSEd Tanous { 70555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7064a0cb85cSEd Tanous [callback{std::move(callback)}]( 7079391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 7084a0cb85cSEd Tanous GetManagedObjects &resp) { 7091abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7101abe55efSEd Tanous // ethernet interfaces 7114a0cb85cSEd Tanous std::vector<std::string> iface_list; 7124a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7131abe55efSEd Tanous if (error_code) 7141abe55efSEd Tanous { 7154a0cb85cSEd Tanous callback(false, iface_list); 7169391bb9cSRapkiewicz, Pawel return; 7179391bb9cSRapkiewicz, Pawel } 7189391bb9cSRapkiewicz, Pawel 7199391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7204a0cb85cSEd Tanous for (const auto &objpath : resp) 7211abe55efSEd Tanous { 7229391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7234a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7241abe55efSEd Tanous { 7251abe55efSEd Tanous // If interface is 7264a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 7274a0cb85cSEd Tanous // what we're looking for. 7289391bb9cSRapkiewicz, Pawel if (interface.first == 7291abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7301abe55efSEd Tanous { 7314a0cb85cSEd Tanous // Cut out everyting until last "/", ... 7324a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 7334a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 7344a0cb85cSEd Tanous if (last_pos != std::string::npos) 7351abe55efSEd Tanous { 7369391bb9cSRapkiewicz, Pawel // and put it into output vector. 7374a0cb85cSEd Tanous iface_list.emplace_back( 7384a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7399391bb9cSRapkiewicz, Pawel } 7409391bb9cSRapkiewicz, Pawel } 7419391bb9cSRapkiewicz, Pawel } 7429391bb9cSRapkiewicz, Pawel } 743a434f2bdSEd Tanous // Finally make a callback with useful data 7444a0cb85cSEd Tanous callback(true, iface_list); 7459391bb9cSRapkiewicz, Pawel }, 746aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 747aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7489391bb9cSRapkiewicz, Pawel }; 7499391bb9cSRapkiewicz, Pawel 7509391bb9cSRapkiewicz, Pawel /** 7519391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7529391bb9cSRapkiewicz, Pawel */ 7531abe55efSEd Tanous class EthernetCollection : public Node 7541abe55efSEd Tanous { 7559391bb9cSRapkiewicz, Pawel public: 7564a0cb85cSEd Tanous template <typename CrowApp> 7571abe55efSEd Tanous EthernetCollection(CrowApp &app) : 7584a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 7591abe55efSEd Tanous { 760588c3f0dSKowalski, Kamil entityPrivileges = { 761588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 762e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 763e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 764e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 765e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 766e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7679391bb9cSRapkiewicz, Pawel } 7689391bb9cSRapkiewicz, Pawel 7699391bb9cSRapkiewicz, Pawel private: 7709391bb9cSRapkiewicz, Pawel /** 7719391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 7729391bb9cSRapkiewicz, Pawel */ 77355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7741abe55efSEd Tanous const std::vector<std::string> ¶ms) override 7751abe55efSEd Tanous { 7760f74e643SEd Tanous res.jsonValue["@odata.type"] = 7770f74e643SEd Tanous "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7780f74e643SEd Tanous res.jsonValue["@odata.context"] = 7790f74e643SEd Tanous "/redfish/v1/" 7800f74e643SEd Tanous "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7810f74e643SEd Tanous res.jsonValue["@odata.id"] = 7820f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7830f74e643SEd Tanous res.jsonValue["Name"] = "Ethernet Network Interface Collection"; 7840f74e643SEd Tanous res.jsonValue["Description"] = 7850f74e643SEd Tanous "Collection of EthernetInterfaces for this Manager"; 7860f74e643SEd Tanous 7874a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 7881abe55efSEd Tanous // preparation 789f12894f8SJason M. Bills getEthernetIfaceList( 790f12894f8SJason M. Bills [&res](const bool &success, 7911abe55efSEd Tanous const std::vector<std::string> &iface_list) { 7924a0cb85cSEd Tanous if (!success) 7931abe55efSEd Tanous { 794f12894f8SJason M. Bills messages::internalError(res); 7954a0cb85cSEd Tanous res.end(); 7964a0cb85cSEd Tanous return; 7974a0cb85cSEd Tanous } 7984a0cb85cSEd Tanous 7994a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 8004a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 8014a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8021abe55efSEd Tanous { 8034a0cb85cSEd Tanous iface_array.push_back( 8044a0cb85cSEd Tanous {{"@odata.id", 8054a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 8064a0cb85cSEd Tanous iface_item}}); 8079391bb9cSRapkiewicz, Pawel } 8084a0cb85cSEd Tanous 8094a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 8104a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 8114a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8129391bb9cSRapkiewicz, Pawel res.end(); 8139391bb9cSRapkiewicz, Pawel }); 8149391bb9cSRapkiewicz, Pawel } 8159391bb9cSRapkiewicz, Pawel }; 8169391bb9cSRapkiewicz, Pawel 8179391bb9cSRapkiewicz, Pawel /** 8189391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8199391bb9cSRapkiewicz, Pawel */ 8201abe55efSEd Tanous class EthernetInterface : public Node 8211abe55efSEd Tanous { 8229391bb9cSRapkiewicz, Pawel public: 8239391bb9cSRapkiewicz, Pawel /* 8249391bb9cSRapkiewicz, Pawel * Default Constructor 8259391bb9cSRapkiewicz, Pawel */ 8264a0cb85cSEd Tanous template <typename CrowApp> 8271abe55efSEd Tanous EthernetInterface(CrowApp &app) : 8284a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8291abe55efSEd Tanous std::string()) 8301abe55efSEd Tanous { 831588c3f0dSKowalski, Kamil entityPrivileges = { 832588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 833e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 834e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 835e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 836e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 837e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8389391bb9cSRapkiewicz, Pawel } 8399391bb9cSRapkiewicz, Pawel 840e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 8410627a2c7SEd Tanous static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable, 8420627a2c7SEd Tanous uint64_t vlanId, 8434a0cb85cSEd Tanous const EthernetInterfaceData ðData, 8444a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8451abe55efSEd Tanous { 8464a0cb85cSEd Tanous if (!ethData.vlan_id) 8471abe55efSEd Tanous { 848e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 849e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 850a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, "VLANEnable"); 851588c3f0dSKowalski, Kamil 852588c3f0dSKowalski, Kamil return; 853588c3f0dSKowalski, Kamil } 854588c3f0dSKowalski, Kamil 855588c3f0dSKowalski, Kamil // VLAN is configured on the interface 8560627a2c7SEd Tanous if (vlanEnable == true) 8571abe55efSEd Tanous { 858588c3f0dSKowalski, Kamil // Change VLAN Id 8590627a2c7SEd Tanous asyncResp->res.jsonValue["VLANId"] = vlanId; 8604a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 8611abe55efSEd Tanous if (ec) 8621abe55efSEd Tanous { 863f12894f8SJason M. Bills messages::internalError(asyncResp->res); 8641abe55efSEd Tanous } 8651abe55efSEd Tanous else 8661abe55efSEd Tanous { 8674a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 868e439f0f8SKowalski, Kamil } 8694a0cb85cSEd Tanous }; 8704a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 8714a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 8724a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 8734a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 8744a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 875abf2add6SEd Tanous std::variant<uint32_t>(vlanId)); 8761abe55efSEd Tanous } 8774a0cb85cSEd Tanous else 8781abe55efSEd Tanous { 8794a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 8801abe55efSEd Tanous if (ec) 8811abe55efSEd Tanous { 882f12894f8SJason M. Bills messages::internalError(asyncResp->res); 8834a0cb85cSEd Tanous return; 8841abe55efSEd Tanous } 8854a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 8864a0cb85cSEd Tanous }; 8874a0cb85cSEd Tanous 8884a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 8894a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 8904a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 8914a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 892588c3f0dSKowalski, Kamil } 893588c3f0dSKowalski, Kamil } 894588c3f0dSKowalski, Kamil 895e439f0f8SKowalski, Kamil private: 896bc0bd6e0SEd Tanous void handleHostnamePatch(const std::string &hostname, 8974a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8981abe55efSEd Tanous { 899bc0bd6e0SEd Tanous asyncResp->res.jsonValue["HostName"] = hostname; 900bc0bd6e0SEd Tanous crow::connections::systemBus->async_method_call( 901bc0bd6e0SEd Tanous [asyncResp](const boost::system::error_code ec) { 9024a0cb85cSEd Tanous if (ec) 9034a0cb85cSEd Tanous { 904a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 9051abe55efSEd Tanous } 906bc0bd6e0SEd Tanous }, 907bc0bd6e0SEd Tanous "xyz.openbmc_project.Network", 908bc0bd6e0SEd Tanous "/xyz/openbmc_project/network/config", 909bc0bd6e0SEd Tanous "org.freedesktop.DBus.Properties", "Set", 910bc0bd6e0SEd Tanous "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 911abf2add6SEd Tanous std::variant<std::string>(hostname)); 912588c3f0dSKowalski, Kamil } 913588c3f0dSKowalski, Kamil 9144a0cb85cSEd Tanous void handleIPv4Patch( 9154a0cb85cSEd Tanous const std::string &ifaceId, const nlohmann::json &input, 9164a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 9174a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9181abe55efSEd Tanous { 9191abe55efSEd Tanous if (!input.is_array()) 9201abe55efSEd Tanous { 921f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 922a08b46ccSJason M. Bills "IPv4Addresses"); 923179db1d7SKowalski, Kamil return; 924179db1d7SKowalski, Kamil } 925179db1d7SKowalski, Kamil 926179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 9274a0cb85cSEd Tanous if (input.size() < ipv4Data.size()) 9281abe55efSEd Tanous { 929a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, input.dump(), 930a08b46ccSJason M. Bills "IPv4Addresses"); 931179db1d7SKowalski, Kamil return; 932179db1d7SKowalski, Kamil } 933179db1d7SKowalski, Kamil 9344a0cb85cSEd Tanous int entryIdx = 0; 9354a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 9364a0cb85cSEd Tanous ipv4Data.begin(); 9374a0cb85cSEd Tanous for (const nlohmann::json &thisJson : input) 9381abe55efSEd Tanous { 9394a0cb85cSEd Tanous std::string pathString = 940a08b46ccSJason M. Bills "IPv4Addresses/" + std::to_string(entryIdx); 941179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 9424a0cb85cSEd Tanous if (!thisJson.is_object() && !thisJson.is_null()) 9431abe55efSEd Tanous { 944a08b46ccSJason M. Bills messages::propertyValueTypeError(asyncResp->res, 945a08b46ccSJason M. Bills thisJson.dump(), 946a08b46ccSJason M. Bills pathString + "/IPv4Address"); 947179db1d7SKowalski, Kamil 948179db1d7SKowalski, Kamil continue; 949179db1d7SKowalski, Kamil } 950179db1d7SKowalski, Kamil 9514a0cb85cSEd Tanous nlohmann::json::const_iterator addressFieldIt = 9524a0cb85cSEd Tanous thisJson.find("Address"); 9534a0cb85cSEd Tanous const std::string *addressField = nullptr; 9544a0cb85cSEd Tanous if (addressFieldIt != thisJson.end()) 9551abe55efSEd Tanous { 9564a0cb85cSEd Tanous addressField = addressFieldIt->get_ptr<const std::string *>(); 9574a0cb85cSEd Tanous if (addressField == nullptr) 9581abe55efSEd Tanous { 959a08b46ccSJason M. Bills messages::propertyValueFormatError(asyncResp->res, 960a08b46ccSJason M. Bills addressFieldIt->dump(), 9614a0cb85cSEd Tanous pathString + "/Address"); 962179db1d7SKowalski, Kamil continue; 963179db1d7SKowalski, Kamil } 9641abe55efSEd Tanous else 9651abe55efSEd Tanous { 9664a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*addressField)) 9674a0cb85cSEd Tanous { 968f12894f8SJason M. Bills messages::propertyValueFormatError( 969a08b46ccSJason M. Bills asyncResp->res, *addressField, 9704a0cb85cSEd Tanous pathString + "/Address"); 9714a0cb85cSEd Tanous continue; 9724a0cb85cSEd Tanous } 9734a0cb85cSEd Tanous } 9744a0cb85cSEd Tanous } 9754a0cb85cSEd Tanous 976a24526dcSEd Tanous std::optional<uint8_t> prefixLength; 9774a0cb85cSEd Tanous const std::string *subnetField = nullptr; 9784a0cb85cSEd Tanous nlohmann::json::const_iterator subnetFieldIt = 9794a0cb85cSEd Tanous thisJson.find("SubnetMask"); 9804a0cb85cSEd Tanous if (subnetFieldIt != thisJson.end()) 9814a0cb85cSEd Tanous { 9824a0cb85cSEd Tanous subnetField = subnetFieldIt->get_ptr<const std::string *>(); 9834a0cb85cSEd Tanous if (subnetField == nullptr) 9844a0cb85cSEd Tanous { 985f12894f8SJason M. Bills messages::propertyValueFormatError( 986a08b46ccSJason M. Bills asyncResp->res, *subnetField, 9874a0cb85cSEd Tanous pathString + "/SubnetMask"); 9884a0cb85cSEd Tanous continue; 9894a0cb85cSEd Tanous } 9904a0cb85cSEd Tanous else 9914a0cb85cSEd Tanous { 9924a0cb85cSEd Tanous prefixLength = 0; 9934a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetField, 9944a0cb85cSEd Tanous &*prefixLength)) 9954a0cb85cSEd Tanous { 996f12894f8SJason M. Bills messages::propertyValueFormatError( 997a08b46ccSJason M. Bills asyncResp->res, *subnetField, 9984a0cb85cSEd Tanous pathString + "/SubnetMask"); 9994a0cb85cSEd Tanous continue; 10004a0cb85cSEd Tanous } 10014a0cb85cSEd Tanous } 10024a0cb85cSEd Tanous } 10034a0cb85cSEd Tanous 10044a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 10054a0cb85cSEd Tanous const std::string *addressOriginField = nullptr; 10064a0cb85cSEd Tanous nlohmann::json::const_iterator addressOriginFieldIt = 10074a0cb85cSEd Tanous thisJson.find("AddressOrigin"); 10084a0cb85cSEd Tanous if (addressOriginFieldIt != thisJson.end()) 10094a0cb85cSEd Tanous { 10104a0cb85cSEd Tanous const std::string *addressOriginField = 10114a0cb85cSEd Tanous addressOriginFieldIt->get_ptr<const std::string *>(); 10124a0cb85cSEd Tanous if (addressOriginField == nullptr) 10134a0cb85cSEd Tanous { 1014f12894f8SJason M. Bills messages::propertyValueFormatError( 1015a08b46ccSJason M. Bills asyncResp->res, *addressOriginField, 10164a0cb85cSEd Tanous pathString + "/AddressOrigin"); 10174a0cb85cSEd Tanous continue; 10184a0cb85cSEd Tanous } 10194a0cb85cSEd Tanous else 10204a0cb85cSEd Tanous { 10214a0cb85cSEd Tanous // Get Address origin in proper format 10224a0cb85cSEd Tanous addressOriginInDBusFormat = 10234a0cb85cSEd Tanous translateAddressOriginRedfishToDbus( 10244a0cb85cSEd Tanous *addressOriginField); 10254a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 10264a0cb85cSEd Tanous { 10274a0cb85cSEd Tanous messages::propertyValueNotInList( 1028f12894f8SJason M. Bills asyncResp->res, *addressOriginField, 1029a08b46ccSJason M. Bills pathString + "/AddressOrigin"); 10304a0cb85cSEd Tanous continue; 10314a0cb85cSEd Tanous } 10324a0cb85cSEd Tanous } 10334a0cb85cSEd Tanous } 10344a0cb85cSEd Tanous 10354a0cb85cSEd Tanous nlohmann::json::const_iterator gatewayFieldIt = 10364a0cb85cSEd Tanous thisJson.find("Gateway"); 10374a0cb85cSEd Tanous const std::string *gatewayField = nullptr; 10384a0cb85cSEd Tanous if (gatewayFieldIt != thisJson.end()) 10394a0cb85cSEd Tanous { 10404a0cb85cSEd Tanous const std::string *gatewayField = 10414a0cb85cSEd Tanous gatewayFieldIt->get_ptr<const std::string *>(); 10424a0cb85cSEd Tanous if (gatewayField == nullptr || 10434a0cb85cSEd Tanous !ipv4VerifyIpAndGetBitcount(*gatewayField)) 10444a0cb85cSEd Tanous { 1045a08b46ccSJason M. Bills messages::propertyValueFormatError( 1046a08b46ccSJason M. Bills asyncResp->res, *gatewayField, pathString + "/Gateway"); 10474a0cb85cSEd Tanous continue; 10484a0cb85cSEd Tanous } 10494a0cb85cSEd Tanous } 10504a0cb85cSEd Tanous 10514a0cb85cSEd Tanous // if a vlan already exists, modify the existing 10524a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 10534a0cb85cSEd Tanous { 10541abe55efSEd Tanous // Existing object that should be modified/deleted/remain 10551abe55efSEd Tanous // unchanged 10564a0cb85cSEd Tanous if (thisJson.is_null()) 10571abe55efSEd Tanous { 10584a0cb85cSEd Tanous auto callback = [entryIdx{std::to_string(entryIdx)}, 10594a0cb85cSEd Tanous asyncResp]( 10604a0cb85cSEd Tanous const boost::system::error_code ec) { 10614a0cb85cSEd Tanous if (ec) 10624a0cb85cSEd Tanous { 1063a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 10644a0cb85cSEd Tanous return; 10651abe55efSEd Tanous } 10664a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 10674a0cb85cSEd Tanous nullptr; 10684a0cb85cSEd Tanous }; 10694a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 10704a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 10714a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 10724a0cb85cSEd Tanous thisData->id, 10734a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 1074179db1d7SKowalski, Kamil } 10754a0cb85cSEd Tanous else if (thisJson.is_object()) 10764a0cb85cSEd Tanous { 1077179db1d7SKowalski, Kamil // Apply changes 10784a0cb85cSEd Tanous if (addressField != nullptr) 10791abe55efSEd Tanous { 10804a0cb85cSEd Tanous auto callback = 10814a0cb85cSEd Tanous [asyncResp, entryIdx, 10824a0cb85cSEd Tanous addressField{std::string(*addressField)}]( 10834a0cb85cSEd Tanous const boost::system::error_code ec) { 10844a0cb85cSEd Tanous if (ec) 10851abe55efSEd Tanous { 1086a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 10874a0cb85cSEd Tanous return; 10884a0cb85cSEd Tanous } 10894a0cb85cSEd Tanous asyncResp->res 10904a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 10914a0cb85cSEd Tanous entryIdx)]["Address"] = addressField; 10924a0cb85cSEd Tanous }; 10934a0cb85cSEd Tanous 10944a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 10954a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 10964a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 10974a0cb85cSEd Tanous "/ipv4/" + thisData->id, 10984a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 10994a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 1100abf2add6SEd Tanous std::variant<std::string>(*addressField)); 1101179db1d7SKowalski, Kamil } 1102179db1d7SKowalski, Kamil 11034a0cb85cSEd Tanous if (prefixLength && subnetField != nullptr) 11041abe55efSEd Tanous { 11054a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 11064a0cb85cSEd Tanous thisData->id, *subnetField, 11074a0cb85cSEd Tanous *prefixLength, asyncResp); 1108179db1d7SKowalski, Kamil } 1109179db1d7SKowalski, Kamil 11104a0cb85cSEd Tanous if (!addressOriginInDBusFormat.empty() && 11114a0cb85cSEd Tanous addressOriginField != nullptr) 11121abe55efSEd Tanous { 11134a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 11144a0cb85cSEd Tanous *addressOriginField, 11154a0cb85cSEd Tanous addressOriginInDBusFormat, asyncResp); 1116179db1d7SKowalski, Kamil } 1117179db1d7SKowalski, Kamil 11184a0cb85cSEd Tanous if (gatewayField != nullptr) 11191abe55efSEd Tanous { 11204a0cb85cSEd Tanous auto callback = 11214a0cb85cSEd Tanous [asyncResp, entryIdx, 11224a0cb85cSEd Tanous gatewayField{std::string(*gatewayField)}]( 11234a0cb85cSEd Tanous const boost::system::error_code ec) { 11244a0cb85cSEd Tanous if (ec) 11251abe55efSEd Tanous { 1126a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11274a0cb85cSEd Tanous return; 11284a0cb85cSEd Tanous } 11294a0cb85cSEd Tanous asyncResp->res 11304a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 11314a0cb85cSEd Tanous entryIdx)]["Gateway"] = 11324a0cb85cSEd Tanous std::move(gatewayField); 11334a0cb85cSEd Tanous }; 11344a0cb85cSEd Tanous 11354a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11364a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11374a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 11384a0cb85cSEd Tanous "/ipv4/" + thisData->id, 11394a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11404a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 1141abf2add6SEd Tanous std::variant<std::string>(*gatewayField)); 11424a0cb85cSEd Tanous } 11434a0cb85cSEd Tanous } 11444a0cb85cSEd Tanous thisData++; 11451abe55efSEd Tanous } 11461abe55efSEd Tanous else 11471abe55efSEd Tanous { 11484a0cb85cSEd Tanous // Create IPv4 with provided data 11494a0cb85cSEd Tanous if (gatewayField == nullptr) 11501abe55efSEd Tanous { 1151a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11524a0cb85cSEd Tanous pathString + "/Gateway"); 11534a0cb85cSEd Tanous continue; 11544a0cb85cSEd Tanous } 11554a0cb85cSEd Tanous 11564a0cb85cSEd Tanous if (addressField == nullptr) 11571abe55efSEd Tanous { 1158a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11594a0cb85cSEd Tanous pathString + "/Address"); 11604a0cb85cSEd Tanous continue; 11614a0cb85cSEd Tanous } 11624a0cb85cSEd Tanous 11634a0cb85cSEd Tanous if (!prefixLength) 11641abe55efSEd Tanous { 1165a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11664a0cb85cSEd Tanous pathString + "/SubnetMask"); 11674a0cb85cSEd Tanous continue; 1168588c3f0dSKowalski, Kamil } 1169588c3f0dSKowalski, Kamil 11704a0cb85cSEd Tanous createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField, 11714a0cb85cSEd Tanous *addressField, asyncResp); 11724a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 11734a0cb85cSEd Tanous } 11744a0cb85cSEd Tanous entryIdx++; 11754a0cb85cSEd Tanous } 11764a0cb85cSEd Tanous } 11774a0cb85cSEd Tanous 11780f74e643SEd Tanous void parseInterfaceData( 11790f74e643SEd Tanous nlohmann::json &json_response, const std::string &iface_id, 11800f74e643SEd Tanous const EthernetInterfaceData ðData, 11814a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 11824a0cb85cSEd Tanous { 11834a0cb85cSEd Tanous json_response["Id"] = iface_id; 11844a0cb85cSEd Tanous json_response["@odata.id"] = 11854a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 1186*029573d4SEd Tanous json_response["InterfaceEnabled"] = true; 1187*029573d4SEd Tanous if (ethData.speed == 0) 1188*029573d4SEd Tanous { 1189*029573d4SEd Tanous json_response["LinkStatus"] = "NoLink"; 1190*029573d4SEd Tanous json_response["Status"] = { 1191*029573d4SEd Tanous {"Health", "OK"}, 1192*029573d4SEd Tanous {"State", "Disabled"}, 1193*029573d4SEd Tanous }; 1194*029573d4SEd Tanous } 1195*029573d4SEd Tanous else 1196*029573d4SEd Tanous { 1197*029573d4SEd Tanous json_response["LinkStatus"] = "LinkUp"; 1198*029573d4SEd Tanous json_response["Status"] = { 1199*029573d4SEd Tanous {"Health", "OK"}, 1200*029573d4SEd Tanous {"State", "Enabled"}, 1201*029573d4SEd Tanous }; 1202*029573d4SEd Tanous } 12034a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 12044a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 12054a0cb85cSEd Tanous if (!ethData.hostname.empty()) 12064a0cb85cSEd Tanous { 12074a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 12084a0cb85cSEd Tanous } 12094a0cb85cSEd Tanous 12104a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 12114a0cb85cSEd Tanous if (ethData.vlan_id) 12124a0cb85cSEd Tanous { 12134a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 12144a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 12154a0cb85cSEd Tanous } 12164a0cb85cSEd Tanous else 12174a0cb85cSEd Tanous { 12184a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 12194a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 12204a0cb85cSEd Tanous } 1221*029573d4SEd Tanous json_response["NameServers"] = ethData.nameservers; 12224a0cb85cSEd Tanous 12234a0cb85cSEd Tanous if (ipv4Data.size() > 0) 12244a0cb85cSEd Tanous { 12254a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 12264a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 12274a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 12284a0cb85cSEd Tanous { 12294a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 12304a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 1231*029573d4SEd Tanous {"Address", ipv4_config.address}, 1232*029573d4SEd Tanous {"Gateway", ipv4_config.gateway}}); 12334a0cb85cSEd Tanous } 12344a0cb85cSEd Tanous } 1235588c3f0dSKowalski, Kamil } 1236588c3f0dSKowalski, Kamil 12379391bb9cSRapkiewicz, Pawel /** 12389391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12399391bb9cSRapkiewicz, Pawel */ 124055c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12411abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12421abe55efSEd Tanous { 12434a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12441abe55efSEd Tanous if (params.size() != 1) 12451abe55efSEd Tanous { 1246f12894f8SJason M. Bills messages::internalError(asyncResp->res); 12479391bb9cSRapkiewicz, Pawel return; 12489391bb9cSRapkiewicz, Pawel } 12499391bb9cSRapkiewicz, Pawel 12504a0cb85cSEd Tanous getEthernetIfaceData( 12514a0cb85cSEd Tanous params[0], 12524a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 12534a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 12544a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 12554a0cb85cSEd Tanous if (!success) 12561abe55efSEd Tanous { 12571abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 12581abe55efSEd Tanous // object, and other errors 1259f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1260f12894f8SJason M. Bills "EthernetInterface", iface_id); 12614a0cb85cSEd Tanous return; 12629391bb9cSRapkiewicz, Pawel } 12630f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 12640f74e643SEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 12650f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 12660f74e643SEd Tanous "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 12670f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; 12680f74e643SEd Tanous asyncResp->res.jsonValue["Description"] = 12690f74e643SEd Tanous "Management Network Interface"; 12700f74e643SEd Tanous 12710f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 12720f74e643SEd Tanous ipv4Data); 12739391bb9cSRapkiewicz, Pawel }); 12749391bb9cSRapkiewicz, Pawel } 12759391bb9cSRapkiewicz, Pawel 127655c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 12771abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12781abe55efSEd Tanous { 12794a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12801abe55efSEd Tanous if (params.size() != 1) 12811abe55efSEd Tanous { 1282f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1283588c3f0dSKowalski, Kamil return; 1284588c3f0dSKowalski, Kamil } 1285588c3f0dSKowalski, Kamil 12864a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1287588c3f0dSKowalski, Kamil 12880627a2c7SEd Tanous std::optional<nlohmann::json> vlan; 1289bc0bd6e0SEd Tanous std::optional<std::string> hostname; 12900627a2c7SEd Tanous std::optional<nlohmann::json> ipv4Addresses; 12910627a2c7SEd Tanous std::optional<nlohmann::json> ipv6Addresses; 12920627a2c7SEd Tanous 12930627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname, 12940627a2c7SEd Tanous "IPv4Addresses", ipv4Addresses, 12950627a2c7SEd Tanous "IPv6Addresses", ipv6Addresses)) 12961abe55efSEd Tanous { 1297588c3f0dSKowalski, Kamil return; 1298588c3f0dSKowalski, Kamil } 12990627a2c7SEd Tanous std::optional<uint64_t> vlanId = 0; 13000627a2c7SEd Tanous std::optional<bool> vlanEnable = false; 13010627a2c7SEd Tanous if (vlan) 13020627a2c7SEd Tanous { 13030627a2c7SEd Tanous if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable, 13040627a2c7SEd Tanous "VLANId", vlanId)) 13050627a2c7SEd Tanous { 13060627a2c7SEd Tanous return; 13070627a2c7SEd Tanous } 13080627a2c7SEd Tanous // Need both vlanId and vlanEnable to service this request 13090627a2c7SEd Tanous if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable)) 13100627a2c7SEd Tanous { 13110627a2c7SEd Tanous if (vlanId) 13120627a2c7SEd Tanous { 13130627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANEnable"); 13140627a2c7SEd Tanous } 13150627a2c7SEd Tanous else 13160627a2c7SEd Tanous { 13170627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANId"); 13180627a2c7SEd Tanous } 13190627a2c7SEd Tanous 13200627a2c7SEd Tanous return; 13210627a2c7SEd Tanous } 13220627a2c7SEd Tanous } 1323588c3f0dSKowalski, Kamil 13244a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1325588c3f0dSKowalski, Kamil // preparation 13264a0cb85cSEd Tanous getEthernetIfaceData( 13274a0cb85cSEd Tanous iface_id, 13280627a2c7SEd Tanous [this, asyncResp, iface_id, vlanId, vlanEnable, 13290627a2c7SEd Tanous hostname = std::move(hostname), 13300627a2c7SEd Tanous ipv4Addresses = std::move(ipv4Addresses), 13310627a2c7SEd Tanous ipv6Addresses = std::move(ipv6Addresses)]( 13324a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13334a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13341abe55efSEd Tanous if (!success) 13351abe55efSEd Tanous { 1336588c3f0dSKowalski, Kamil // ... otherwise return error 13371abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13381abe55efSEd Tanous // object, and other errors 1339f12894f8SJason M. Bills messages::resourceNotFound( 1340f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1341588c3f0dSKowalski, Kamil return; 1342588c3f0dSKowalski, Kamil } 1343588c3f0dSKowalski, Kamil 13440f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13450f74e643SEd Tanous ipv4Data); 1346588c3f0dSKowalski, Kamil 13470627a2c7SEd Tanous if (vlanId && vlanEnable) 13481abe55efSEd Tanous { 13490627a2c7SEd Tanous handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData, 13504a0cb85cSEd Tanous asyncResp); 13511abe55efSEd Tanous } 13520627a2c7SEd Tanous 13530627a2c7SEd Tanous if (hostname) 13541abe55efSEd Tanous { 13550627a2c7SEd Tanous handleHostnamePatch(*hostname, asyncResp); 13561abe55efSEd Tanous } 13570627a2c7SEd Tanous 13580627a2c7SEd Tanous if (ipv4Addresses) 13591abe55efSEd Tanous { 13600627a2c7SEd Tanous handleIPv4Patch(iface_id, *ipv4Addresses, ipv4Data, 1361179db1d7SKowalski, Kamil asyncResp); 13621abe55efSEd Tanous } 13630627a2c7SEd Tanous 13640627a2c7SEd Tanous if (ipv6Addresses) 13651abe55efSEd Tanous { 1366179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1367a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, 13680627a2c7SEd Tanous "IPv6Addresses"); 1369588c3f0dSKowalski, Kamil } 1370588c3f0dSKowalski, Kamil }); 1371588c3f0dSKowalski, Kamil } 13729391bb9cSRapkiewicz, Pawel }; 13739391bb9cSRapkiewicz, Pawel 1374e439f0f8SKowalski, Kamil /** 13754a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 13764a0cb85cSEd Tanous * Schema 1377e439f0f8SKowalski, Kamil */ 13781abe55efSEd Tanous class VlanNetworkInterface : public Node 13791abe55efSEd Tanous { 1380e439f0f8SKowalski, Kamil public: 1381e439f0f8SKowalski, Kamil /* 1382e439f0f8SKowalski, Kamil * Default Constructor 1383e439f0f8SKowalski, Kamil */ 1384e439f0f8SKowalski, Kamil template <typename CrowApp> 13851abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 13864a0cb85cSEd Tanous Node(app, 13870f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>", 13881abe55efSEd Tanous std::string(), std::string()) 13891abe55efSEd Tanous { 1390e439f0f8SKowalski, Kamil entityPrivileges = { 1391e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1392e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1393e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1394e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1395e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1396e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1397e439f0f8SKowalski, Kamil } 1398e439f0f8SKowalski, Kamil 1399e439f0f8SKowalski, Kamil private: 14000f74e643SEd Tanous void parseInterfaceData( 14010f74e643SEd Tanous nlohmann::json &json_response, const std::string &parent_iface_id, 14020f74e643SEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 14034a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 14041abe55efSEd Tanous { 1405e439f0f8SKowalski, Kamil // Fill out obvious data... 14064a0cb85cSEd Tanous json_response["Id"] = iface_id; 14074a0cb85cSEd Tanous json_response["@odata.id"] = 14084a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 14094a0cb85cSEd Tanous "/VLANs/" + iface_id; 1410e439f0f8SKowalski, Kamil 14114a0cb85cSEd Tanous json_response["VLANEnable"] = true; 14124a0cb85cSEd Tanous if (ethData.vlan_id) 14134a0cb85cSEd Tanous { 14144a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 14154a0cb85cSEd Tanous } 1416e439f0f8SKowalski, Kamil } 1417e439f0f8SKowalski, Kamil 141855c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 14191abe55efSEd Tanous const std::string &iface) 14201abe55efSEd Tanous { 1421f12894f8SJason M. Bills std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14221abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 14231abe55efSEd Tanous { 1424f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1425f12894f8SJason M. Bills iface); 1426927a505aSKowalski, Kamil return false; 14271abe55efSEd Tanous } 14281abe55efSEd Tanous else 14291abe55efSEd Tanous { 1430927a505aSKowalski, Kamil return true; 1431927a505aSKowalski, Kamil } 1432927a505aSKowalski, Kamil } 1433927a505aSKowalski, Kamil 1434e439f0f8SKowalski, Kamil /** 1435e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1436e439f0f8SKowalski, Kamil */ 143755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 14381abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14391abe55efSEd Tanous { 14404a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14414a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1442e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1443e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1444e439f0f8SKowalski, Kamil // impossible. 14451abe55efSEd Tanous if (params.size() != 2) 14461abe55efSEd Tanous { 1447f12894f8SJason M. Bills messages::internalError(res); 1448e439f0f8SKowalski, Kamil res.end(); 1449e439f0f8SKowalski, Kamil return; 1450e439f0f8SKowalski, Kamil } 1451e439f0f8SKowalski, Kamil 14524a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 14534a0cb85cSEd Tanous const std::string &iface_id = params[1]; 14540f74e643SEd Tanous res.jsonValue["@odata.type"] = 14550f74e643SEd Tanous "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 14560f74e643SEd Tanous res.jsonValue["@odata.context"] = 14570f74e643SEd Tanous "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 14580f74e643SEd Tanous res.jsonValue["Name"] = "VLAN Network Interface"; 1459e439f0f8SKowalski, Kamil 14604a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 14611abe55efSEd Tanous { 1462a434f2bdSEd Tanous return; 1463a434f2bdSEd Tanous } 1464a434f2bdSEd Tanous 1465e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1466e439f0f8SKowalski, Kamil // preparation 14674a0cb85cSEd Tanous getEthernetIfaceData( 14684a0cb85cSEd Tanous iface_id, 14694a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 14704a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 14714a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 14724a0cb85cSEd Tanous if (success && ethData.vlan_id) 14731abe55efSEd Tanous { 14740f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, 14750f74e643SEd Tanous parent_iface_id, iface_id, ethData, 14760f74e643SEd Tanous ipv4Data); 14771abe55efSEd Tanous } 14781abe55efSEd Tanous else 14791abe55efSEd Tanous { 1480e439f0f8SKowalski, Kamil // ... otherwise return error 14811abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 14821abe55efSEd Tanous // object, and other errors 1483f12894f8SJason M. Bills messages::resourceNotFound( 1484f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1485e439f0f8SKowalski, Kamil } 1486e439f0f8SKowalski, Kamil }); 1487e439f0f8SKowalski, Kamil } 1488e439f0f8SKowalski, Kamil 148955c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 14901abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14911abe55efSEd Tanous { 14924a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14931abe55efSEd Tanous if (params.size() != 2) 14941abe55efSEd Tanous { 1495f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1496e439f0f8SKowalski, Kamil return; 1497e439f0f8SKowalski, Kamil } 1498e439f0f8SKowalski, Kamil 1499d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 150055c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1501927a505aSKowalski, Kamil 15021abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 15031abe55efSEd Tanous { 1504927a505aSKowalski, Kamil return; 1505927a505aSKowalski, Kamil } 1506927a505aSKowalski, Kamil 15070627a2c7SEd Tanous bool vlanEnable = false; 15080627a2c7SEd Tanous uint64_t vlanId = 0; 15090627a2c7SEd Tanous 15100627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId", 15110627a2c7SEd Tanous vlanId)) 15121abe55efSEd Tanous { 1513927a505aSKowalski, Kamil return; 1514927a505aSKowalski, Kamil } 1515927a505aSKowalski, Kamil 1516927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1517927a505aSKowalski, Kamil // preparation 15184a0cb85cSEd Tanous getEthernetIfaceData( 15191abe55efSEd Tanous ifaceId, 15200627a2c7SEd Tanous [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId]( 15214a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15224a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15231abe55efSEd Tanous if (!success) 15241abe55efSEd Tanous { 15251abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15261abe55efSEd Tanous // object, and other errors 1527f12894f8SJason M. Bills messages::resourceNotFound( 1528f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1529927a505aSKowalski, Kamil 1530927a505aSKowalski, Kamil return; 1531927a505aSKowalski, Kamil } 1532927a505aSKowalski, Kamil 15330f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15340f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1535927a505aSKowalski, Kamil 15360627a2c7SEd Tanous EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable, 15370627a2c7SEd Tanous ethData, asyncResp); 1538927a505aSKowalski, Kamil }); 1539e439f0f8SKowalski, Kamil } 1540e439f0f8SKowalski, Kamil 154155c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 15421abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15431abe55efSEd Tanous { 15444a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15451abe55efSEd Tanous if (params.size() != 2) 15461abe55efSEd Tanous { 1547f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1548e439f0f8SKowalski, Kamil return; 1549e439f0f8SKowalski, Kamil } 1550e439f0f8SKowalski, Kamil 1551d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 155255c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1553927a505aSKowalski, Kamil 15544a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 15551abe55efSEd Tanous { 1556927a505aSKowalski, Kamil return; 1557927a505aSKowalski, Kamil } 1558927a505aSKowalski, Kamil 1559927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1560927a505aSKowalski, Kamil // preparation 1561f12894f8SJason M. Bills getEthernetIfaceData( 1562f12894f8SJason M. Bills ifaceId, 1563f12894f8SJason M. Bills [this, asyncResp, parentIfaceId{std::string(parentIfaceId)}, 15644a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1565f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1566f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15674a0cb85cSEd Tanous if (success && ethData.vlan_id) 15681abe55efSEd Tanous { 15690f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15700f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1571927a505aSKowalski, Kamil 1572f12894f8SJason M. Bills auto callback = 1573f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 15741abe55efSEd Tanous if (ec) 15751abe55efSEd Tanous { 1576f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1577927a505aSKowalski, Kamil } 15784a0cb85cSEd Tanous }; 15794a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 15804a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 15814a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 15824a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 15831abe55efSEd Tanous } 15841abe55efSEd Tanous else 15851abe55efSEd Tanous { 1586927a505aSKowalski, Kamil // ... otherwise return error 1587f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1588f12894f8SJason M. Bills // object, and other errors 1589f12894f8SJason M. Bills messages::resourceNotFound( 1590f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1591927a505aSKowalski, Kamil } 1592927a505aSKowalski, Kamil }); 1593e439f0f8SKowalski, Kamil } 1594e439f0f8SKowalski, Kamil }; 1595e439f0f8SKowalski, Kamil 1596e439f0f8SKowalski, Kamil /** 1597e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1598e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1599e439f0f8SKowalski, Kamil */ 16001abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 16011abe55efSEd Tanous { 1602e439f0f8SKowalski, Kamil public: 1603e439f0f8SKowalski, Kamil template <typename CrowApp> 16041abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 16054a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 16064a0cb85cSEd Tanous std::string()) 16071abe55efSEd Tanous { 1608e439f0f8SKowalski, Kamil entityPrivileges = { 1609e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1610e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1611e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1612e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1613e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1614e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1615e439f0f8SKowalski, Kamil } 1616e439f0f8SKowalski, Kamil 1617e439f0f8SKowalski, Kamil private: 1618e439f0f8SKowalski, Kamil /** 1619e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1620e439f0f8SKowalski, Kamil */ 162155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 16221abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16231abe55efSEd Tanous { 16244a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16251abe55efSEd Tanous if (params.size() != 1) 16261abe55efSEd Tanous { 1627e439f0f8SKowalski, Kamil // This means there is a problem with the router 1628f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1629e439f0f8SKowalski, Kamil return; 1630e439f0f8SKowalski, Kamil } 1631e439f0f8SKowalski, Kamil 16324a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1633e439f0f8SKowalski, Kamil 16344a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 16351abe55efSEd Tanous // preparation 1636f12894f8SJason M. Bills getEthernetIfaceList( 1637f12894f8SJason M. Bills [this, asyncResp, 1638f12894f8SJason M. Bills rootInterfaceName{std::string(rootInterfaceName)}]( 16391abe55efSEd Tanous const bool &success, 16401abe55efSEd Tanous const std::vector<std::string> &iface_list) { 16414a0cb85cSEd Tanous if (!success) 16421abe55efSEd Tanous { 1643f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16444a0cb85cSEd Tanous return; 16451abe55efSEd Tanous } 16460f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 16470f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 16480f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 16490f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 16500f74e643SEd Tanous "/redfish/v1/$metadata" 16510f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 16520f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 16530f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = 16540f74e643SEd Tanous "VLAN Network Interface Collection"; 16554a0cb85cSEd Tanous 16564a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 16574a0cb85cSEd Tanous 16584a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 16591abe55efSEd Tanous { 16604a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 16614a0cb85cSEd Tanous { 16624a0cb85cSEd Tanous iface_array.push_back( 16634a0cb85cSEd Tanous {{"@odata.id", 16644a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 16654a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1666e439f0f8SKowalski, Kamil } 1667e439f0f8SKowalski, Kamil } 1668e439f0f8SKowalski, Kamil 16694a0cb85cSEd Tanous if (iface_array.empty()) 16701abe55efSEd Tanous { 1671f12894f8SJason M. Bills messages::resourceNotFound( 1672f12894f8SJason M. Bills asyncResp->res, "EthernetInterface", rootInterfaceName); 16734a0cb85cSEd Tanous return; 1674e439f0f8SKowalski, Kamil } 16754a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 16764a0cb85cSEd Tanous iface_array.size(); 16774a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 16784a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 16794a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 16804a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1681e439f0f8SKowalski, Kamil }); 1682e439f0f8SKowalski, Kamil } 1683e439f0f8SKowalski, Kamil 168455c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 16851abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16861abe55efSEd Tanous { 16874a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16881abe55efSEd Tanous if (params.size() != 1) 16891abe55efSEd Tanous { 1690f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1691e439f0f8SKowalski, Kamil return; 1692e439f0f8SKowalski, Kamil } 1693e439f0f8SKowalski, Kamil 16940627a2c7SEd Tanous uint32_t vlanId = 0; 16950627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANId", vlanId)) 16961abe55efSEd Tanous { 16974a0cb85cSEd Tanous return; 1698e439f0f8SKowalski, Kamil } 16994a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 17004a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 17011abe55efSEd Tanous if (ec) 17021abe55efSEd Tanous { 17034a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 17044a0cb85cSEd Tanous // phosphor-network responses 1705f12894f8SJason M. Bills messages::internalError(asyncResp->res); 17064a0cb85cSEd Tanous return; 17071abe55efSEd Tanous } 1708f12894f8SJason M. Bills messages::created(asyncResp->res); 1709e439f0f8SKowalski, Kamil }; 17104a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 17114a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 17124a0cb85cSEd Tanous "/xyz/openbmc_project/network", 17134a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 17140627a2c7SEd Tanous rootInterfaceName, vlanId); 17154a0cb85cSEd Tanous } 17164a0cb85cSEd Tanous }; 17179391bb9cSRapkiewicz, Pawel } // namespace redfish 1718