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> 204a0cb85cSEd Tanous #include <boost/optional.hpp> 21179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 22588c3f0dSKowalski, Kamil #include <error_messages.hpp> 23179db1d7SKowalski, Kamil #include <node.hpp> 24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 259391bb9cSRapkiewicz, Pawel 261abe55efSEd Tanous namespace redfish 271abe55efSEd Tanous { 289391bb9cSRapkiewicz, Pawel 299391bb9cSRapkiewicz, Pawel /** 309391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 319391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 329391bb9cSRapkiewicz, Pawel */ 33aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 34aa2e59c1SEd Tanous std::string, 35aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 36aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 379391bb9cSRapkiewicz, Pawel 384a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair< 39aa2e59c1SEd Tanous sdbusplus::message::object_path, 404a0cb85cSEd Tanous std::vector<std::pair< 41aa2e59c1SEd Tanous std::string, 42aa2e59c1SEd Tanous boost::container::flat_map< 43aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 44aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 454a0cb85cSEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>>>>>; 464a0cb85cSEd Tanous 474a0cb85cSEd Tanous enum class LinkType 484a0cb85cSEd Tanous { 494a0cb85cSEd Tanous Local, 504a0cb85cSEd Tanous Global 514a0cb85cSEd Tanous }; 529391bb9cSRapkiewicz, Pawel 539391bb9cSRapkiewicz, Pawel /** 549391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 559391bb9cSRapkiewicz, Pawel */ 561abe55efSEd Tanous struct IPv4AddressData 571abe55efSEd Tanous { 58179db1d7SKowalski, Kamil std::string id; 594a0cb85cSEd Tanous std::string address; 604a0cb85cSEd Tanous std::string domain; 614a0cb85cSEd Tanous std::string gateway; 629391bb9cSRapkiewicz, Pawel std::string netmask; 639391bb9cSRapkiewicz, Pawel std::string origin; 644a0cb85cSEd Tanous LinkType linktype; 654a0cb85cSEd Tanous 661abe55efSEd Tanous bool operator<(const IPv4AddressData &obj) const 671abe55efSEd Tanous { 684a0cb85cSEd Tanous return id < obj.id; 691abe55efSEd Tanous } 709391bb9cSRapkiewicz, Pawel }; 719391bb9cSRapkiewicz, Pawel 729391bb9cSRapkiewicz, Pawel /** 739391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 749391bb9cSRapkiewicz, Pawel * available from DBus 759391bb9cSRapkiewicz, Pawel */ 761abe55efSEd Tanous struct EthernetInterfaceData 771abe55efSEd Tanous { 784a0cb85cSEd Tanous uint32_t speed; 794a0cb85cSEd Tanous bool auto_neg; 804a0cb85cSEd Tanous std::string hostname; 814a0cb85cSEd Tanous std::string default_gateway; 824a0cb85cSEd Tanous std::string mac_address; 834a0cb85cSEd Tanous boost::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 = 1744a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 1754a0cb85cSEd Tanous propertyPair.second); 1764a0cb85cSEd Tanous if (mac != nullptr) 1774a0cb85cSEd Tanous { 1784a0cb85cSEd Tanous ethData.mac_address = *mac; 1794a0cb85cSEd Tanous } 1804a0cb85cSEd Tanous } 1814a0cb85cSEd Tanous } 1824a0cb85cSEd Tanous } 1834a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1844a0cb85cSEd Tanous { 1854a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1864a0cb85cSEd Tanous { 1874a0cb85cSEd Tanous if (propertyPair.first == "Id") 1884a0cb85cSEd Tanous { 1894a0cb85cSEd Tanous const uint32_t *id = mapbox::getPtr<const uint32_t>( 1904a0cb85cSEd Tanous propertyPair.second); 1914a0cb85cSEd Tanous if (id != nullptr) 1924a0cb85cSEd Tanous { 1934a0cb85cSEd Tanous ethData.vlan_id = *id; 1944a0cb85cSEd Tanous } 1954a0cb85cSEd Tanous } 1964a0cb85cSEd Tanous } 1974a0cb85cSEd Tanous } 1984a0cb85cSEd Tanous else if (ifacePair.first == 1994a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 2004a0cb85cSEd Tanous { 2014a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2024a0cb85cSEd Tanous { 2034a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 2044a0cb85cSEd Tanous { 2054a0cb85cSEd Tanous const bool *auto_neg = 2064a0cb85cSEd Tanous mapbox::getPtr<const bool>(propertyPair.second); 2074a0cb85cSEd Tanous if (auto_neg != nullptr) 2084a0cb85cSEd Tanous { 2094a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2104a0cb85cSEd Tanous } 2114a0cb85cSEd Tanous } 2124a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2134a0cb85cSEd Tanous { 2144a0cb85cSEd Tanous const uint32_t *speed = 2154a0cb85cSEd Tanous mapbox::getPtr<const uint32_t>( 2164a0cb85cSEd Tanous propertyPair.second); 2174a0cb85cSEd Tanous if (speed != nullptr) 2184a0cb85cSEd Tanous { 2194a0cb85cSEd Tanous ethData.speed = *speed; 2204a0cb85cSEd Tanous } 2214a0cb85cSEd Tanous } 2224a0cb85cSEd Tanous } 2234a0cb85cSEd Tanous } 2244a0cb85cSEd Tanous else if (ifacePair.first == 2254a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2264a0cb85cSEd Tanous { 2274a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2284a0cb85cSEd Tanous { 2294a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2304a0cb85cSEd Tanous { 2314a0cb85cSEd Tanous const std::string *hostname = 2324a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 2334a0cb85cSEd Tanous propertyPair.second); 2344a0cb85cSEd Tanous if (hostname != nullptr) 2354a0cb85cSEd Tanous { 2364a0cb85cSEd Tanous ethData.hostname = *hostname; 2374a0cb85cSEd Tanous } 2384a0cb85cSEd Tanous } 2394a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2404a0cb85cSEd Tanous { 2414a0cb85cSEd Tanous const std::string *defaultGateway = 2424a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 2434a0cb85cSEd Tanous propertyPair.second); 2444a0cb85cSEd Tanous if (defaultGateway != nullptr) 2454a0cb85cSEd Tanous { 2464a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2474a0cb85cSEd Tanous } 2484a0cb85cSEd Tanous } 2494a0cb85cSEd Tanous } 2504a0cb85cSEd Tanous } 2514a0cb85cSEd Tanous } 2524a0cb85cSEd Tanous } 2534a0cb85cSEd Tanous } 2544a0cb85cSEd Tanous } 2554a0cb85cSEd Tanous 2564a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2574a0cb85cSEd Tanous inline void 2584a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2594a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2604a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2614a0cb85cSEd Tanous { 2624a0cb85cSEd Tanous const std::string ipv4PathStart = 2634a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 2644a0cb85cSEd Tanous 2654a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 2664a0cb85cSEd Tanous // single ethernet interface, loop over all of them 2674a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 2684a0cb85cSEd Tanous { 2694a0cb85cSEd Tanous // Check if proper pattern for object path appears 2704a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 2714a0cb85cSEd Tanous { 2724a0cb85cSEd Tanous for (auto &interface : objpath.second) 2734a0cb85cSEd Tanous { 2744a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 2754a0cb85cSEd Tanous { 2764a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 2774a0cb85cSEd Tanous // appropriate 2784a0cb85cSEd Tanous std::pair< 2794a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 2804a0cb85cSEd Tanous bool> 2814a0cb85cSEd Tanous it = ipv4_config.insert( 2824a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 2834a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 2844a0cb85cSEd Tanous for (auto &property : interface.second) 2854a0cb85cSEd Tanous { 2864a0cb85cSEd Tanous if (property.first == "Address") 2874a0cb85cSEd Tanous { 2884a0cb85cSEd Tanous const std::string *address = 2894a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 2904a0cb85cSEd Tanous property.second); 2914a0cb85cSEd Tanous if (address != nullptr) 2924a0cb85cSEd Tanous { 2934a0cb85cSEd Tanous ipv4_address.address = *address; 2944a0cb85cSEd Tanous } 2954a0cb85cSEd Tanous } 2964a0cb85cSEd Tanous else if (property.first == "Gateway") 2974a0cb85cSEd Tanous { 2984a0cb85cSEd Tanous const std::string *gateway = 2994a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 3004a0cb85cSEd Tanous property.second); 3014a0cb85cSEd Tanous if (gateway != nullptr) 3024a0cb85cSEd Tanous { 3034a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 3044a0cb85cSEd Tanous } 3054a0cb85cSEd Tanous } 3064a0cb85cSEd Tanous else if (property.first == "Origin") 3074a0cb85cSEd Tanous { 3084a0cb85cSEd Tanous const std::string *origin = 3094a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 3104a0cb85cSEd Tanous property.second); 3114a0cb85cSEd Tanous if (origin != nullptr) 3124a0cb85cSEd Tanous { 3134a0cb85cSEd Tanous ipv4_address.origin = 3144a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3154a0cb85cSEd Tanous true); 3164a0cb85cSEd Tanous } 3174a0cb85cSEd Tanous } 3184a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3194a0cb85cSEd Tanous { 3204a0cb85cSEd Tanous const uint8_t *mask = 3214a0cb85cSEd Tanous mapbox::getPtr<uint8_t>(property.second); 3224a0cb85cSEd Tanous if (mask != nullptr) 3234a0cb85cSEd Tanous { 3244a0cb85cSEd Tanous // convert it to the string 3254a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3264a0cb85cSEd Tanous } 3274a0cb85cSEd Tanous } 3284a0cb85cSEd Tanous else 3294a0cb85cSEd Tanous { 3304a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3314a0cb85cSEd Tanous << "Got extra property: " << property.first 3324a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3334a0cb85cSEd Tanous } 3344a0cb85cSEd Tanous } 3354a0cb85cSEd Tanous // Check if given address is local, or global 3364a0cb85cSEd Tanous ipv4_address.linktype = 3374a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3384a0cb85cSEd Tanous ? LinkType::Global 3394a0cb85cSEd Tanous : LinkType::Local; 3404a0cb85cSEd Tanous } 3414a0cb85cSEd Tanous } 3424a0cb85cSEd Tanous } 3434a0cb85cSEd Tanous } 3444a0cb85cSEd Tanous } 345588c3f0dSKowalski, Kamil 346588c3f0dSKowalski, Kamil /** 347588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 348588c3f0dSKowalski, Kamil * 349588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 350588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 351588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 352588c3f0dSKowalski, Kamil * 353588c3f0dSKowalski, Kamil * @return None. 354588c3f0dSKowalski, Kamil */ 355588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3564a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3571abe55efSEd Tanous CallbackFunc &&callback) 3581abe55efSEd Tanous { 35955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 360588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 361588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 362588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 363588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 364588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 3654a0cb85cSEd Tanous } 366588c3f0dSKowalski, Kamil 367588c3f0dSKowalski, Kamil /** 368179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 369179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 370179db1d7SKowalski, Kamil * bit count for Subnet Mask. 371179db1d7SKowalski, Kamil * 372179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 373179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 374179db1d7SKowalski, Kamil * 375179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 376179db1d7SKowalski, Kamil */ 3774a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3781abe55efSEd Tanous uint8_t *bits = nullptr) 3791abe55efSEd Tanous { 380179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 381179db1d7SKowalski, Kamil 382179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 383179db1d7SKowalski, Kamil 3844a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 3851abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 3861abe55efSEd Tanous { 387179db1d7SKowalski, Kamil return false; 388179db1d7SKowalski, Kamil } 389179db1d7SKowalski, Kamil 3901abe55efSEd Tanous if (bits != nullptr) 3911abe55efSEd Tanous { 392179db1d7SKowalski, Kamil *bits = 0; 393179db1d7SKowalski, Kamil } 394179db1d7SKowalski, Kamil 395179db1d7SKowalski, Kamil char *endPtr; 396179db1d7SKowalski, Kamil long previousValue = 255; 397179db1d7SKowalski, Kamil bool firstZeroInByteHit; 3981abe55efSEd Tanous for (const std::string &byte : bytesInMask) 3991abe55efSEd Tanous { 4001abe55efSEd Tanous if (byte.empty()) 4011abe55efSEd Tanous { 4021db9ca37SKowalski, Kamil return false; 4031db9ca37SKowalski, Kamil } 4041db9ca37SKowalski, Kamil 405179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4061db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 407179db1d7SKowalski, Kamil 4084a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4094a0cb85cSEd Tanous // is not 100% number 4101abe55efSEd Tanous if (*endPtr != '\0') 4111abe55efSEd Tanous { 412179db1d7SKowalski, Kamil return false; 413179db1d7SKowalski, Kamil } 414179db1d7SKowalski, Kamil 415179db1d7SKowalski, Kamil // Value should be contained in byte 4161abe55efSEd Tanous if (value < 0 || value > 255) 4171abe55efSEd Tanous { 418179db1d7SKowalski, Kamil return false; 419179db1d7SKowalski, Kamil } 420179db1d7SKowalski, Kamil 4211abe55efSEd Tanous if (bits != nullptr) 4221abe55efSEd Tanous { 423179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4241abe55efSEd Tanous if (previousValue != 255 && value != 0) 4251abe55efSEd Tanous { 426179db1d7SKowalski, Kamil return false; 427179db1d7SKowalski, Kamil } 428179db1d7SKowalski, Kamil 429179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 430179db1d7SKowalski, Kamil firstZeroInByteHit = false; 431179db1d7SKowalski, Kamil 432179db1d7SKowalski, Kamil // Count bits 4331abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4341abe55efSEd Tanous { 4351abe55efSEd Tanous if (value & (1 << bitIdx)) 4361abe55efSEd Tanous { 4371abe55efSEd Tanous if (firstZeroInByteHit) 4381abe55efSEd Tanous { 439179db1d7SKowalski, Kamil // Continuity not preserved 440179db1d7SKowalski, Kamil return false; 4411abe55efSEd Tanous } 4421abe55efSEd Tanous else 4431abe55efSEd Tanous { 444179db1d7SKowalski, Kamil (*bits)++; 445179db1d7SKowalski, Kamil } 4461abe55efSEd Tanous } 4471abe55efSEd Tanous else 4481abe55efSEd Tanous { 449179db1d7SKowalski, Kamil firstZeroInByteHit = true; 450179db1d7SKowalski, Kamil } 451179db1d7SKowalski, Kamil } 452179db1d7SKowalski, Kamil } 453179db1d7SKowalski, Kamil 454179db1d7SKowalski, Kamil previousValue = value; 455179db1d7SKowalski, Kamil } 456179db1d7SKowalski, Kamil 457179db1d7SKowalski, Kamil return true; 458179db1d7SKowalski, Kamil } 459179db1d7SKowalski, Kamil 460179db1d7SKowalski, Kamil /** 461179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 462179db1d7SKowalski, Kamil * 463179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4644a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 465179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 466179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 467179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 468179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 469179db1d7SKowalski, Kamil * 470179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 471179db1d7SKowalski, Kamil * otherwise 472179db1d7SKowalski, Kamil */ 4734a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 4744a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 4754a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 4764a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4771abe55efSEd Tanous { 4784a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 4794a0cb85cSEd Tanous newValue{std::move(newValue)}]( 4801abe55efSEd Tanous const boost::system::error_code ec) { 4811abe55efSEd Tanous if (ec) 4821abe55efSEd Tanous { 483*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/IPv4Addresses/" + 484*f12894f8SJason M. Bills std::to_string(ipIdx) + 485*f12894f8SJason M. Bills "/" + name); 4861abe55efSEd Tanous } 4871abe55efSEd Tanous else 4881abe55efSEd Tanous { 4894a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 490179db1d7SKowalski, Kamil } 491179db1d7SKowalski, Kamil }; 492179db1d7SKowalski, Kamil 49355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 494179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 495179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 496179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 497179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 498179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 4994a0cb85cSEd Tanous } 500179db1d7SKowalski, Kamil 501179db1d7SKowalski, Kamil /** 502179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 503179db1d7SKowalski, Kamil * 504179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5054a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5061abe55efSEd Tanous * modified 507179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 508179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 509179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 510179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 511179db1d7SKowalski, Kamil * 512179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 513179db1d7SKowalski, Kamil * otherwise 514179db1d7SKowalski, Kamil */ 5154a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5161abe55efSEd Tanous const std::string &ipHash, 5171abe55efSEd Tanous const std::string &newValue, 518179db1d7SKowalski, Kamil const std::string &newValueDbus, 5194a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5201abe55efSEd Tanous { 5214a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5221abe55efSEd Tanous const boost::system::error_code ec) { 5231abe55efSEd Tanous if (ec) 5241abe55efSEd Tanous { 525*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/IPv4Addresses/" + 526*f12894f8SJason M. Bills std::to_string(ipIdx) + 527*f12894f8SJason M. Bills "/AddressOrigin"); 5281abe55efSEd Tanous } 5291abe55efSEd Tanous else 5301abe55efSEd Tanous { 5314a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 532179db1d7SKowalski, Kamil newValue; 533179db1d7SKowalski, Kamil } 534179db1d7SKowalski, Kamil }; 535179db1d7SKowalski, Kamil 53655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 537179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 538179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 539179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 540179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 541179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 5424a0cb85cSEd Tanous } 543179db1d7SKowalski, Kamil 544179db1d7SKowalski, Kamil /** 545179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 546179db1d7SKowalski, Kamil * 547179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5484a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5491abe55efSEd Tanous * modified 550179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 551179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 552179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 553179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 554179db1d7SKowalski, Kamil * 555179db1d7SKowalski, Kamil * @return None 556179db1d7SKowalski, Kamil */ 5574a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5584a0cb85cSEd Tanous const std::string &ipHash, 5594a0cb85cSEd Tanous const std::string &newValueStr, 5604a0cb85cSEd Tanous uint8_t &newValue, 5614a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5621abe55efSEd Tanous { 5634a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5641abe55efSEd Tanous const boost::system::error_code ec) { 5651abe55efSEd Tanous if (ec) 5661abe55efSEd Tanous { 567*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/IPv4Addresses/" + 568*f12894f8SJason M. Bills std::to_string(ipIdx) + 569*f12894f8SJason M. Bills "/SubnetMask"); 5701abe55efSEd Tanous } 5711abe55efSEd Tanous else 5721abe55efSEd Tanous { 57355c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 574179db1d7SKowalski, Kamil newValueStr; 575179db1d7SKowalski, Kamil } 576179db1d7SKowalski, Kamil }; 577179db1d7SKowalski, Kamil 57855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 579179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 580179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 581179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 582179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 583179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 5844a0cb85cSEd Tanous } 585588c3f0dSKowalski, Kamil 586588c3f0dSKowalski, Kamil /** 587588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 588588c3f0dSKowalski, Kamil * 589588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 590588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 591588c3f0dSKowalski, Kamil * 592588c3f0dSKowalski, Kamil * @return None. 593588c3f0dSKowalski, Kamil */ 594588c3f0dSKowalski, Kamil template <typename CallbackFunc> 5951abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback) 5961abe55efSEd Tanous { 59755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 598588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 599588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 600588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 601588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 602588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 6034a0cb85cSEd Tanous } 604588c3f0dSKowalski, Kamil 605588c3f0dSKowalski, Kamil /** 606179db1d7SKowalski, Kamil * @brief Deletes given IPv4 607179db1d7SKowalski, Kamil * 608179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6094a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 610179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 611179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 612179db1d7SKowalski, Kamil * 613179db1d7SKowalski, Kamil * @return None 614179db1d7SKowalski, Kamil */ 6154a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 616179db1d7SKowalski, Kamil unsigned int ipIdx, 6174a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6181abe55efSEd Tanous { 61955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6204a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6211abe55efSEd Tanous if (ec) 6221abe55efSEd Tanous { 623*f12894f8SJason M. Bills messages::internalError(asyncResp->res, 624*f12894f8SJason M. Bills "/IPv4Addresses/" + 625*f12894f8SJason M. Bills std::to_string(ipIdx) + "/"); 6261abe55efSEd Tanous } 6271abe55efSEd Tanous else 6281abe55efSEd Tanous { 62955c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 630179db1d7SKowalski, Kamil } 631179db1d7SKowalski, Kamil }, 632179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 633179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 634179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 635179db1d7SKowalski, Kamil } 636179db1d7SKowalski, Kamil 637179db1d7SKowalski, Kamil /** 638179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 639179db1d7SKowalski, Kamil * 640179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6414a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 642179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 643179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 644179db1d7SKowalski, Kamil * 645179db1d7SKowalski, Kamil * @return None 646179db1d7SKowalski, Kamil */ 6474a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 648179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 649179db1d7SKowalski, Kamil const std::string &address, 6504a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6511abe55efSEd Tanous { 6524a0cb85cSEd Tanous auto createIpHandler = [ipIdx, 6534a0cb85cSEd Tanous asyncResp](const boost::system::error_code ec) { 6541abe55efSEd Tanous if (ec) 6551abe55efSEd Tanous { 656*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/IPv4Addresses/" + 657*f12894f8SJason M. Bills std::to_string(ipIdx) + 658*f12894f8SJason M. Bills "/"); 659179db1d7SKowalski, Kamil } 660179db1d7SKowalski, Kamil }; 661179db1d7SKowalski, Kamil 66255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 663179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 664179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 665179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 666179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 667179db1d7SKowalski, Kamil gateway); 668179db1d7SKowalski, Kamil } 669179db1d7SKowalski, Kamil 670179db1d7SKowalski, Kamil /** 671179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 672179db1d7SKowalski, Kamil * Object 673179db1d7SKowalski, Kamil * from EntityManager Network Manager 6744a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 675179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 676179db1d7SKowalski, Kamil * into JSON 677179db1d7SKowalski, Kamil */ 678179db1d7SKowalski, Kamil template <typename CallbackFunc> 6794a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 6801abe55efSEd Tanous CallbackFunc &&callback) 6811abe55efSEd Tanous { 68255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6834a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 6841abe55efSEd Tanous const boost::system::error_code error_code, 6854a0cb85cSEd Tanous const GetManagedObjects &resp) { 68655c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 6874a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 688179db1d7SKowalski, Kamil 6891abe55efSEd Tanous if (error_code) 6901abe55efSEd Tanous { 69155c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 692179db1d7SKowalski, Kamil return; 693179db1d7SKowalski, Kamil } 694179db1d7SKowalski, Kamil 6954a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 6964a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 697179db1d7SKowalski, Kamil 698179db1d7SKowalski, Kamil // Fix global GW 6991abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 7001abe55efSEd Tanous { 7014a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 7024a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 7031abe55efSEd Tanous { 7044a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 705179db1d7SKowalski, Kamil } 706179db1d7SKowalski, Kamil } 707179db1d7SKowalski, Kamil 7084a0cb85cSEd Tanous // Finally make a callback with usefull data 70955c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 710179db1d7SKowalski, Kamil }, 711179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 712179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 713179db1d7SKowalski, Kamil }; 714179db1d7SKowalski, Kamil 715179db1d7SKowalski, Kamil /** 7169391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7179391bb9cSRapkiewicz, Pawel * Manager 7181abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7191abe55efSEd Tanous * into JSON. 7209391bb9cSRapkiewicz, Pawel */ 7219391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7221abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7231abe55efSEd Tanous { 72455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7254a0cb85cSEd Tanous [callback{std::move(callback)}]( 7269391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 7274a0cb85cSEd Tanous GetManagedObjects &resp) { 7281abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7291abe55efSEd Tanous // ethernet interfaces 7304a0cb85cSEd Tanous std::vector<std::string> iface_list; 7314a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7321abe55efSEd Tanous if (error_code) 7331abe55efSEd Tanous { 7344a0cb85cSEd Tanous callback(false, iface_list); 7359391bb9cSRapkiewicz, Pawel return; 7369391bb9cSRapkiewicz, Pawel } 7379391bb9cSRapkiewicz, Pawel 7389391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7394a0cb85cSEd Tanous for (const auto &objpath : resp) 7401abe55efSEd Tanous { 7419391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7424a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7431abe55efSEd Tanous { 7441abe55efSEd Tanous // If interface is 7454a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 7464a0cb85cSEd Tanous // what we're looking for. 7479391bb9cSRapkiewicz, Pawel if (interface.first == 7481abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7491abe55efSEd Tanous { 7504a0cb85cSEd Tanous // Cut out everyting until last "/", ... 7514a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 7524a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 7534a0cb85cSEd Tanous if (last_pos != std::string::npos) 7541abe55efSEd Tanous { 7559391bb9cSRapkiewicz, Pawel // and put it into output vector. 7564a0cb85cSEd Tanous iface_list.emplace_back( 7574a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7589391bb9cSRapkiewicz, Pawel } 7599391bb9cSRapkiewicz, Pawel } 7609391bb9cSRapkiewicz, Pawel } 7619391bb9cSRapkiewicz, Pawel } 762a434f2bdSEd Tanous // Finally make a callback with useful data 7634a0cb85cSEd Tanous callback(true, iface_list); 7649391bb9cSRapkiewicz, Pawel }, 765aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 766aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7679391bb9cSRapkiewicz, Pawel }; 7689391bb9cSRapkiewicz, Pawel 7699391bb9cSRapkiewicz, Pawel /** 7709391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7719391bb9cSRapkiewicz, Pawel */ 7721abe55efSEd Tanous class EthernetCollection : public Node 7731abe55efSEd Tanous { 7749391bb9cSRapkiewicz, Pawel public: 7754a0cb85cSEd Tanous template <typename CrowApp> 7761abe55efSEd Tanous EthernetCollection(CrowApp &app) : 7774a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 7781abe55efSEd Tanous { 7799391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7809391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7819391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7829391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7839391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7844a0cb85cSEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7859391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7869391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7879391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7889391bb9cSRapkiewicz, Pawel 789588c3f0dSKowalski, Kamil entityPrivileges = { 790588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 791e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 792e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 793e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 794e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 795e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7969391bb9cSRapkiewicz, Pawel } 7979391bb9cSRapkiewicz, Pawel 7989391bb9cSRapkiewicz, Pawel private: 7999391bb9cSRapkiewicz, Pawel /** 8009391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 8019391bb9cSRapkiewicz, Pawel */ 80255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 8031abe55efSEd Tanous const std::vector<std::string> ¶ms) override 8041abe55efSEd Tanous { 8054a0cb85cSEd Tanous res.jsonValue = Node::json; 8064a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 8071abe55efSEd Tanous // preparation 808*f12894f8SJason M. Bills getEthernetIfaceList( 809*f12894f8SJason M. Bills [&res](const bool &success, 8101abe55efSEd Tanous const std::vector<std::string> &iface_list) { 8114a0cb85cSEd Tanous if (!success) 8121abe55efSEd Tanous { 813*f12894f8SJason M. Bills messages::internalError(res); 8144a0cb85cSEd Tanous res.end(); 8154a0cb85cSEd Tanous return; 8164a0cb85cSEd Tanous } 8174a0cb85cSEd Tanous 8184a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 8194a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 8204a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8211abe55efSEd Tanous { 8224a0cb85cSEd Tanous iface_array.push_back( 8234a0cb85cSEd Tanous {{"@odata.id", 8244a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 8254a0cb85cSEd Tanous iface_item}}); 8269391bb9cSRapkiewicz, Pawel } 8274a0cb85cSEd Tanous 8284a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 8294a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 8304a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8319391bb9cSRapkiewicz, Pawel res.end(); 8329391bb9cSRapkiewicz, Pawel }); 8339391bb9cSRapkiewicz, Pawel } 8349391bb9cSRapkiewicz, Pawel }; 8359391bb9cSRapkiewicz, Pawel 8369391bb9cSRapkiewicz, Pawel /** 8379391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8389391bb9cSRapkiewicz, Pawel */ 8391abe55efSEd Tanous class EthernetInterface : public Node 8401abe55efSEd Tanous { 8419391bb9cSRapkiewicz, Pawel public: 8429391bb9cSRapkiewicz, Pawel /* 8439391bb9cSRapkiewicz, Pawel * Default Constructor 8449391bb9cSRapkiewicz, Pawel */ 8454a0cb85cSEd Tanous template <typename CrowApp> 8461abe55efSEd Tanous EthernetInterface(CrowApp &app) : 8474a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8481abe55efSEd Tanous std::string()) 8491abe55efSEd Tanous { 8501abe55efSEd Tanous Node::json["@odata.type"] = 8511abe55efSEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 8529391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8539391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8549391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8559391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8569391bb9cSRapkiewicz, Pawel 857588c3f0dSKowalski, Kamil entityPrivileges = { 858588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 859e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 860e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 861e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 862e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 863e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8649391bb9cSRapkiewicz, Pawel } 8659391bb9cSRapkiewicz, Pawel 866e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 867e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 868e439f0f8SKowalski, Kamil const nlohmann::json &input, 8694a0cb85cSEd Tanous const EthernetInterfaceData ðData, 8704a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8711abe55efSEd Tanous { 8721abe55efSEd Tanous if (!input.is_object()) 8731abe55efSEd Tanous { 874*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 875*f12894f8SJason M. Bills "VLAN", "/"); 876588c3f0dSKowalski, Kamil return; 877588c3f0dSKowalski, Kamil } 878588c3f0dSKowalski, Kamil 8794a0cb85cSEd Tanous nlohmann::json::const_iterator vlanEnable = input.find("VLANEnable"); 8804a0cb85cSEd Tanous if (vlanEnable == input.end()) 8811abe55efSEd Tanous { 882*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "VLANEnable", 8834a0cb85cSEd Tanous "/VLANEnable"); 8844a0cb85cSEd Tanous return; 8854a0cb85cSEd Tanous } 8864a0cb85cSEd Tanous const bool *vlanEnableBool = vlanEnable->get_ptr<const bool *>(); 8874a0cb85cSEd Tanous if (vlanEnableBool == nullptr) 8884a0cb85cSEd Tanous { 889*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanEnable->dump(), 890*f12894f8SJason M. Bills "VLANEnable", "/VLANEnable"); 891588c3f0dSKowalski, Kamil return; 892588c3f0dSKowalski, Kamil } 893588c3f0dSKowalski, Kamil 8944a0cb85cSEd Tanous nlohmann::json::const_iterator vlanId = input.find("VLANId"); 8954a0cb85cSEd Tanous if (vlanId == input.end()) 8964a0cb85cSEd Tanous { 897*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "VLANId", "/VLANId"); 8984a0cb85cSEd Tanous return; 8994a0cb85cSEd Tanous } 9004a0cb85cSEd Tanous const uint64_t *vlanIdUint = vlanId->get_ptr<const uint64_t *>(); 9014a0cb85cSEd Tanous if (vlanIdUint == nullptr) 9024a0cb85cSEd Tanous { 903*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanId->dump(), 904*f12894f8SJason M. Bills "VLANId", "/VLANId"); 9054a0cb85cSEd Tanous return; 9064a0cb85cSEd Tanous } 9074a0cb85cSEd Tanous 9084a0cb85cSEd Tanous if (!ethData.vlan_id) 9091abe55efSEd Tanous { 910e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 911e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 912*f12894f8SJason M. Bills messages::propertyNotWritable(asyncResp->res, "VLANEnable", 913*f12894f8SJason M. Bills "/VLANEnable"); 914588c3f0dSKowalski, Kamil 915588c3f0dSKowalski, Kamil return; 916588c3f0dSKowalski, Kamil } 917588c3f0dSKowalski, Kamil 918588c3f0dSKowalski, Kamil // VLAN is configured on the interface 9194a0cb85cSEd Tanous if (*vlanEnableBool == true) 9201abe55efSEd Tanous { 921588c3f0dSKowalski, Kamil // Change VLAN Id 9224a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANId"] = *vlanIdUint; 9234a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9241abe55efSEd Tanous if (ec) 9251abe55efSEd Tanous { 926*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9271abe55efSEd Tanous } 9281abe55efSEd Tanous else 9291abe55efSEd Tanous { 9304a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 931e439f0f8SKowalski, Kamil } 9324a0cb85cSEd Tanous }; 9334a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9344a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9354a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9364a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 9374a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 9384a0cb85cSEd Tanous sdbusplus::message::variant<uint32_t>(*vlanIdUint)); 9391abe55efSEd Tanous } 9404a0cb85cSEd Tanous else 9411abe55efSEd Tanous { 9424a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9431abe55efSEd Tanous if (ec) 9441abe55efSEd Tanous { 945*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9464a0cb85cSEd Tanous return; 9471abe55efSEd Tanous } 9484a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 9494a0cb85cSEd Tanous }; 9504a0cb85cSEd Tanous 9514a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9524a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9534a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9544a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 955588c3f0dSKowalski, Kamil } 956588c3f0dSKowalski, Kamil } 957588c3f0dSKowalski, Kamil 958e439f0f8SKowalski, Kamil private: 959588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 9604a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9611abe55efSEd Tanous { 9624a0cb85cSEd Tanous const std::string *newHostname = input.get_ptr<const std::string *>(); 9634a0cb85cSEd Tanous if (newHostname == nullptr) 9641abe55efSEd Tanous { 965*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 966*f12894f8SJason M. Bills "HostName", "/HostName"); 9674a0cb85cSEd Tanous return; 9684a0cb85cSEd Tanous } 9694a0cb85cSEd Tanous 9704a0cb85cSEd Tanous // Change hostname 9714a0cb85cSEd Tanous setHostName( 9724a0cb85cSEd Tanous *newHostname, [asyncResp, newHostname{std::string(*newHostname)}]( 9734a0cb85cSEd Tanous const boost::system::error_code ec) { 9744a0cb85cSEd Tanous if (ec) 9754a0cb85cSEd Tanous { 976*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/HostName"); 9771abe55efSEd Tanous } 9781abe55efSEd Tanous else 9791abe55efSEd Tanous { 98055c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 981588c3f0dSKowalski, Kamil } 982588c3f0dSKowalski, Kamil }); 983588c3f0dSKowalski, Kamil } 984588c3f0dSKowalski, Kamil 9854a0cb85cSEd Tanous void handleIPv4Patch( 9864a0cb85cSEd Tanous const std::string &ifaceId, const nlohmann::json &input, 9874a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 9884a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9891abe55efSEd Tanous { 9901abe55efSEd Tanous if (!input.is_array()) 9911abe55efSEd Tanous { 992*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, input.dump(), 993*f12894f8SJason M. Bills "IPv4Addresses", "/IPv4Addresses"); 994179db1d7SKowalski, Kamil return; 995179db1d7SKowalski, Kamil } 996179db1d7SKowalski, Kamil 997179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 9984a0cb85cSEd Tanous if (input.size() < ipv4Data.size()) 9991abe55efSEd Tanous { 10001abe55efSEd Tanous // TODO(kkowalsk) This should be a message indicating that not 10011abe55efSEd Tanous // enough data has been provided 1002*f12894f8SJason M. Bills messages::internalError(asyncResp->res, "/IPv4Addresses"); 1003179db1d7SKowalski, Kamil return; 1004179db1d7SKowalski, Kamil } 1005179db1d7SKowalski, Kamil 10064a0cb85cSEd Tanous int entryIdx = 0; 10074a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 10084a0cb85cSEd Tanous ipv4Data.begin(); 10094a0cb85cSEd Tanous for (const nlohmann::json &thisJson : input) 10101abe55efSEd Tanous { 10114a0cb85cSEd Tanous std::string pathString = 10124a0cb85cSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx); 1013179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 10144a0cb85cSEd Tanous if (!thisJson.is_object() && !thisJson.is_null()) 10151abe55efSEd Tanous { 10164a0cb85cSEd Tanous messages::propertyValueTypeError( 1017*f12894f8SJason M. Bills asyncResp->res, thisJson.dump(), "IPv4Address", pathString); 1018179db1d7SKowalski, Kamil 1019179db1d7SKowalski, Kamil continue; 1020179db1d7SKowalski, Kamil } 1021179db1d7SKowalski, Kamil 10224a0cb85cSEd Tanous nlohmann::json::const_iterator addressFieldIt = 10234a0cb85cSEd Tanous thisJson.find("Address"); 10244a0cb85cSEd Tanous const std::string *addressField = nullptr; 10254a0cb85cSEd Tanous if (addressFieldIt != thisJson.end()) 10261abe55efSEd Tanous { 10274a0cb85cSEd Tanous addressField = addressFieldIt->get_ptr<const std::string *>(); 10284a0cb85cSEd Tanous if (addressField == nullptr) 10291abe55efSEd Tanous { 10304a0cb85cSEd Tanous messages::propertyValueFormatError( 1031*f12894f8SJason M. Bills asyncResp->res, addressFieldIt->dump(), "Address", 10324a0cb85cSEd Tanous pathString + "/Address"); 1033179db1d7SKowalski, Kamil continue; 1034179db1d7SKowalski, Kamil } 10351abe55efSEd Tanous else 10361abe55efSEd Tanous { 10374a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*addressField)) 10384a0cb85cSEd Tanous { 1039*f12894f8SJason M. Bills messages::propertyValueFormatError( 1040*f12894f8SJason M. Bills asyncResp->res, *addressField, "Address", 10414a0cb85cSEd Tanous pathString + "/Address"); 10424a0cb85cSEd Tanous continue; 10434a0cb85cSEd Tanous } 10444a0cb85cSEd Tanous } 10454a0cb85cSEd Tanous } 10464a0cb85cSEd Tanous 10474a0cb85cSEd Tanous boost::optional<uint8_t> prefixLength; 10484a0cb85cSEd Tanous const std::string *subnetField = nullptr; 10494a0cb85cSEd Tanous nlohmann::json::const_iterator subnetFieldIt = 10504a0cb85cSEd Tanous thisJson.find("SubnetMask"); 10514a0cb85cSEd Tanous if (subnetFieldIt != thisJson.end()) 10524a0cb85cSEd Tanous { 10534a0cb85cSEd Tanous subnetField = subnetFieldIt->get_ptr<const std::string *>(); 10544a0cb85cSEd Tanous if (subnetField == nullptr) 10554a0cb85cSEd Tanous { 1056*f12894f8SJason M. Bills messages::propertyValueFormatError( 1057*f12894f8SJason M. Bills asyncResp->res, *subnetField, "SubnetMask", 10584a0cb85cSEd Tanous pathString + "/SubnetMask"); 10594a0cb85cSEd Tanous continue; 10604a0cb85cSEd Tanous } 10614a0cb85cSEd Tanous else 10624a0cb85cSEd Tanous { 10634a0cb85cSEd Tanous prefixLength = 0; 10644a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetField, 10654a0cb85cSEd Tanous &*prefixLength)) 10664a0cb85cSEd Tanous { 1067*f12894f8SJason M. Bills messages::propertyValueFormatError( 1068*f12894f8SJason M. Bills asyncResp->res, *subnetField, "SubnetMask", 10694a0cb85cSEd Tanous pathString + "/SubnetMask"); 10704a0cb85cSEd Tanous continue; 10714a0cb85cSEd Tanous } 10724a0cb85cSEd Tanous } 10734a0cb85cSEd Tanous } 10744a0cb85cSEd Tanous 10754a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 10764a0cb85cSEd Tanous const std::string *addressOriginField = nullptr; 10774a0cb85cSEd Tanous nlohmann::json::const_iterator addressOriginFieldIt = 10784a0cb85cSEd Tanous thisJson.find("AddressOrigin"); 10794a0cb85cSEd Tanous if (addressOriginFieldIt != thisJson.end()) 10804a0cb85cSEd Tanous { 10814a0cb85cSEd Tanous const std::string *addressOriginField = 10824a0cb85cSEd Tanous addressOriginFieldIt->get_ptr<const std::string *>(); 10834a0cb85cSEd Tanous if (addressOriginField == nullptr) 10844a0cb85cSEd Tanous { 1085*f12894f8SJason M. Bills messages::propertyValueFormatError( 1086*f12894f8SJason M. Bills asyncResp->res, *addressOriginField, "AddressOrigin", 10874a0cb85cSEd Tanous pathString + "/AddressOrigin"); 10884a0cb85cSEd Tanous continue; 10894a0cb85cSEd Tanous } 10904a0cb85cSEd Tanous else 10914a0cb85cSEd Tanous { 10924a0cb85cSEd Tanous // Get Address origin in proper format 10934a0cb85cSEd Tanous addressOriginInDBusFormat = 10944a0cb85cSEd Tanous translateAddressOriginRedfishToDbus( 10954a0cb85cSEd Tanous *addressOriginField); 10964a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 10974a0cb85cSEd Tanous { 10984a0cb85cSEd Tanous messages::propertyValueNotInList( 1099*f12894f8SJason M. Bills asyncResp->res, *addressOriginField, 1100*f12894f8SJason M. Bills "AddressOrigin", pathString + "/AddressOrigin"); 11014a0cb85cSEd Tanous continue; 11024a0cb85cSEd Tanous } 11034a0cb85cSEd Tanous } 11044a0cb85cSEd Tanous } 11054a0cb85cSEd Tanous 11064a0cb85cSEd Tanous nlohmann::json::const_iterator gatewayFieldIt = 11074a0cb85cSEd Tanous thisJson.find("Gateway"); 11084a0cb85cSEd Tanous const std::string *gatewayField = nullptr; 11094a0cb85cSEd Tanous if (gatewayFieldIt != thisJson.end()) 11104a0cb85cSEd Tanous { 11114a0cb85cSEd Tanous const std::string *gatewayField = 11124a0cb85cSEd Tanous gatewayFieldIt->get_ptr<const std::string *>(); 11134a0cb85cSEd Tanous if (gatewayField == nullptr || 11144a0cb85cSEd Tanous !ipv4VerifyIpAndGetBitcount(*gatewayField)) 11154a0cb85cSEd Tanous { 1116*f12894f8SJason M. Bills messages::propertyValueFormatError(asyncResp->res, 1117*f12894f8SJason M. Bills *gatewayField, "Gateway", 11184a0cb85cSEd Tanous pathString + "/Gateway"); 11194a0cb85cSEd Tanous continue; 11204a0cb85cSEd Tanous } 11214a0cb85cSEd Tanous } 11224a0cb85cSEd Tanous 11234a0cb85cSEd Tanous // if a vlan already exists, modify the existing 11244a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 11254a0cb85cSEd Tanous { 11261abe55efSEd Tanous // Existing object that should be modified/deleted/remain 11271abe55efSEd Tanous // unchanged 11284a0cb85cSEd Tanous if (thisJson.is_null()) 11291abe55efSEd Tanous { 11304a0cb85cSEd Tanous auto callback = [entryIdx{std::to_string(entryIdx)}, 11314a0cb85cSEd Tanous asyncResp]( 11324a0cb85cSEd Tanous const boost::system::error_code ec) { 11334a0cb85cSEd Tanous if (ec) 11344a0cb85cSEd Tanous { 1135*f12894f8SJason M. Bills messages::internalError(asyncResp->res, 1136*f12894f8SJason M. Bills "/IPv4Addresses/" + 1137*f12894f8SJason M. Bills entryIdx + "/"); 11384a0cb85cSEd Tanous return; 11391abe55efSEd Tanous } 11404a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 11414a0cb85cSEd Tanous nullptr; 11424a0cb85cSEd Tanous }; 11434a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11444a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11454a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 11464a0cb85cSEd Tanous thisData->id, 11474a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 1148179db1d7SKowalski, Kamil } 11494a0cb85cSEd Tanous else if (thisJson.is_object()) 11504a0cb85cSEd Tanous { 1151179db1d7SKowalski, Kamil // Apply changes 11524a0cb85cSEd Tanous if (addressField != nullptr) 11531abe55efSEd Tanous { 11544a0cb85cSEd Tanous auto callback = 11554a0cb85cSEd Tanous [asyncResp, entryIdx, 11564a0cb85cSEd Tanous addressField{std::string(*addressField)}]( 11574a0cb85cSEd Tanous const boost::system::error_code ec) { 11584a0cb85cSEd Tanous if (ec) 11591abe55efSEd Tanous { 1160*f12894f8SJason M. Bills messages::internalError( 1161*f12894f8SJason M. Bills asyncResp->res, 11624a0cb85cSEd Tanous "/IPv4Addresses/" + 11634a0cb85cSEd Tanous std::to_string(entryIdx) + 11644a0cb85cSEd Tanous "/Address"); 11654a0cb85cSEd Tanous return; 11664a0cb85cSEd Tanous } 11674a0cb85cSEd Tanous asyncResp->res 11684a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 11694a0cb85cSEd Tanous entryIdx)]["Address"] = addressField; 11704a0cb85cSEd Tanous }; 11714a0cb85cSEd Tanous 11724a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11734a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 11744a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 11754a0cb85cSEd Tanous "/ipv4/" + thisData->id, 11764a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11774a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 11784a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 11794a0cb85cSEd Tanous *addressField)); 1180179db1d7SKowalski, Kamil } 1181179db1d7SKowalski, Kamil 11824a0cb85cSEd Tanous if (prefixLength && subnetField != nullptr) 11831abe55efSEd Tanous { 11844a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 11854a0cb85cSEd Tanous thisData->id, *subnetField, 11864a0cb85cSEd Tanous *prefixLength, asyncResp); 1187179db1d7SKowalski, Kamil } 1188179db1d7SKowalski, Kamil 11894a0cb85cSEd Tanous if (!addressOriginInDBusFormat.empty() && 11904a0cb85cSEd Tanous addressOriginField != nullptr) 11911abe55efSEd Tanous { 11924a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 11934a0cb85cSEd Tanous *addressOriginField, 11944a0cb85cSEd Tanous addressOriginInDBusFormat, asyncResp); 1195179db1d7SKowalski, Kamil } 1196179db1d7SKowalski, Kamil 11974a0cb85cSEd Tanous if (gatewayField != nullptr) 11981abe55efSEd Tanous { 11994a0cb85cSEd Tanous auto callback = 12004a0cb85cSEd Tanous [asyncResp, entryIdx, 12014a0cb85cSEd Tanous gatewayField{std::string(*gatewayField)}]( 12024a0cb85cSEd Tanous const boost::system::error_code ec) { 12034a0cb85cSEd Tanous if (ec) 12041abe55efSEd Tanous { 1205*f12894f8SJason M. Bills messages::internalError( 1206*f12894f8SJason M. Bills asyncResp->res, 12074a0cb85cSEd Tanous "/IPv4Addresses/" + 12084a0cb85cSEd Tanous std::to_string(entryIdx) + 12094a0cb85cSEd Tanous "/Gateway"); 12104a0cb85cSEd Tanous return; 12114a0cb85cSEd Tanous } 12124a0cb85cSEd Tanous asyncResp->res 12134a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 12144a0cb85cSEd Tanous entryIdx)]["Gateway"] = 12154a0cb85cSEd Tanous std::move(gatewayField); 12164a0cb85cSEd Tanous }; 12174a0cb85cSEd Tanous 12184a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 12194a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 12204a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 12214a0cb85cSEd Tanous "/ipv4/" + thisData->id, 12224a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 12234a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 12244a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 12254a0cb85cSEd Tanous *gatewayField)); 12264a0cb85cSEd Tanous } 12274a0cb85cSEd Tanous } 12284a0cb85cSEd Tanous thisData++; 12291abe55efSEd Tanous } 12301abe55efSEd Tanous else 12311abe55efSEd Tanous { 12324a0cb85cSEd Tanous // Create IPv4 with provided data 12334a0cb85cSEd Tanous if (gatewayField == nullptr) 12341abe55efSEd Tanous { 1235*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "Gateway", 12364a0cb85cSEd Tanous pathString + "/Gateway"); 12374a0cb85cSEd Tanous continue; 12384a0cb85cSEd Tanous } 12394a0cb85cSEd Tanous 12404a0cb85cSEd Tanous if (addressField == nullptr) 12411abe55efSEd Tanous { 1242*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "Address", 12434a0cb85cSEd Tanous pathString + "/Address"); 12444a0cb85cSEd Tanous continue; 12454a0cb85cSEd Tanous } 12464a0cb85cSEd Tanous 12474a0cb85cSEd Tanous if (!prefixLength) 12481abe55efSEd Tanous { 1249*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "SubnetMask", 12504a0cb85cSEd Tanous pathString + "/SubnetMask"); 12514a0cb85cSEd Tanous continue; 1252588c3f0dSKowalski, Kamil } 1253588c3f0dSKowalski, Kamil 12544a0cb85cSEd Tanous createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField, 12554a0cb85cSEd Tanous *addressField, asyncResp); 12564a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 12574a0cb85cSEd Tanous } 12584a0cb85cSEd Tanous entryIdx++; 12594a0cb85cSEd Tanous } 12604a0cb85cSEd Tanous } 12614a0cb85cSEd Tanous 12624a0cb85cSEd Tanous nlohmann::json parseInterfaceData( 12634a0cb85cSEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 12644a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 12654a0cb85cSEd Tanous { 12664a0cb85cSEd Tanous // Copy JSON object to avoid race condition 12674a0cb85cSEd Tanous nlohmann::json json_response(Node::json); 12684a0cb85cSEd Tanous 12694a0cb85cSEd Tanous json_response["Id"] = iface_id; 12704a0cb85cSEd Tanous json_response["@odata.id"] = 12714a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 12724a0cb85cSEd Tanous 12734a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 12744a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 12754a0cb85cSEd Tanous if (!ethData.hostname.empty()) 12764a0cb85cSEd Tanous { 12774a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 12784a0cb85cSEd Tanous } 12794a0cb85cSEd Tanous 12804a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 12814a0cb85cSEd Tanous if (ethData.vlan_id) 12824a0cb85cSEd Tanous { 12834a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 12844a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 12854a0cb85cSEd Tanous } 12864a0cb85cSEd Tanous else 12874a0cb85cSEd Tanous { 12884a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 12894a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 12904a0cb85cSEd Tanous } 12914a0cb85cSEd Tanous 12924a0cb85cSEd Tanous if (ipv4Data.size() > 0) 12934a0cb85cSEd Tanous { 12944a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 12954a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 12964a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 12974a0cb85cSEd Tanous { 12984a0cb85cSEd Tanous if (!ipv4_config.address.empty()) 12994a0cb85cSEd Tanous { 13004a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 13014a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 13024a0cb85cSEd Tanous {"Address", ipv4_config.address}}); 13034a0cb85cSEd Tanous 13044a0cb85cSEd Tanous if (!ipv4_config.gateway.empty()) 13054a0cb85cSEd Tanous { 13064a0cb85cSEd Tanous ipv4_array.back()["Gateway"] = ipv4_config.gateway; 13074a0cb85cSEd Tanous } 13084a0cb85cSEd Tanous } 13094a0cb85cSEd Tanous } 13104a0cb85cSEd Tanous } 13114a0cb85cSEd Tanous 13124a0cb85cSEd Tanous return json_response; 1313588c3f0dSKowalski, Kamil } 1314588c3f0dSKowalski, Kamil 13159391bb9cSRapkiewicz, Pawel /** 13169391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 13179391bb9cSRapkiewicz, Pawel */ 131855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 13191abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13201abe55efSEd Tanous { 13214a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13221abe55efSEd Tanous if (params.size() != 1) 13231abe55efSEd Tanous { 1324*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 13259391bb9cSRapkiewicz, Pawel return; 13269391bb9cSRapkiewicz, Pawel } 13279391bb9cSRapkiewicz, Pawel 13284a0cb85cSEd Tanous getEthernetIfaceData( 13294a0cb85cSEd Tanous params[0], 13304a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 13314a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13324a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13334a0cb85cSEd Tanous if (!success) 13341abe55efSEd Tanous { 13351abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13361abe55efSEd Tanous // object, and other errors 1337*f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1338*f12894f8SJason M. Bills "EthernetInterface", iface_id); 13394a0cb85cSEd Tanous return; 13409391bb9cSRapkiewicz, Pawel } 13414a0cb85cSEd Tanous asyncResp->res.jsonValue = 13424a0cb85cSEd Tanous parseInterfaceData(iface_id, ethData, ipv4Data); 13439391bb9cSRapkiewicz, Pawel }); 13449391bb9cSRapkiewicz, Pawel } 13459391bb9cSRapkiewicz, Pawel 134655c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 13471abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13481abe55efSEd Tanous { 13494a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13501abe55efSEd Tanous if (params.size() != 1) 13511abe55efSEd Tanous { 1352*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1353588c3f0dSKowalski, Kamil return; 1354588c3f0dSKowalski, Kamil } 1355588c3f0dSKowalski, Kamil 13564a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1357588c3f0dSKowalski, Kamil 1358179db1d7SKowalski, Kamil nlohmann::json patchReq; 13591abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 13601abe55efSEd Tanous { 1361588c3f0dSKowalski, Kamil return; 1362588c3f0dSKowalski, Kamil } 1363588c3f0dSKowalski, Kamil 13644a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1365588c3f0dSKowalski, Kamil // preparation 13664a0cb85cSEd Tanous getEthernetIfaceData( 13674a0cb85cSEd Tanous iface_id, 13684a0cb85cSEd Tanous [this, asyncResp, iface_id, patchReq = std::move(patchReq)]( 13694a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13704a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13711abe55efSEd Tanous if (!success) 13721abe55efSEd Tanous { 1373588c3f0dSKowalski, Kamil // ... otherwise return error 13741abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13751abe55efSEd Tanous // object, and other errors 1376*f12894f8SJason M. Bills messages::resourceNotFound( 1377*f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1378588c3f0dSKowalski, Kamil return; 1379588c3f0dSKowalski, Kamil } 1380588c3f0dSKowalski, Kamil 13814a0cb85cSEd Tanous asyncResp->res.jsonValue = 13824a0cb85cSEd Tanous parseInterfaceData(iface_id, ethData, ipv4Data); 1383588c3f0dSKowalski, Kamil 13844a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 13851abe55efSEd Tanous { 13861abe55efSEd Tanous if (propertyIt.key() == "VLAN") 13871abe55efSEd Tanous { 13884a0cb85cSEd Tanous handleVlanPatch(iface_id, propertyIt.value(), ethData, 13894a0cb85cSEd Tanous asyncResp); 13901abe55efSEd Tanous } 13911abe55efSEd Tanous else if (propertyIt.key() == "HostName") 13921abe55efSEd Tanous { 13934a0cb85cSEd Tanous handleHostnamePatch(propertyIt.value(), asyncResp); 13941abe55efSEd Tanous } 13951abe55efSEd Tanous else if (propertyIt.key() == "IPv4Addresses") 13961abe55efSEd Tanous { 13974a0cb85cSEd Tanous handleIPv4Patch(iface_id, propertyIt.value(), ipv4Data, 1398179db1d7SKowalski, Kamil asyncResp); 13991abe55efSEd Tanous } 14001abe55efSEd Tanous else if (propertyIt.key() == "IPv6Addresses") 14011abe55efSEd Tanous { 1402179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1403*f12894f8SJason M. Bills messages::propertyNotWritable( 1404*f12894f8SJason M. Bills asyncResp->res, propertyIt.key(), propertyIt.key()); 14051abe55efSEd Tanous } 14061abe55efSEd Tanous else 14071abe55efSEd Tanous { 14081abe55efSEd Tanous auto fieldInJsonIt = 14094a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 1410588c3f0dSKowalski, Kamil 14114a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 14121abe55efSEd Tanous { 1413588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1414*f12894f8SJason M. Bills messages::propertyUnknown(asyncResp->res, 1415*f12894f8SJason M. Bills propertyIt.key(), 1416*f12894f8SJason M. Bills propertyIt.key()); 14171abe55efSEd Tanous } 14184a0cb85cSEd Tanous else 14191abe55efSEd Tanous { 1420588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1421*f12894f8SJason M. Bills messages::propertyNotWritable(asyncResp->res, 1422*f12894f8SJason M. Bills propertyIt.key(), 1423*f12894f8SJason M. Bills propertyIt.key()); 1424588c3f0dSKowalski, Kamil } 1425588c3f0dSKowalski, Kamil } 1426588c3f0dSKowalski, Kamil } 1427588c3f0dSKowalski, Kamil }); 1428588c3f0dSKowalski, Kamil } 14299391bb9cSRapkiewicz, Pawel }; 14309391bb9cSRapkiewicz, Pawel 1431e439f0f8SKowalski, Kamil /** 14324a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 14334a0cb85cSEd Tanous * Schema 1434e439f0f8SKowalski, Kamil */ 14351abe55efSEd Tanous class VlanNetworkInterface : public Node 14361abe55efSEd Tanous { 1437e439f0f8SKowalski, Kamil public: 1438e439f0f8SKowalski, Kamil /* 1439e439f0f8SKowalski, Kamil * Default Constructor 1440e439f0f8SKowalski, Kamil */ 1441e439f0f8SKowalski, Kamil template <typename CrowApp> 14421abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 14434a0cb85cSEd Tanous // one manager called openbmc. This shall be generic, but requires to 14444a0cb85cSEd Tanous // update GetSubroutes method 14451abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 14464a0cb85cSEd Tanous Node(app, 14474a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>>/VLANs/" 14484a0cb85cSEd Tanous "<str>", 14491abe55efSEd Tanous std::string(), std::string()) 14501abe55efSEd Tanous { 1451e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1452e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1453e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1454e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1455e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1456e439f0f8SKowalski, Kamil 1457e439f0f8SKowalski, Kamil entityPrivileges = { 1458e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1459e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1460e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1461e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1462e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1463e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1464e439f0f8SKowalski, Kamil } 1465e439f0f8SKowalski, Kamil 1466e439f0f8SKowalski, Kamil private: 14674a0cb85cSEd Tanous nlohmann::json parseInterfaceData( 14684a0cb85cSEd Tanous const std::string &parent_iface_id, const std::string &iface_id, 14694a0cb85cSEd Tanous const EthernetInterfaceData ðData, 14704a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 14711abe55efSEd Tanous { 1472e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 14734a0cb85cSEd Tanous nlohmann::json json_response(Node::json); 1474e439f0f8SKowalski, Kamil 1475e439f0f8SKowalski, Kamil // Fill out obvious data... 14764a0cb85cSEd Tanous json_response["Id"] = iface_id; 14774a0cb85cSEd Tanous json_response["@odata.id"] = 14784a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 14794a0cb85cSEd Tanous "/VLANs/" + iface_id; 1480e439f0f8SKowalski, Kamil 14814a0cb85cSEd Tanous json_response["VLANEnable"] = true; 14824a0cb85cSEd Tanous if (ethData.vlan_id) 14834a0cb85cSEd Tanous { 14844a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 14854a0cb85cSEd Tanous } 14864a0cb85cSEd Tanous return json_response; 1487e439f0f8SKowalski, Kamil } 1488e439f0f8SKowalski, Kamil 148955c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 14901abe55efSEd Tanous const std::string &iface) 14911abe55efSEd Tanous { 1492*f12894f8SJason M. Bills std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14931abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 14941abe55efSEd Tanous { 1495*f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1496*f12894f8SJason M. Bills iface); 1497927a505aSKowalski, Kamil return false; 14981abe55efSEd Tanous } 14991abe55efSEd Tanous else 15001abe55efSEd Tanous { 1501927a505aSKowalski, Kamil return true; 1502927a505aSKowalski, Kamil } 1503927a505aSKowalski, Kamil } 1504927a505aSKowalski, Kamil 1505e439f0f8SKowalski, Kamil /** 1506e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1507e439f0f8SKowalski, Kamil */ 150855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 15091abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15101abe55efSEd Tanous { 15114a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15124a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1513e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1514e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1515e439f0f8SKowalski, Kamil // impossible. 15161abe55efSEd Tanous if (params.size() != 2) 15171abe55efSEd Tanous { 1518*f12894f8SJason M. Bills messages::internalError(res); 1519e439f0f8SKowalski, Kamil res.end(); 1520e439f0f8SKowalski, Kamil return; 1521e439f0f8SKowalski, Kamil } 1522e439f0f8SKowalski, Kamil 15234a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 15244a0cb85cSEd Tanous const std::string &iface_id = params[1]; 1525e439f0f8SKowalski, Kamil 15264a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 15271abe55efSEd Tanous { 1528a434f2bdSEd Tanous return; 1529a434f2bdSEd Tanous } 1530a434f2bdSEd Tanous 1531e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1532e439f0f8SKowalski, Kamil // preparation 15334a0cb85cSEd Tanous getEthernetIfaceData( 15344a0cb85cSEd Tanous iface_id, 15354a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 15364a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15374a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15384a0cb85cSEd Tanous if (success && ethData.vlan_id) 15391abe55efSEd Tanous { 15404a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 15414a0cb85cSEd Tanous parent_iface_id, iface_id, ethData, ipv4Data); 15421abe55efSEd Tanous } 15431abe55efSEd Tanous else 15441abe55efSEd Tanous { 1545e439f0f8SKowalski, Kamil // ... otherwise return error 15461abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15471abe55efSEd Tanous // object, and other errors 1548*f12894f8SJason M. Bills messages::resourceNotFound( 1549*f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1550e439f0f8SKowalski, Kamil } 1551e439f0f8SKowalski, Kamil }); 1552e439f0f8SKowalski, Kamil } 1553e439f0f8SKowalski, Kamil 155455c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 15551abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15561abe55efSEd Tanous { 15574a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15581abe55efSEd Tanous if (params.size() != 2) 15591abe55efSEd Tanous { 1560*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1561e439f0f8SKowalski, Kamil return; 1562e439f0f8SKowalski, Kamil } 1563e439f0f8SKowalski, Kamil 1564d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 156555c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1566927a505aSKowalski, Kamil 15671abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 15681abe55efSEd Tanous { 1569927a505aSKowalski, Kamil return; 1570927a505aSKowalski, Kamil } 1571927a505aSKowalski, Kamil 1572927a505aSKowalski, Kamil nlohmann::json patchReq; 15731abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 15741abe55efSEd Tanous { 1575927a505aSKowalski, Kamil return; 1576927a505aSKowalski, Kamil } 1577927a505aSKowalski, Kamil 1578927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1579927a505aSKowalski, Kamil // preparation 15804a0cb85cSEd Tanous getEthernetIfaceData( 15811abe55efSEd Tanous ifaceId, 15824a0cb85cSEd Tanous [this, asyncResp, parentIfaceId, ifaceId, 15834a0cb85cSEd Tanous patchReq{std::move(patchReq)}]( 15844a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15854a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15861abe55efSEd Tanous if (!success) 15871abe55efSEd Tanous { 15881abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15891abe55efSEd Tanous // object, and other errors 1590*f12894f8SJason M. Bills messages::resourceNotFound( 1591*f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1592927a505aSKowalski, Kamil 1593927a505aSKowalski, Kamil return; 1594927a505aSKowalski, Kamil } 1595927a505aSKowalski, Kamil 15964a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 15974a0cb85cSEd Tanous parentIfaceId, ifaceId, ethData, ipv4Data); 1598927a505aSKowalski, Kamil 15994a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 16001abe55efSEd Tanous { 1601927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 16021abe55efSEd Tanous propertyIt.key() != "VLANId") 16031abe55efSEd Tanous { 16041abe55efSEd Tanous auto fieldInJsonIt = 16054a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 16064a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 16071abe55efSEd Tanous { 1608927a505aSKowalski, Kamil // Field not in scope of defined fields 1609*f12894f8SJason M. Bills messages::propertyUnknown(asyncResp->res, 1610*f12894f8SJason M. Bills propertyIt.key(), 1611*f12894f8SJason M. Bills propertyIt.key()); 16121abe55efSEd Tanous } 16134a0cb85cSEd Tanous else 16141abe55efSEd Tanous { 1615927a505aSKowalski, Kamil // User attempted to modify non-writable field 1616*f12894f8SJason M. Bills messages::propertyNotWritable(asyncResp->res, 1617*f12894f8SJason M. Bills propertyIt.key(), 1618*f12894f8SJason M. Bills propertyIt.key()); 1619927a505aSKowalski, Kamil } 1620927a505aSKowalski, Kamil } 1621927a505aSKowalski, Kamil } 1622927a505aSKowalski, Kamil 16234a0cb85cSEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, ethData, 16244a0cb85cSEd Tanous asyncResp); 1625927a505aSKowalski, Kamil }); 1626e439f0f8SKowalski, Kamil } 1627e439f0f8SKowalski, Kamil 162855c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 16291abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16301abe55efSEd Tanous { 16314a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16321abe55efSEd Tanous if (params.size() != 2) 16331abe55efSEd Tanous { 1634*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1635e439f0f8SKowalski, Kamil return; 1636e439f0f8SKowalski, Kamil } 1637e439f0f8SKowalski, Kamil 1638d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 163955c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1640927a505aSKowalski, Kamil 16414a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 16421abe55efSEd Tanous { 1643927a505aSKowalski, Kamil return; 1644927a505aSKowalski, Kamil } 1645927a505aSKowalski, Kamil 1646927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1647927a505aSKowalski, Kamil // preparation 1648*f12894f8SJason M. Bills getEthernetIfaceData( 1649*f12894f8SJason M. Bills ifaceId, 1650*f12894f8SJason M. Bills [this, asyncResp, parentIfaceId{std::string(parentIfaceId)}, 16514a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1652*f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1653*f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 16544a0cb85cSEd Tanous if (success && ethData.vlan_id) 16551abe55efSEd Tanous { 16564a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 16574a0cb85cSEd Tanous parentIfaceId, ifaceId, ethData, ipv4Data); 1658927a505aSKowalski, Kamil 1659*f12894f8SJason M. Bills auto callback = 1660*f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 16611abe55efSEd Tanous if (ec) 16621abe55efSEd Tanous { 1663*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1664927a505aSKowalski, Kamil } 16654a0cb85cSEd Tanous }; 16664a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 16674a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 16684a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 16694a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 16701abe55efSEd Tanous } 16711abe55efSEd Tanous else 16721abe55efSEd Tanous { 1673927a505aSKowalski, Kamil // ... otherwise return error 1674*f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1675*f12894f8SJason M. Bills // object, and other errors 1676*f12894f8SJason M. Bills messages::resourceNotFound( 1677*f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1678927a505aSKowalski, Kamil } 1679927a505aSKowalski, Kamil }); 1680e439f0f8SKowalski, Kamil } 1681e439f0f8SKowalski, Kamil }; 1682e439f0f8SKowalski, Kamil 1683e439f0f8SKowalski, Kamil /** 1684e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1685e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1686e439f0f8SKowalski, Kamil */ 16871abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 16881abe55efSEd Tanous { 1689e439f0f8SKowalski, Kamil public: 1690e439f0f8SKowalski, Kamil template <typename CrowApp> 16911abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 16924a0cb85cSEd Tanous // one manager called openbmc. This shall be generic, but requires to 16934a0cb85cSEd Tanous // update GetSubroutes method 16941abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 16954a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 16964a0cb85cSEd Tanous std::string()) 16971abe55efSEd Tanous { 1698e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1699e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1700e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1701e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1702e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1703e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1704e439f0f8SKowalski, Kamil 1705e439f0f8SKowalski, Kamil entityPrivileges = { 1706e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1707e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1708e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1709e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1710e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1711e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1712e439f0f8SKowalski, Kamil } 1713e439f0f8SKowalski, Kamil 1714e439f0f8SKowalski, Kamil private: 1715e439f0f8SKowalski, Kamil /** 1716e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1717e439f0f8SKowalski, Kamil */ 171855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 17191abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17201abe55efSEd Tanous { 17214a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17221abe55efSEd Tanous if (params.size() != 1) 17231abe55efSEd Tanous { 1724e439f0f8SKowalski, Kamil // This means there is a problem with the router 1725*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1726e439f0f8SKowalski, Kamil return; 1727e439f0f8SKowalski, Kamil } 1728e439f0f8SKowalski, Kamil 17294a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1730e439f0f8SKowalski, Kamil 17314a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 17321abe55efSEd Tanous // preparation 1733*f12894f8SJason M. Bills getEthernetIfaceList( 1734*f12894f8SJason M. Bills [this, asyncResp, 1735*f12894f8SJason M. Bills rootInterfaceName{std::string(rootInterfaceName)}]( 17361abe55efSEd Tanous const bool &success, 17371abe55efSEd Tanous const std::vector<std::string> &iface_list) { 17384a0cb85cSEd Tanous if (!success) 17391abe55efSEd Tanous { 1740*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 17414a0cb85cSEd Tanous return; 17421abe55efSEd Tanous } 17434a0cb85cSEd Tanous asyncResp->res.jsonValue = Node::json; 17444a0cb85cSEd Tanous 17454a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 17464a0cb85cSEd Tanous 17474a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 17481abe55efSEd Tanous { 17494a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 17504a0cb85cSEd Tanous { 17514a0cb85cSEd Tanous iface_array.push_back( 17524a0cb85cSEd Tanous {{"@odata.id", 17534a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17544a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1755e439f0f8SKowalski, Kamil } 1756e439f0f8SKowalski, Kamil } 1757e439f0f8SKowalski, Kamil 17584a0cb85cSEd Tanous if (iface_array.empty()) 17591abe55efSEd Tanous { 1760*f12894f8SJason M. Bills messages::resourceNotFound( 1761*f12894f8SJason M. Bills asyncResp->res, "EthernetInterface", rootInterfaceName); 17624a0cb85cSEd Tanous return; 1763e439f0f8SKowalski, Kamil } 17644a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 17654a0cb85cSEd Tanous iface_array.size(); 17664a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 17674a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17684a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17694a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1770e439f0f8SKowalski, Kamil }); 1771e439f0f8SKowalski, Kamil } 1772e439f0f8SKowalski, Kamil 177355c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 17741abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17751abe55efSEd Tanous { 17764a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17771abe55efSEd Tanous if (params.size() != 1) 17781abe55efSEd Tanous { 1779*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1780e439f0f8SKowalski, Kamil return; 1781e439f0f8SKowalski, Kamil } 1782e439f0f8SKowalski, Kamil 1783e439f0f8SKowalski, Kamil nlohmann::json postReq; 17841abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, postReq)) 17851abe55efSEd Tanous { 1786e439f0f8SKowalski, Kamil return; 1787e439f0f8SKowalski, Kamil } 1788e439f0f8SKowalski, Kamil 17894a0cb85cSEd Tanous auto vlanIdJson = json.find("VLANId"); 17904a0cb85cSEd Tanous if (vlanIdJson == json.end()) 17911abe55efSEd Tanous { 1792*f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, "VLANId", "/VLANId"); 1793e439f0f8SKowalski, Kamil return; 1794e439f0f8SKowalski, Kamil } 1795e439f0f8SKowalski, Kamil 17964a0cb85cSEd Tanous const uint64_t *vlanId = vlanIdJson->get_ptr<const uint64_t *>(); 17974a0cb85cSEd Tanous if (vlanId == nullptr) 17981abe55efSEd Tanous { 1799*f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, vlanIdJson->dump(), 1800*f12894f8SJason M. Bills "VLANId", "/VLANId"); 18014a0cb85cSEd Tanous return; 1802e439f0f8SKowalski, Kamil } 18034a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1804e439f0f8SKowalski, Kamil 18054a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 18061abe55efSEd Tanous if (ec) 18071abe55efSEd Tanous { 18084a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 18094a0cb85cSEd Tanous // phosphor-network responses 1810*f12894f8SJason M. Bills messages::internalError(asyncResp->res); 18114a0cb85cSEd Tanous return; 18121abe55efSEd Tanous } 1813*f12894f8SJason M. Bills messages::created(asyncResp->res); 1814e439f0f8SKowalski, Kamil }; 18154a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 18164a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 18174a0cb85cSEd Tanous "/xyz/openbmc_project/network", 18184a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 18194a0cb85cSEd Tanous rootInterfaceName, static_cast<uint32_t>(*vlanId)); 18204a0cb85cSEd Tanous } 18214a0cb85cSEd Tanous }; 18229391bb9cSRapkiewicz, Pawel } // namespace redfish 1823