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< 43029573d4SEd Tanous std::string, sdbusplus::message::variant< 44029573d4SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 45029573d4SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double, 46029573d4SEd 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; 812a133282Smanojkiraneda bool DHCPEnabled; 824a0cb85cSEd Tanous std::string hostname; 834a0cb85cSEd Tanous std::string default_gateway; 849a6fc6feSRavi Teja std::string ipv6_default_gateway; 854a0cb85cSEd Tanous std::string mac_address; 86fda13ad2SSunitha Harish std::vector<std::uint32_t> vlan_id; 87029573d4SEd Tanous std::vector<std::string> nameservers; 889391bb9cSRapkiewicz, Pawel }; 899391bb9cSRapkiewicz, Pawel 909391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 919391bb9cSRapkiewicz, Pawel // into full dot notation 921abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 931abe55efSEd Tanous { 949391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 959391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 969391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 979391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 989391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 999391bb9cSRapkiewicz, Pawel return netmask; 1009391bb9cSRapkiewicz, Pawel } 1019391bb9cSRapkiewicz, Pawel 1024a0cb85cSEd Tanous inline std::string 1034a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(const std::string &inputOrigin, 1044a0cb85cSEd Tanous bool isIPv4) 1051abe55efSEd Tanous { 1064a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 1071abe55efSEd Tanous { 1084a0cb85cSEd Tanous return "Static"; 1099391bb9cSRapkiewicz, Pawel } 1104a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal") 1111abe55efSEd Tanous { 1124a0cb85cSEd Tanous if (isIPv4) 1131abe55efSEd Tanous { 1144a0cb85cSEd Tanous return "IPv4LinkLocal"; 1151abe55efSEd Tanous } 1161abe55efSEd Tanous else 1171abe55efSEd Tanous { 1184a0cb85cSEd Tanous return "LinkLocal"; 1199391bb9cSRapkiewicz, Pawel } 1209391bb9cSRapkiewicz, Pawel } 1214a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1221abe55efSEd Tanous { 1234a0cb85cSEd Tanous if (isIPv4) 1244a0cb85cSEd Tanous { 1254a0cb85cSEd Tanous return "DHCP"; 1264a0cb85cSEd Tanous } 1274a0cb85cSEd Tanous else 1284a0cb85cSEd Tanous { 1294a0cb85cSEd Tanous return "DHCPv6"; 1304a0cb85cSEd Tanous } 1314a0cb85cSEd Tanous } 1324a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC") 1334a0cb85cSEd Tanous { 1344a0cb85cSEd Tanous return "SLAAC"; 1354a0cb85cSEd Tanous } 1364a0cb85cSEd Tanous return ""; 1374a0cb85cSEd Tanous } 1384a0cb85cSEd Tanous 1394a0cb85cSEd Tanous inline std::string 1404a0cb85cSEd Tanous translateAddressOriginRedfishToDbus(const std::string &inputOrigin) 1414a0cb85cSEd Tanous { 1424a0cb85cSEd Tanous if (inputOrigin == "Static") 1434a0cb85cSEd Tanous { 1444a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 1454a0cb85cSEd Tanous } 1464a0cb85cSEd Tanous if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6") 1474a0cb85cSEd Tanous { 1484a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 1494a0cb85cSEd Tanous } 1504a0cb85cSEd Tanous if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal") 1514a0cb85cSEd Tanous { 1524a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal"; 1534a0cb85cSEd Tanous } 1544a0cb85cSEd Tanous if (inputOrigin == "SLAAC") 1554a0cb85cSEd Tanous { 1564a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC"; 1574a0cb85cSEd Tanous } 1584a0cb85cSEd Tanous return ""; 1594a0cb85cSEd Tanous } 1604a0cb85cSEd Tanous 1614c9afe43SEd Tanous inline bool extractEthernetInterfaceData(const std::string ðiface_id, 1624a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 1634a0cb85cSEd Tanous EthernetInterfaceData ðData) 1644a0cb85cSEd Tanous { 1654c9afe43SEd Tanous bool idFound = false; 1664a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 1674a0cb85cSEd Tanous { 1684a0cb85cSEd Tanous for (const auto &ifacePair : objpath.second) 1694a0cb85cSEd Tanous { 170029573d4SEd Tanous if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id) 171029573d4SEd Tanous { 1724c9afe43SEd Tanous idFound = true; 1734a0cb85cSEd Tanous if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 1744a0cb85cSEd Tanous { 1754a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1764a0cb85cSEd Tanous { 1774a0cb85cSEd Tanous if (propertyPair.first == "MACAddress") 1784a0cb85cSEd Tanous { 1794a0cb85cSEd Tanous const std::string *mac = 180abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 1814a0cb85cSEd Tanous if (mac != nullptr) 1824a0cb85cSEd Tanous { 1834a0cb85cSEd Tanous ethData.mac_address = *mac; 1844a0cb85cSEd Tanous } 1854a0cb85cSEd Tanous } 1864a0cb85cSEd Tanous } 1874a0cb85cSEd Tanous } 1884a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1894a0cb85cSEd Tanous { 1904a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1914a0cb85cSEd Tanous { 1924a0cb85cSEd Tanous if (propertyPair.first == "Id") 1934a0cb85cSEd Tanous { 1941b6b96c5SEd Tanous const uint32_t *id = 195abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 1964a0cb85cSEd Tanous if (id != nullptr) 1974a0cb85cSEd Tanous { 198fda13ad2SSunitha Harish ethData.vlan_id.push_back(*id); 1994a0cb85cSEd Tanous } 2004a0cb85cSEd Tanous } 2014a0cb85cSEd Tanous } 2024a0cb85cSEd Tanous } 2034a0cb85cSEd Tanous else if (ifacePair.first == 2044a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 2054a0cb85cSEd Tanous { 2064a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2074a0cb85cSEd Tanous { 2084a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 2094a0cb85cSEd Tanous { 2104a0cb85cSEd Tanous const bool *auto_neg = 211abf2add6SEd Tanous std::get_if<bool>(&propertyPair.second); 2124a0cb85cSEd Tanous if (auto_neg != nullptr) 2134a0cb85cSEd Tanous { 2144a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2154a0cb85cSEd Tanous } 2164a0cb85cSEd Tanous } 2174a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2184a0cb85cSEd Tanous { 2194a0cb85cSEd Tanous const uint32_t *speed = 220abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 2214a0cb85cSEd Tanous if (speed != nullptr) 2224a0cb85cSEd Tanous { 2234a0cb85cSEd Tanous ethData.speed = *speed; 2244a0cb85cSEd Tanous } 2254a0cb85cSEd Tanous } 226f85837bfSRAJESWARAN THILLAIGOVINDAN else if (propertyPair.first == "Nameservers") 227029573d4SEd Tanous { 228029573d4SEd Tanous const std::vector<std::string> *nameservers = 229029573d4SEd Tanous sdbusplus::message::variant_ns::get_if< 230029573d4SEd Tanous std::vector<std::string>>( 231029573d4SEd Tanous &propertyPair.second); 232029573d4SEd Tanous if (nameservers != nullptr) 233029573d4SEd Tanous { 234029573d4SEd Tanous ethData.nameservers = std::move(*nameservers); 2354a0cb85cSEd Tanous } 2364a0cb85cSEd Tanous } 2372a133282Smanojkiraneda else if (propertyPair.first == "DHCPEnabled") 2382a133282Smanojkiraneda { 2392a133282Smanojkiraneda const bool *DHCPEnabled = 2402a133282Smanojkiraneda std::get_if<bool>(&propertyPair.second); 2412a133282Smanojkiraneda if (DHCPEnabled != nullptr) 2422a133282Smanojkiraneda { 2432a133282Smanojkiraneda ethData.DHCPEnabled = *DHCPEnabled; 2442a133282Smanojkiraneda } 2452a133282Smanojkiraneda } 246029573d4SEd Tanous } 247029573d4SEd Tanous } 248029573d4SEd Tanous } 249029573d4SEd Tanous // System configuration shows up in the global namespace, so no need 250029573d4SEd Tanous // to check eth number 251029573d4SEd Tanous if (ifacePair.first == 2524a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2534a0cb85cSEd Tanous { 2544a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2554a0cb85cSEd Tanous { 2564a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2574a0cb85cSEd Tanous { 2584a0cb85cSEd Tanous const std::string *hostname = 259029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 260029573d4SEd Tanous &propertyPair.second); 2614a0cb85cSEd Tanous if (hostname != nullptr) 2624a0cb85cSEd Tanous { 2634a0cb85cSEd Tanous ethData.hostname = *hostname; 2644a0cb85cSEd Tanous } 2654a0cb85cSEd Tanous } 2664a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2674a0cb85cSEd Tanous { 2684a0cb85cSEd Tanous const std::string *defaultGateway = 269029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 270029573d4SEd Tanous &propertyPair.second); 2714a0cb85cSEd Tanous if (defaultGateway != nullptr) 2724a0cb85cSEd Tanous { 2734a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2744a0cb85cSEd Tanous } 2754a0cb85cSEd Tanous } 2769a6fc6feSRavi Teja else if (propertyPair.first == "DefaultGateway6") 2779a6fc6feSRavi Teja { 2789a6fc6feSRavi Teja const std::string *defaultGateway6 = 2799a6fc6feSRavi Teja sdbusplus::message::variant_ns::get_if<std::string>( 2809a6fc6feSRavi Teja &propertyPair.second); 2819a6fc6feSRavi Teja if (defaultGateway6 != nullptr) 2829a6fc6feSRavi Teja { 2839a6fc6feSRavi Teja ethData.ipv6_default_gateway = *defaultGateway6; 2849a6fc6feSRavi Teja } 2859a6fc6feSRavi Teja } 2864a0cb85cSEd Tanous } 2874a0cb85cSEd Tanous } 2884a0cb85cSEd Tanous } 2894a0cb85cSEd Tanous } 2904c9afe43SEd Tanous return idFound; 2914a0cb85cSEd Tanous } 2924a0cb85cSEd Tanous 2934a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2944a0cb85cSEd Tanous inline void 2954a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2964a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2974a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2984a0cb85cSEd Tanous { 2994a0cb85cSEd Tanous const std::string ipv4PathStart = 3004a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 3014a0cb85cSEd Tanous 3024a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 3034a0cb85cSEd Tanous // single ethernet interface, loop over all of them 3044a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 3054a0cb85cSEd Tanous { 3064a0cb85cSEd Tanous // Check if proper pattern for object path appears 3074a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 3084a0cb85cSEd Tanous { 3094a0cb85cSEd Tanous for (auto &interface : objpath.second) 3104a0cb85cSEd Tanous { 3114a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 3124a0cb85cSEd Tanous { 3134a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 3144a0cb85cSEd Tanous // appropriate 3154a0cb85cSEd Tanous std::pair< 3164a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 3174a0cb85cSEd Tanous bool> 3184a0cb85cSEd Tanous it = ipv4_config.insert( 319b01bf299SEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 3204a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 3214a0cb85cSEd Tanous for (auto &property : interface.second) 3224a0cb85cSEd Tanous { 3234a0cb85cSEd Tanous if (property.first == "Address") 3244a0cb85cSEd Tanous { 3254a0cb85cSEd Tanous const std::string *address = 326abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3274a0cb85cSEd Tanous if (address != nullptr) 3284a0cb85cSEd Tanous { 3294a0cb85cSEd Tanous ipv4_address.address = *address; 3304a0cb85cSEd Tanous } 3314a0cb85cSEd Tanous } 3324a0cb85cSEd Tanous else if (property.first == "Gateway") 3334a0cb85cSEd Tanous { 3344a0cb85cSEd Tanous const std::string *gateway = 335abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3364a0cb85cSEd Tanous if (gateway != nullptr) 3374a0cb85cSEd Tanous { 3384a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 3394a0cb85cSEd Tanous } 3404a0cb85cSEd Tanous } 3414a0cb85cSEd Tanous else if (property.first == "Origin") 3424a0cb85cSEd Tanous { 3434a0cb85cSEd Tanous const std::string *origin = 344abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3454a0cb85cSEd Tanous if (origin != nullptr) 3464a0cb85cSEd Tanous { 3474a0cb85cSEd Tanous ipv4_address.origin = 3484a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3494a0cb85cSEd Tanous true); 3504a0cb85cSEd Tanous } 3514a0cb85cSEd Tanous } 3524a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3534a0cb85cSEd Tanous { 3544a0cb85cSEd Tanous const uint8_t *mask = 355abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 3564a0cb85cSEd Tanous if (mask != nullptr) 3574a0cb85cSEd Tanous { 3584a0cb85cSEd Tanous // convert it to the string 3594a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3604a0cb85cSEd Tanous } 3614a0cb85cSEd Tanous } 3624a0cb85cSEd Tanous else 3634a0cb85cSEd Tanous { 3644a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3654a0cb85cSEd Tanous << "Got extra property: " << property.first 3664a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3674a0cb85cSEd Tanous } 3684a0cb85cSEd Tanous } 3694a0cb85cSEd Tanous // Check if given address is local, or global 3704a0cb85cSEd Tanous ipv4_address.linktype = 3714a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3724a0cb85cSEd Tanous ? LinkType::Global 3734a0cb85cSEd Tanous : LinkType::Local; 3744a0cb85cSEd Tanous } 3754a0cb85cSEd Tanous } 3764a0cb85cSEd Tanous } 3774a0cb85cSEd Tanous } 3784a0cb85cSEd Tanous } 379588c3f0dSKowalski, Kamil 380588c3f0dSKowalski, Kamil /** 381588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 382588c3f0dSKowalski, Kamil * 383588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 384588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 385588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 386588c3f0dSKowalski, Kamil * 387588c3f0dSKowalski, Kamil * @return None. 388588c3f0dSKowalski, Kamil */ 389588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3904a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3911abe55efSEd Tanous CallbackFunc &&callback) 3921abe55efSEd Tanous { 39355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 394588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 395588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 396588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 397588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 398abf2add6SEd Tanous std::variant<uint32_t>(inputVlanId)); 3994a0cb85cSEd Tanous } 400588c3f0dSKowalski, Kamil 401588c3f0dSKowalski, Kamil /** 402179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 403179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 404179db1d7SKowalski, Kamil * bit count for Subnet Mask. 405179db1d7SKowalski, Kamil * 406179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 407179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 408179db1d7SKowalski, Kamil * 409179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 410179db1d7SKowalski, Kamil */ 4114a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 4121abe55efSEd Tanous uint8_t *bits = nullptr) 4131abe55efSEd Tanous { 414179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 415179db1d7SKowalski, Kamil 416179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 417179db1d7SKowalski, Kamil 4184a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 4191abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 4201abe55efSEd Tanous { 421179db1d7SKowalski, Kamil return false; 422179db1d7SKowalski, Kamil } 423179db1d7SKowalski, Kamil 4241abe55efSEd Tanous if (bits != nullptr) 4251abe55efSEd Tanous { 426179db1d7SKowalski, Kamil *bits = 0; 427179db1d7SKowalski, Kamil } 428179db1d7SKowalski, Kamil 429179db1d7SKowalski, Kamil char *endPtr; 430179db1d7SKowalski, Kamil long previousValue = 255; 431179db1d7SKowalski, Kamil bool firstZeroInByteHit; 4321abe55efSEd Tanous for (const std::string &byte : bytesInMask) 4331abe55efSEd Tanous { 4341abe55efSEd Tanous if (byte.empty()) 4351abe55efSEd Tanous { 4361db9ca37SKowalski, Kamil return false; 4371db9ca37SKowalski, Kamil } 4381db9ca37SKowalski, Kamil 439179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4401db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 441179db1d7SKowalski, Kamil 4424a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4434a0cb85cSEd Tanous // is not 100% number 4441abe55efSEd Tanous if (*endPtr != '\0') 4451abe55efSEd Tanous { 446179db1d7SKowalski, Kamil return false; 447179db1d7SKowalski, Kamil } 448179db1d7SKowalski, Kamil 449179db1d7SKowalski, Kamil // Value should be contained in byte 4501abe55efSEd Tanous if (value < 0 || value > 255) 4511abe55efSEd Tanous { 452179db1d7SKowalski, Kamil return false; 453179db1d7SKowalski, Kamil } 454179db1d7SKowalski, Kamil 4551abe55efSEd Tanous if (bits != nullptr) 4561abe55efSEd Tanous { 457179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4581abe55efSEd Tanous if (previousValue != 255 && value != 0) 4591abe55efSEd Tanous { 460179db1d7SKowalski, Kamil return false; 461179db1d7SKowalski, Kamil } 462179db1d7SKowalski, Kamil 463179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 464179db1d7SKowalski, Kamil firstZeroInByteHit = false; 465179db1d7SKowalski, Kamil 466179db1d7SKowalski, Kamil // Count bits 4671abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4681abe55efSEd Tanous { 4691abe55efSEd Tanous if (value & (1 << bitIdx)) 4701abe55efSEd Tanous { 4711abe55efSEd Tanous if (firstZeroInByteHit) 4721abe55efSEd Tanous { 473179db1d7SKowalski, Kamil // Continuity not preserved 474179db1d7SKowalski, Kamil return false; 4751abe55efSEd Tanous } 4761abe55efSEd Tanous else 4771abe55efSEd Tanous { 478179db1d7SKowalski, Kamil (*bits)++; 479179db1d7SKowalski, Kamil } 4801abe55efSEd Tanous } 4811abe55efSEd Tanous else 4821abe55efSEd Tanous { 483179db1d7SKowalski, Kamil firstZeroInByteHit = true; 484179db1d7SKowalski, Kamil } 485179db1d7SKowalski, Kamil } 486179db1d7SKowalski, Kamil } 487179db1d7SKowalski, Kamil 488179db1d7SKowalski, Kamil previousValue = value; 489179db1d7SKowalski, Kamil } 490179db1d7SKowalski, Kamil 491179db1d7SKowalski, Kamil return true; 492179db1d7SKowalski, Kamil } 493179db1d7SKowalski, Kamil 494179db1d7SKowalski, Kamil /** 495b01bf299SEd Tanous * @brief Changes IPv4 address type property (Address, Gateway) 496b01bf299SEd Tanous * 497b01bf299SEd Tanous * @param[in] ifaceId Id of interface whose IP should be modified 498b01bf299SEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 499b01bf299SEd Tanous * @param[in] ipHash DBus Hash id of modified IP 500b01bf299SEd Tanous * @param[in] name Name of field in JSON representation 501b01bf299SEd Tanous * @param[in] newValue New value that should be written 502b01bf299SEd Tanous * @param[io] asyncResp Response object that will be returned to client 503b01bf299SEd Tanous * 504b01bf299SEd Tanous * @return true if give IP is valid and has been sent do D-Bus, false 505b01bf299SEd Tanous * otherwise 506b01bf299SEd Tanous */ 507b01bf299SEd Tanous inline void changeIPv4AddressProperty( 508b01bf299SEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 509b01bf299SEd Tanous const std::string &name, const std::string &newValue, 510b01bf299SEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 511b01bf299SEd Tanous { 512b01bf299SEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 513b01bf299SEd Tanous newValue{std::move(newValue)}]( 514b01bf299SEd Tanous const boost::system::error_code ec) { 515b01bf299SEd Tanous if (ec) 516b01bf299SEd Tanous { 517b01bf299SEd Tanous messages::internalError(asyncResp->res); 518b01bf299SEd Tanous } 519b01bf299SEd Tanous else 520b01bf299SEd Tanous { 521b01bf299SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 522b01bf299SEd Tanous } 523b01bf299SEd Tanous }; 524b01bf299SEd Tanous 525b01bf299SEd Tanous crow::connections::systemBus->async_method_call( 526b01bf299SEd Tanous std::move(callback), "xyz.openbmc_project.Network", 527b01bf299SEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 528b01bf299SEd Tanous "org.freedesktop.DBus.Properties", "Set", 529b01bf299SEd Tanous "xyz.openbmc_project.Network.IP", name, 530b01bf299SEd Tanous std::variant<std::string>(newValue)); 531b01bf299SEd Tanous } 532b01bf299SEd Tanous 533b01bf299SEd Tanous /** 534179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 535179db1d7SKowalski, Kamil * 536179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5374a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5381abe55efSEd Tanous * modified 539179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 540179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 541179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 542179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 543179db1d7SKowalski, Kamil * 544179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 545179db1d7SKowalski, Kamil * otherwise 546179db1d7SKowalski, Kamil */ 547b01bf299SEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5481abe55efSEd Tanous const std::string &ipHash, 5491abe55efSEd Tanous const std::string &newValue, 550179db1d7SKowalski, Kamil const std::string &newValueDbus, 5514a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5521abe55efSEd Tanous { 5534a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5541abe55efSEd Tanous const boost::system::error_code ec) { 5551abe55efSEd Tanous if (ec) 5561abe55efSEd Tanous { 557a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5581abe55efSEd Tanous } 5591abe55efSEd Tanous else 5601abe55efSEd Tanous { 5614a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 562179db1d7SKowalski, Kamil newValue; 563179db1d7SKowalski, Kamil } 564179db1d7SKowalski, Kamil }; 565179db1d7SKowalski, Kamil 56655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 567179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 568179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 569179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 570179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 571abf2add6SEd Tanous std::variant<std::string>(newValueDbus)); 5724a0cb85cSEd Tanous } 573179db1d7SKowalski, Kamil 574179db1d7SKowalski, Kamil /** 575179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 576179db1d7SKowalski, Kamil * 577179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5784a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5791abe55efSEd Tanous * modified 580179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 581179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 582179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 583179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 584179db1d7SKowalski, Kamil * 585179db1d7SKowalski, Kamil * @return None 586179db1d7SKowalski, Kamil */ 587b01bf299SEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5884a0cb85cSEd Tanous const std::string &ipHash, 5894a0cb85cSEd Tanous const std::string &newValueStr, 5904a0cb85cSEd Tanous uint8_t &newValue, 5914a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5921abe55efSEd Tanous { 5934a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5941abe55efSEd Tanous const boost::system::error_code ec) { 5951abe55efSEd Tanous if (ec) 5961abe55efSEd Tanous { 597a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5981abe55efSEd Tanous } 5991abe55efSEd Tanous else 6001abe55efSEd Tanous { 60155c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 602179db1d7SKowalski, Kamil newValueStr; 603179db1d7SKowalski, Kamil } 604179db1d7SKowalski, Kamil }; 605179db1d7SKowalski, Kamil 60655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 607179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 608179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 609179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 610179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 611abf2add6SEd Tanous std::variant<uint8_t>(newValue)); 6124a0cb85cSEd Tanous } 613588c3f0dSKowalski, Kamil 614588c3f0dSKowalski, Kamil /** 615179db1d7SKowalski, Kamil * @brief Deletes given IPv4 616179db1d7SKowalski, Kamil * 617179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6184a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 619179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 620179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 621179db1d7SKowalski, Kamil * 622179db1d7SKowalski, Kamil * @return None 623179db1d7SKowalski, Kamil */ 6244a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 625179db1d7SKowalski, Kamil unsigned int ipIdx, 6264a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6271abe55efSEd Tanous { 62855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6294a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6301abe55efSEd Tanous if (ec) 6311abe55efSEd Tanous { 632a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 6331abe55efSEd Tanous } 6341abe55efSEd Tanous else 6351abe55efSEd Tanous { 63655c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 637179db1d7SKowalski, Kamil } 638179db1d7SKowalski, Kamil }, 639179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 640179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 641179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 642179db1d7SKowalski, Kamil } 643179db1d7SKowalski, Kamil 644179db1d7SKowalski, Kamil /** 645179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 646179db1d7SKowalski, Kamil * 647179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6484a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 649179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 650179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 651179db1d7SKowalski, Kamil * 652179db1d7SKowalski, Kamil * @return None 653179db1d7SKowalski, Kamil */ 654b01bf299SEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 655b01bf299SEd Tanous uint8_t subnetMask, const std::string &gateway, 656b01bf299SEd Tanous const std::string &address, 6574a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6581abe55efSEd Tanous { 65943b761d0SEd Tanous auto createIpHandler = [asyncResp](const boost::system::error_code ec) { 6601abe55efSEd Tanous if (ec) 6611abe55efSEd Tanous { 662a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 663179db1d7SKowalski, Kamil } 664179db1d7SKowalski, Kamil }; 665179db1d7SKowalski, Kamil 66655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 667179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 668179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 669179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 670179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 671179db1d7SKowalski, Kamil gateway); 672179db1d7SKowalski, Kamil } 6732a133282Smanojkiraneda using GetAllPropertiesType = 6742a133282Smanojkiraneda boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>; 6752a133282Smanojkiraneda 6762a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp) 6772a133282Smanojkiraneda { 6782a133282Smanojkiraneda auto getConfig = [asyncResp](const boost::system::error_code error_code, 6792a133282Smanojkiraneda const GetAllPropertiesType &dbus_data) { 6802a133282Smanojkiraneda if (error_code) 6812a133282Smanojkiraneda { 6822a133282Smanojkiraneda BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code; 6832a133282Smanojkiraneda messages::internalError(asyncResp->res); 6842a133282Smanojkiraneda return; 6852a133282Smanojkiraneda } 686fda13ad2SSunitha Harish nlohmann::json &DHCPConfigTypeJson = asyncResp->res.jsonValue["DHCPv4"]; 6872a133282Smanojkiraneda for (const auto &property : dbus_data) 6882a133282Smanojkiraneda { 6892a133282Smanojkiraneda auto value = 6902a133282Smanojkiraneda sdbusplus::message::variant_ns::get_if<bool>(&property.second); 6912a133282Smanojkiraneda 6922a133282Smanojkiraneda if (value == nullptr) 6932a133282Smanojkiraneda { 6942a133282Smanojkiraneda continue; 6952a133282Smanojkiraneda } 6962a133282Smanojkiraneda if (property.first == "DNSEnabled") 6972a133282Smanojkiraneda { 6982a133282Smanojkiraneda DHCPConfigTypeJson["UseDNSServers"] = *value; 6992a133282Smanojkiraneda } 7002a133282Smanojkiraneda else if (property.first == "HostNameEnabled") 7012a133282Smanojkiraneda { 7022a133282Smanojkiraneda DHCPConfigTypeJson["UseDomainName"] = *value; 7032a133282Smanojkiraneda } 7042a133282Smanojkiraneda else if (property.first == "NTPEnabled") 7052a133282Smanojkiraneda { 7062a133282Smanojkiraneda DHCPConfigTypeJson["UseNTPServers"] = *value; 7072a133282Smanojkiraneda } 7082a133282Smanojkiraneda } 7092a133282Smanojkiraneda }; 7102a133282Smanojkiraneda crow::connections::systemBus->async_method_call( 7112a133282Smanojkiraneda std::move(getConfig), "xyz.openbmc_project.Network", 7122a133282Smanojkiraneda "/xyz/openbmc_project/network/config/dhcp", 7132a133282Smanojkiraneda "org.freedesktop.DBus.Properties", "GetAll", 7142a133282Smanojkiraneda "xyz.openbmc_project.Network.DHCPConfiguration"); 7152a133282Smanojkiraneda } 716179db1d7SKowalski, Kamil 717179db1d7SKowalski, Kamil /** 718179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 719179db1d7SKowalski, Kamil * Object 720179db1d7SKowalski, Kamil * from EntityManager Network Manager 7214a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 722179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 723179db1d7SKowalski, Kamil * into JSON 724179db1d7SKowalski, Kamil */ 725179db1d7SKowalski, Kamil template <typename CallbackFunc> 7264a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 7271abe55efSEd Tanous CallbackFunc &&callback) 7281abe55efSEd Tanous { 72955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7304a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 7311abe55efSEd Tanous const boost::system::error_code error_code, 7324a0cb85cSEd Tanous const GetManagedObjects &resp) { 73355c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 7344a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 735179db1d7SKowalski, Kamil 7361abe55efSEd Tanous if (error_code) 7371abe55efSEd Tanous { 73855c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 739179db1d7SKowalski, Kamil return; 740179db1d7SKowalski, Kamil } 741179db1d7SKowalski, Kamil 7424c9afe43SEd Tanous bool found = 7434a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 7444c9afe43SEd Tanous if (!found) 7454c9afe43SEd Tanous { 7464c9afe43SEd Tanous callback(false, ethData, ipv4Data); 7474c9afe43SEd Tanous return; 7484c9afe43SEd Tanous } 7494c9afe43SEd Tanous 7504a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 751179db1d7SKowalski, Kamil 752179db1d7SKowalski, Kamil // Fix global GW 7531abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 7541abe55efSEd Tanous { 7554a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 7564a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 7571abe55efSEd Tanous { 7584a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 759179db1d7SKowalski, Kamil } 760179db1d7SKowalski, Kamil } 761179db1d7SKowalski, Kamil 7624a0cb85cSEd Tanous // Finally make a callback with usefull data 76355c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 764179db1d7SKowalski, Kamil }, 765179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 766179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 767179db1d7SKowalski, Kamil }; 768179db1d7SKowalski, Kamil 769179db1d7SKowalski, Kamil /** 7709391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7719391bb9cSRapkiewicz, Pawel * Manager 7721abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7731abe55efSEd Tanous * into JSON. 7749391bb9cSRapkiewicz, Pawel */ 7759391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7761abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7771abe55efSEd Tanous { 77855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7794a0cb85cSEd Tanous [callback{std::move(callback)}]( 7809391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 7814a0cb85cSEd Tanous GetManagedObjects &resp) { 7821abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7831abe55efSEd Tanous // ethernet interfaces 7844c9afe43SEd Tanous boost::container::flat_set<std::string> iface_list; 7854a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7861abe55efSEd Tanous if (error_code) 7871abe55efSEd Tanous { 7884a0cb85cSEd Tanous callback(false, iface_list); 7899391bb9cSRapkiewicz, Pawel return; 7909391bb9cSRapkiewicz, Pawel } 7919391bb9cSRapkiewicz, Pawel 7929391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7934a0cb85cSEd Tanous for (const auto &objpath : resp) 7941abe55efSEd Tanous { 7959391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7964a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7971abe55efSEd Tanous { 7981abe55efSEd Tanous // If interface is 7994a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 8004a0cb85cSEd Tanous // what we're looking for. 8019391bb9cSRapkiewicz, Pawel if (interface.first == 8021abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 8031abe55efSEd Tanous { 8044a0cb85cSEd Tanous // Cut out everyting until last "/", ... 8054a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 8064a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 8074a0cb85cSEd Tanous if (last_pos != std::string::npos) 8081abe55efSEd Tanous { 8099391bb9cSRapkiewicz, Pawel // and put it into output vector. 8104c9afe43SEd Tanous iface_list.emplace(iface_id.substr(last_pos + 1)); 8119391bb9cSRapkiewicz, Pawel } 8129391bb9cSRapkiewicz, Pawel } 8139391bb9cSRapkiewicz, Pawel } 8149391bb9cSRapkiewicz, Pawel } 815a434f2bdSEd Tanous // Finally make a callback with useful data 8164a0cb85cSEd Tanous callback(true, iface_list); 8179391bb9cSRapkiewicz, Pawel }, 818aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 819aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 8209391bb9cSRapkiewicz, Pawel }; 8219391bb9cSRapkiewicz, Pawel 8229391bb9cSRapkiewicz, Pawel /** 8239391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 8249391bb9cSRapkiewicz, Pawel */ 8251abe55efSEd Tanous class EthernetCollection : public Node 8261abe55efSEd Tanous { 8279391bb9cSRapkiewicz, Pawel public: 8284a0cb85cSEd Tanous template <typename CrowApp> 8291abe55efSEd Tanous EthernetCollection(CrowApp &app) : 8304a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 8311abe55efSEd Tanous { 832588c3f0dSKowalski, Kamil entityPrivileges = { 833588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 834e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 835e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 836e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 837e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 838e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8399391bb9cSRapkiewicz, Pawel } 8409391bb9cSRapkiewicz, Pawel 8419391bb9cSRapkiewicz, Pawel private: 8429391bb9cSRapkiewicz, Pawel /** 8439391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 8449391bb9cSRapkiewicz, Pawel */ 84555c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 8461abe55efSEd Tanous const std::vector<std::string> ¶ms) override 8471abe55efSEd Tanous { 8480f74e643SEd Tanous res.jsonValue["@odata.type"] = 8490f74e643SEd Tanous "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 8500f74e643SEd Tanous res.jsonValue["@odata.context"] = 8510f74e643SEd Tanous "/redfish/v1/" 8520f74e643SEd Tanous "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 8530f74e643SEd Tanous res.jsonValue["@odata.id"] = 8540f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8550f74e643SEd Tanous res.jsonValue["Name"] = "Ethernet Network Interface Collection"; 8560f74e643SEd Tanous res.jsonValue["Description"] = 8570f74e643SEd Tanous "Collection of EthernetInterfaces for this Manager"; 8584c9afe43SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 8594a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 8601abe55efSEd Tanous // preparation 861f12894f8SJason M. Bills getEthernetIfaceList( 8624c9afe43SEd Tanous [asyncResp]( 8634c9afe43SEd Tanous const bool &success, 8644c9afe43SEd Tanous const boost::container::flat_set<std::string> &iface_list) { 8654a0cb85cSEd Tanous if (!success) 8661abe55efSEd Tanous { 8674c9afe43SEd Tanous messages::internalError(asyncResp->res); 8684a0cb85cSEd Tanous return; 8694a0cb85cSEd Tanous } 8704a0cb85cSEd Tanous 8714c9afe43SEd Tanous nlohmann::json &iface_array = 8724c9afe43SEd Tanous asyncResp->res.jsonValue["Members"]; 8734a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 874fda13ad2SSunitha Harish std::string tag = "_"; 8754a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8761abe55efSEd Tanous { 877fda13ad2SSunitha Harish std::size_t found = iface_item.find(tag); 878fda13ad2SSunitha Harish if (found == std::string::npos) 879fda13ad2SSunitha Harish { 8804a0cb85cSEd Tanous iface_array.push_back( 8814a0cb85cSEd Tanous {{"@odata.id", 8824a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 8834a0cb85cSEd Tanous iface_item}}); 8849391bb9cSRapkiewicz, Pawel } 885fda13ad2SSunitha Harish } 8864a0cb85cSEd Tanous 8874c9afe43SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 8884c9afe43SEd Tanous iface_array.size(); 8894c9afe43SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 8904a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8919391bb9cSRapkiewicz, Pawel }); 8929391bb9cSRapkiewicz, Pawel } 8939391bb9cSRapkiewicz, Pawel }; 8949391bb9cSRapkiewicz, Pawel 8959391bb9cSRapkiewicz, Pawel /** 8969391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8979391bb9cSRapkiewicz, Pawel */ 8981abe55efSEd Tanous class EthernetInterface : public Node 8991abe55efSEd Tanous { 9009391bb9cSRapkiewicz, Pawel public: 9019391bb9cSRapkiewicz, Pawel /* 9029391bb9cSRapkiewicz, Pawel * Default Constructor 9039391bb9cSRapkiewicz, Pawel */ 9044a0cb85cSEd Tanous template <typename CrowApp> 9051abe55efSEd Tanous EthernetInterface(CrowApp &app) : 9064a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 9071abe55efSEd Tanous std::string()) 9081abe55efSEd Tanous { 909588c3f0dSKowalski, Kamil entityPrivileges = { 910588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 911e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 912e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 913e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 914e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 915e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 9169391bb9cSRapkiewicz, Pawel } 9179391bb9cSRapkiewicz, Pawel 918e439f0f8SKowalski, Kamil private: 919bc0bd6e0SEd Tanous void handleHostnamePatch(const std::string &hostname, 9204a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9211abe55efSEd Tanous { 922bc0bd6e0SEd Tanous asyncResp->res.jsonValue["HostName"] = hostname; 923bc0bd6e0SEd Tanous crow::connections::systemBus->async_method_call( 924bc0bd6e0SEd Tanous [asyncResp](const boost::system::error_code ec) { 9254a0cb85cSEd Tanous if (ec) 9264a0cb85cSEd Tanous { 927a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 9281abe55efSEd Tanous } 929bc0bd6e0SEd Tanous }, 930bc0bd6e0SEd Tanous "xyz.openbmc_project.Network", 931bc0bd6e0SEd Tanous "/xyz/openbmc_project/network/config", 932bc0bd6e0SEd Tanous "org.freedesktop.DBus.Properties", "Set", 933bc0bd6e0SEd Tanous "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 934abf2add6SEd Tanous std::variant<std::string>(hostname)); 935588c3f0dSKowalski, Kamil } 936588c3f0dSKowalski, Kamil 937d577665bSRatan Gupta void handleMACAddressPatch(const std::string &ifaceId, 938d577665bSRatan Gupta const std::string &macAddress, 939d577665bSRatan Gupta const std::shared_ptr<AsyncResp> &asyncResp) 940d577665bSRatan Gupta { 941d577665bSRatan Gupta crow::connections::systemBus->async_method_call( 942d577665bSRatan Gupta [asyncResp, macAddress](const boost::system::error_code ec) { 943d577665bSRatan Gupta if (ec) 944d577665bSRatan Gupta { 945d577665bSRatan Gupta messages::internalError(asyncResp->res); 946d577665bSRatan Gupta return; 947d577665bSRatan Gupta } 948d577665bSRatan Gupta asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress); 949d577665bSRatan Gupta }, 950d577665bSRatan Gupta "xyz.openbmc_project.Network", 951d577665bSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId, 952d577665bSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 953d577665bSRatan Gupta "xyz.openbmc_project.Network.MACAddress", "MACAddress", 954d577665bSRatan Gupta std::variant<std::string>(macAddress)); 955d577665bSRatan Gupta } 956*da131a9aSJennifer Lee void setDHCPEnabled(const std::string &ifaceId, 957*da131a9aSJennifer Lee const std::string &propertyName, const bool &value, 958*da131a9aSJennifer Lee const std::shared_ptr<AsyncResp> asyncResp) 959*da131a9aSJennifer Lee { 960*da131a9aSJennifer Lee crow::connections::systemBus->async_method_call( 961*da131a9aSJennifer Lee [asyncResp](const boost::system::error_code ec) { 962*da131a9aSJennifer Lee if (ec) 963*da131a9aSJennifer Lee { 964*da131a9aSJennifer Lee BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 965*da131a9aSJennifer Lee messages::internalError(asyncResp->res); 966*da131a9aSJennifer Lee return; 967*da131a9aSJennifer Lee } 968*da131a9aSJennifer Lee }, 969*da131a9aSJennifer Lee "xyz.openbmc_project.Network", 970*da131a9aSJennifer Lee "/xyz/openbmc_project/network/" + ifaceId, 971*da131a9aSJennifer Lee "org.freedesktop.DBus.Properties", "Set", 972*da131a9aSJennifer Lee "xyz.openbmc_project.Network.EthernetInterface", propertyName, 973*da131a9aSJennifer Lee std::variant<bool>{value}); 974*da131a9aSJennifer Lee } 975*da131a9aSJennifer Lee void setDHCPv4Config(const std::string &propertyName, const bool &value, 976*da131a9aSJennifer Lee const std::shared_ptr<AsyncResp> asyncResp) 977*da131a9aSJennifer Lee { 978*da131a9aSJennifer Lee BMCWEB_LOG_DEBUG << propertyName << " = " << value; 979*da131a9aSJennifer Lee crow::connections::systemBus->async_method_call( 980*da131a9aSJennifer Lee [asyncResp](const boost::system::error_code ec) { 981*da131a9aSJennifer Lee if (ec) 982*da131a9aSJennifer Lee { 983*da131a9aSJennifer Lee BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 984*da131a9aSJennifer Lee messages::internalError(asyncResp->res); 985*da131a9aSJennifer Lee return; 986*da131a9aSJennifer Lee } 987*da131a9aSJennifer Lee }, 988*da131a9aSJennifer Lee "xyz.openbmc_project.Network", 989*da131a9aSJennifer Lee "/xyz/openbmc_project/network/config/dhcp", 990*da131a9aSJennifer Lee "org.freedesktop.DBus.Properties", "Set", 991*da131a9aSJennifer Lee "xyz.openbmc_project.Network.DHCPConfiguration", propertyName, 992*da131a9aSJennifer Lee std::variant<bool>{value}); 993*da131a9aSJennifer Lee } 994d577665bSRatan Gupta 995*da131a9aSJennifer Lee void handleDHCPv4Patch(const std::string &ifaceId, nlohmann::json &input, 996*da131a9aSJennifer Lee const std::shared_ptr<AsyncResp> asyncResp) 997*da131a9aSJennifer Lee { 998*da131a9aSJennifer Lee std::optional<bool> dhcpEnabled; 999*da131a9aSJennifer Lee std::optional<bool> useDNSServers; 1000*da131a9aSJennifer Lee std::optional<bool> useDomainName; 1001*da131a9aSJennifer Lee std::optional<bool> useNTPServers; 1002*da131a9aSJennifer Lee 1003*da131a9aSJennifer Lee if (!json_util::readJson(input, asyncResp->res, "DHCPEnabled", 1004*da131a9aSJennifer Lee dhcpEnabled, "UseDNSServers", useDNSServers, 1005*da131a9aSJennifer Lee "UseDomainName", useDomainName, 1006*da131a9aSJennifer Lee "UseNTPServers", useNTPServers)) 1007*da131a9aSJennifer Lee { 1008*da131a9aSJennifer Lee return; 1009*da131a9aSJennifer Lee } 1010*da131a9aSJennifer Lee 1011*da131a9aSJennifer Lee if (dhcpEnabled) 1012*da131a9aSJennifer Lee { 1013*da131a9aSJennifer Lee BMCWEB_LOG_DEBUG << "set DHCPEnabled..."; 1014*da131a9aSJennifer Lee setDHCPEnabled(ifaceId, "DHCPEnabled", *dhcpEnabled, asyncResp); 1015*da131a9aSJennifer Lee } 1016*da131a9aSJennifer Lee 1017*da131a9aSJennifer Lee if (useDNSServers) 1018*da131a9aSJennifer Lee { 1019*da131a9aSJennifer Lee BMCWEB_LOG_DEBUG << "set DNSEnabled..."; 1020*da131a9aSJennifer Lee setDHCPv4Config("DNSEnabled", *useDNSServers, asyncResp); 1021*da131a9aSJennifer Lee } 1022*da131a9aSJennifer Lee 1023*da131a9aSJennifer Lee if (useDomainName) 1024*da131a9aSJennifer Lee { 1025*da131a9aSJennifer Lee BMCWEB_LOG_DEBUG << "set HostNameEnabled..."; 1026*da131a9aSJennifer Lee setDHCPv4Config("HostNameEnabled", *useDomainName, asyncResp); 1027*da131a9aSJennifer Lee } 1028*da131a9aSJennifer Lee 1029*da131a9aSJennifer Lee if (useNTPServers) 1030*da131a9aSJennifer Lee { 1031*da131a9aSJennifer Lee BMCWEB_LOG_DEBUG << "set NTPEnabled..."; 1032*da131a9aSJennifer Lee setDHCPv4Config("NTPEnabled", *useNTPServers, asyncResp); 1033*da131a9aSJennifer Lee } 1034*da131a9aSJennifer Lee } 10354a0cb85cSEd Tanous void handleIPv4Patch( 1036f476acbfSRatan Gupta const std::string &ifaceId, nlohmann::json &input, 10374a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 10384a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 10391abe55efSEd Tanous { 1040f476acbfSRatan Gupta if (!input.is_array()) 1041f476acbfSRatan Gupta { 1042f476acbfSRatan Gupta messages::propertyValueTypeError(asyncResp->res, input.dump(), 1043f476acbfSRatan Gupta "IPv4Addresses"); 1044f476acbfSRatan Gupta return; 1045f476acbfSRatan Gupta } 1046f476acbfSRatan Gupta 10474a0cb85cSEd Tanous int entryIdx = 0; 10484a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 10494a0cb85cSEd Tanous ipv4Data.begin(); 1050537174c4SEd Tanous for (nlohmann::json &thisJson : input) 10511abe55efSEd Tanous { 10524a0cb85cSEd Tanous std::string pathString = 1053a08b46ccSJason M. Bills "IPv4Addresses/" + std::to_string(entryIdx); 1054179db1d7SKowalski, Kamil 1055f476acbfSRatan Gupta if (thisJson.is_null()) 1056f476acbfSRatan Gupta { 1057f476acbfSRatan Gupta if (thisData != ipv4Data.end()) 1058f476acbfSRatan Gupta { 1059f476acbfSRatan Gupta deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp); 1060f476acbfSRatan Gupta thisData++; 1061f476acbfSRatan Gupta } 1062f476acbfSRatan Gupta else 1063f476acbfSRatan Gupta { 1064f476acbfSRatan Gupta messages::propertyValueFormatError( 1065f476acbfSRatan Gupta asyncResp->res, input.dump(), pathString); 1066f476acbfSRatan Gupta return; 1067f476acbfSRatan Gupta // TODO(ratagupt) Not sure about the property where value is 1068f476acbfSRatan Gupta // list and if unable to update one of the 1069f476acbfSRatan Gupta // list value then should we proceed further or 1070f476acbfSRatan Gupta // break there, would ask in the redfish forum 1071f476acbfSRatan Gupta // till then we stop processing the next list item. 1072f476acbfSRatan Gupta } 1073f476acbfSRatan Gupta entryIdx++; 1074f476acbfSRatan Gupta continue; // not an error as per the redfish spec. 1075f476acbfSRatan Gupta } 1076f476acbfSRatan Gupta 10779474b378SRatan Gupta if (thisJson.empty()) 10789474b378SRatan Gupta { 10799474b378SRatan Gupta if (thisData != ipv4Data.end()) 10809474b378SRatan Gupta { 10819474b378SRatan Gupta thisData++; 10829474b378SRatan Gupta } 10839474b378SRatan Gupta else 10849474b378SRatan Gupta { 10859474b378SRatan Gupta messages::propertyMissing(asyncResp->res, 10869474b378SRatan Gupta pathString + "/Address"); 10879474b378SRatan Gupta return; 1088f476acbfSRatan Gupta // TODO(ratagupt) Not sure about the property where value is 10899474b378SRatan Gupta // list and if unable to update one of the 10909474b378SRatan Gupta // list value then should we proceed further or 10919474b378SRatan Gupta // break there, would ask in the redfish forum 10929474b378SRatan Gupta // till then we stop processing the next list item. 10939474b378SRatan Gupta } 10949474b378SRatan Gupta entryIdx++; 10959474b378SRatan Gupta continue; // not an error as per the redfish spec. 10969474b378SRatan Gupta } 10979474b378SRatan Gupta 1098537174c4SEd Tanous std::optional<std::string> address; 1099537174c4SEd Tanous std::optional<std::string> addressOrigin; 1100537174c4SEd Tanous std::optional<std::string> subnetMask; 1101537174c4SEd Tanous std::optional<std::string> gateway; 1102537174c4SEd Tanous 1103537174c4SEd Tanous if (!json_util::readJson(thisJson, asyncResp->res, "Address", 1104537174c4SEd Tanous address, "AddressOrigin", addressOrigin, 1105537174c4SEd Tanous "SubnetMask", subnetMask, "Gateway", 1106537174c4SEd Tanous gateway)) 1107537174c4SEd Tanous { 1108537174c4SEd Tanous return; 1109179db1d7SKowalski, Kamil } 1110179db1d7SKowalski, Kamil 1111537174c4SEd Tanous if (address) 11121abe55efSEd Tanous { 1113537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*address)) 11141abe55efSEd Tanous { 1115537174c4SEd Tanous messages::propertyValueFormatError(asyncResp->res, *address, 11164a0cb85cSEd Tanous pathString + "/Address"); 1117537174c4SEd Tanous return; 11184a0cb85cSEd Tanous } 11194a0cb85cSEd Tanous } 11204a0cb85cSEd Tanous 1121537174c4SEd Tanous uint8_t prefixLength = 0; 1122537174c4SEd Tanous if (subnetMask) 11234a0cb85cSEd Tanous { 1124537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 11254a0cb85cSEd Tanous { 1126f12894f8SJason M. Bills messages::propertyValueFormatError( 1127537174c4SEd Tanous asyncResp->res, *subnetMask, 11284a0cb85cSEd Tanous pathString + "/SubnetMask"); 1129537174c4SEd Tanous return; 11304a0cb85cSEd Tanous } 11314a0cb85cSEd Tanous } 11324a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 1133537174c4SEd Tanous if (addressOrigin) 11344a0cb85cSEd Tanous { 11354a0cb85cSEd Tanous // Get Address origin in proper format 11364a0cb85cSEd Tanous addressOriginInDBusFormat = 1137537174c4SEd Tanous translateAddressOriginRedfishToDbus(*addressOrigin); 11384a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 11394a0cb85cSEd Tanous { 11404a0cb85cSEd Tanous messages::propertyValueNotInList( 1141537174c4SEd Tanous asyncResp->res, *addressOrigin, 1142a08b46ccSJason M. Bills pathString + "/AddressOrigin"); 1143537174c4SEd Tanous return; 11444a0cb85cSEd Tanous } 11454a0cb85cSEd Tanous } 11464a0cb85cSEd Tanous 1147537174c4SEd Tanous if (gateway) 11484a0cb85cSEd Tanous { 1149537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*gateway)) 11504a0cb85cSEd Tanous { 1151537174c4SEd Tanous messages::propertyValueFormatError(asyncResp->res, *gateway, 1152537174c4SEd Tanous pathString + "/Gateway"); 1153537174c4SEd Tanous return; 11544a0cb85cSEd Tanous } 11554a0cb85cSEd Tanous } 11564a0cb85cSEd Tanous 1157f476acbfSRatan Gupta // if IP address exist then modify it. 11584a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 11594a0cb85cSEd Tanous { 1160179db1d7SKowalski, Kamil // Apply changes 1161537174c4SEd Tanous if (address) 11621abe55efSEd Tanous { 1163f476acbfSRatan Gupta auto callback = [asyncResp, entryIdx, 1164f476acbfSRatan Gupta address{std::string(*address)}]( 11654a0cb85cSEd Tanous const boost::system::error_code ec) { 11664a0cb85cSEd Tanous if (ec) 11671abe55efSEd Tanous { 1168a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11694a0cb85cSEd Tanous return; 11704a0cb85cSEd Tanous } 1171f476acbfSRatan Gupta asyncResp->res 1172f476acbfSRatan Gupta .jsonValue["IPv4Addresses"][entryIdx]["Address"] = 1173f476acbfSRatan Gupta std::move(address); 11744a0cb85cSEd Tanous }; 11754a0cb85cSEd Tanous 11764a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11774a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1178f476acbfSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 1179f476acbfSRatan Gupta thisData->id, 11804a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11814a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 1182537174c4SEd Tanous std::variant<std::string>(*address)); 1183179db1d7SKowalski, Kamil } 1184179db1d7SKowalski, Kamil 1185537174c4SEd Tanous if (subnetMask) 11861abe55efSEd Tanous { 11874a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 1188537174c4SEd Tanous thisData->id, *subnetMask, 1189537174c4SEd Tanous prefixLength, asyncResp); 1190179db1d7SKowalski, Kamil } 1191179db1d7SKowalski, Kamil 1192537174c4SEd Tanous if (addressOrigin) 11931abe55efSEd Tanous { 11944a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 1195f476acbfSRatan Gupta *addressOrigin, addressOriginInDBusFormat, 1196f476acbfSRatan Gupta asyncResp); 1197179db1d7SKowalski, Kamil } 1198179db1d7SKowalski, Kamil 1199537174c4SEd Tanous if (gateway) 12001abe55efSEd Tanous { 1201f476acbfSRatan Gupta auto callback = [asyncResp, entryIdx, 1202537174c4SEd Tanous gateway{std::string(*gateway)}]( 12034a0cb85cSEd Tanous const boost::system::error_code ec) { 12044a0cb85cSEd Tanous if (ec) 12051abe55efSEd Tanous { 1206a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 12074a0cb85cSEd Tanous return; 12084a0cb85cSEd Tanous } 1209f476acbfSRatan Gupta asyncResp->res 1210f476acbfSRatan Gupta .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] = 1211537174c4SEd Tanous std::move(gateway); 12124a0cb85cSEd Tanous }; 12134a0cb85cSEd Tanous 12144a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 12154a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1216f476acbfSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 1217f476acbfSRatan Gupta thisData->id, 12184a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 12194a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 1220537174c4SEd Tanous std::variant<std::string>(*gateway)); 12214a0cb85cSEd Tanous } 1222f476acbfSRatan Gupta 12234a0cb85cSEd Tanous thisData++; 12241abe55efSEd Tanous } 12251abe55efSEd Tanous else 12261abe55efSEd Tanous { 12274a0cb85cSEd Tanous // Create IPv4 with provided data 1228537174c4SEd Tanous if (!gateway) 12291abe55efSEd Tanous { 1230a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12314a0cb85cSEd Tanous pathString + "/Gateway"); 12324a0cb85cSEd Tanous continue; 12334a0cb85cSEd Tanous } 12344a0cb85cSEd Tanous 1235537174c4SEd Tanous if (!address) 12361abe55efSEd Tanous { 1237a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12384a0cb85cSEd Tanous pathString + "/Address"); 12394a0cb85cSEd Tanous continue; 12404a0cb85cSEd Tanous } 12414a0cb85cSEd Tanous 1242537174c4SEd Tanous if (!subnetMask) 12431abe55efSEd Tanous { 1244a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 12454a0cb85cSEd Tanous pathString + "/SubnetMask"); 12464a0cb85cSEd Tanous continue; 1247588c3f0dSKowalski, Kamil } 1248588c3f0dSKowalski, Kamil 1249b01bf299SEd Tanous createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address, 1250b01bf299SEd Tanous asyncResp); 125195897b20SRatan Gupta 125295897b20SRatan Gupta nlohmann::json &ipv4AddressJson = 125395897b20SRatan Gupta asyncResp->res.jsonValue["IPv4Addresses"][entryIdx]; 125495897b20SRatan Gupta ipv4AddressJson["Address"] = *address; 125595897b20SRatan Gupta ipv4AddressJson["SubnetMask"] = *subnetMask; 125695897b20SRatan Gupta ipv4AddressJson["Gateway"] = *gateway; 12574a0cb85cSEd Tanous } 12584a0cb85cSEd Tanous entryIdx++; 12594a0cb85cSEd Tanous } 12604a0cb85cSEd Tanous } 12614a0cb85cSEd Tanous 1262f85837bfSRAJESWARAN THILLAIGOVINDAN void handleStaticNameServersPatch( 1263f85837bfSRAJESWARAN THILLAIGOVINDAN const std::string &ifaceId, 1264f85837bfSRAJESWARAN THILLAIGOVINDAN const std::vector<std::string> &updatedStaticNameServers, 1265f85837bfSRAJESWARAN THILLAIGOVINDAN const std::shared_ptr<AsyncResp> &asyncResp) 1266f85837bfSRAJESWARAN THILLAIGOVINDAN { 1267f85837bfSRAJESWARAN THILLAIGOVINDAN crow::connections::systemBus->async_method_call( 1268f85837bfSRAJESWARAN THILLAIGOVINDAN [asyncResp, 1269f85837bfSRAJESWARAN THILLAIGOVINDAN updatedStaticNameServers](const boost::system::error_code ec) { 1270f85837bfSRAJESWARAN THILLAIGOVINDAN if (ec) 1271f85837bfSRAJESWARAN THILLAIGOVINDAN { 1272f85837bfSRAJESWARAN THILLAIGOVINDAN messages::internalError(asyncResp->res); 1273f85837bfSRAJESWARAN THILLAIGOVINDAN return; 1274f85837bfSRAJESWARAN THILLAIGOVINDAN } 1275f85837bfSRAJESWARAN THILLAIGOVINDAN asyncResp->res.jsonValue["NameServers"] = 1276f85837bfSRAJESWARAN THILLAIGOVINDAN updatedStaticNameServers; 1277f85837bfSRAJESWARAN THILLAIGOVINDAN asyncResp->res.jsonValue["StaticNameServers"] = 1278f85837bfSRAJESWARAN THILLAIGOVINDAN updatedStaticNameServers; 1279f85837bfSRAJESWARAN THILLAIGOVINDAN }, 1280f85837bfSRAJESWARAN THILLAIGOVINDAN "xyz.openbmc_project.Network", 1281f85837bfSRAJESWARAN THILLAIGOVINDAN "/xyz/openbmc_project/network/" + ifaceId, 1282f85837bfSRAJESWARAN THILLAIGOVINDAN "org.freedesktop.DBus.Properties", "Set", 1283f85837bfSRAJESWARAN THILLAIGOVINDAN "xyz.openbmc_project.Network.EthernetInterface", "Nameservers", 1284f85837bfSRAJESWARAN THILLAIGOVINDAN std::variant<std::vector<std::string>>{updatedStaticNameServers}); 1285f85837bfSRAJESWARAN THILLAIGOVINDAN } 1286f85837bfSRAJESWARAN THILLAIGOVINDAN 12870f74e643SEd Tanous void parseInterfaceData( 12880f74e643SEd Tanous nlohmann::json &json_response, const std::string &iface_id, 12890f74e643SEd Tanous const EthernetInterfaceData ðData, 12904a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 12914a0cb85cSEd Tanous { 12924a0cb85cSEd Tanous json_response["Id"] = iface_id; 12934a0cb85cSEd Tanous json_response["@odata.id"] = 12944a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 1295029573d4SEd Tanous json_response["InterfaceEnabled"] = true; 1296029573d4SEd Tanous if (ethData.speed == 0) 1297029573d4SEd Tanous { 1298029573d4SEd Tanous json_response["LinkStatus"] = "NoLink"; 1299029573d4SEd Tanous json_response["Status"] = { 1300029573d4SEd Tanous {"Health", "OK"}, 1301029573d4SEd Tanous {"State", "Disabled"}, 1302029573d4SEd Tanous }; 1303029573d4SEd Tanous } 1304029573d4SEd Tanous else 1305029573d4SEd Tanous { 1306029573d4SEd Tanous json_response["LinkStatus"] = "LinkUp"; 1307029573d4SEd Tanous json_response["Status"] = { 1308029573d4SEd Tanous {"Health", "OK"}, 1309029573d4SEd Tanous {"State", "Enabled"}, 1310029573d4SEd Tanous }; 1311029573d4SEd Tanous } 13124a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 13134a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 1314fda13ad2SSunitha Harish json_response["DHCPv4"]["DHCPEnabled"] = ethData.DHCPEnabled; 13152a133282Smanojkiraneda 13164a0cb85cSEd Tanous if (!ethData.hostname.empty()) 13174a0cb85cSEd Tanous { 13184a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 13194a0cb85cSEd Tanous } 13204a0cb85cSEd Tanous 1321fda13ad2SSunitha Harish json_response["VLANs"] = { 1322fda13ad2SSunitha Harish {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 1323fda13ad2SSunitha Harish iface_id + "/VLANs"}}; 1324fda13ad2SSunitha Harish 1325029573d4SEd Tanous json_response["NameServers"] = ethData.nameservers; 1326f85837bfSRAJESWARAN THILLAIGOVINDAN json_response["StaticNameServers"] = ethData.nameservers; 13274a0cb85cSEd Tanous 13284a0cb85cSEd Tanous if (ipv4Data.size() > 0) 13294a0cb85cSEd Tanous { 13304a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 13314a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 13324a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 13334a0cb85cSEd Tanous { 1334fa5053a6SGunnar Mills 1335fa5053a6SGunnar Mills std::string gatewayStr = ipv4_config.gateway; 1336fa5053a6SGunnar Mills if (gatewayStr.empty()) 1337fa5053a6SGunnar Mills { 1338fa5053a6SGunnar Mills gatewayStr = "0.0.0.0"; 1339fa5053a6SGunnar Mills } 1340fa5053a6SGunnar Mills 13414a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 13424a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 1343029573d4SEd Tanous {"Address", ipv4_config.address}, 1344fa5053a6SGunnar Mills {"Gateway", gatewayStr}}); 13454a0cb85cSEd Tanous } 13464a0cb85cSEd Tanous } 13479a6fc6feSRavi Teja json_response["IPv6DefaultGateway"] = ethData.ipv6_default_gateway; 1348588c3f0dSKowalski, Kamil } 1349588c3f0dSKowalski, Kamil 13509391bb9cSRapkiewicz, Pawel /** 13519391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 13529391bb9cSRapkiewicz, Pawel */ 135355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 13541abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13551abe55efSEd Tanous { 13564a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13571abe55efSEd Tanous if (params.size() != 1) 13581abe55efSEd Tanous { 1359f12894f8SJason M. Bills messages::internalError(asyncResp->res); 13609391bb9cSRapkiewicz, Pawel return; 13619391bb9cSRapkiewicz, Pawel } 13629391bb9cSRapkiewicz, Pawel 13634a0cb85cSEd Tanous getEthernetIfaceData( 13644a0cb85cSEd Tanous params[0], 13654a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 13664a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13674a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13684a0cb85cSEd Tanous if (!success) 13691abe55efSEd Tanous { 13701abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13711abe55efSEd Tanous // object, and other errors 1372f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1373f12894f8SJason M. Bills "EthernetInterface", iface_id); 13744a0cb85cSEd Tanous return; 13759391bb9cSRapkiewicz, Pawel } 13764c9afe43SEd Tanous 13774c9afe43SEd Tanous // because this has no dependence on the interface at this 13784c9afe43SEd Tanous // point, it needs to be done after we know the interface 13794c9afe43SEd Tanous // exists, not before. 13804c9afe43SEd Tanous getDHCPConfigData(asyncResp); 13814c9afe43SEd Tanous 13820f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 1383fda13ad2SSunitha Harish "#EthernetInterface.v1_4_1.EthernetInterface"; 13840f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 13850f74e643SEd Tanous "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 13860f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; 13870f74e643SEd Tanous asyncResp->res.jsonValue["Description"] = 13880f74e643SEd Tanous "Management Network Interface"; 13890f74e643SEd Tanous 13900f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13910f74e643SEd Tanous ipv4Data); 13929391bb9cSRapkiewicz, Pawel }); 13939391bb9cSRapkiewicz, Pawel } 13949391bb9cSRapkiewicz, Pawel 139555c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 13961abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13971abe55efSEd Tanous { 13984a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13991abe55efSEd Tanous if (params.size() != 1) 14001abe55efSEd Tanous { 1401f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1402588c3f0dSKowalski, Kamil return; 1403588c3f0dSKowalski, Kamil } 1404588c3f0dSKowalski, Kamil 14054a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1406588c3f0dSKowalski, Kamil 1407bc0bd6e0SEd Tanous std::optional<std::string> hostname; 1408d577665bSRatan Gupta std::optional<std::string> macAddress; 14099a6fc6feSRavi Teja std::optional<std::string> ipv6DefaultGateway; 1410f476acbfSRatan Gupta std::optional<nlohmann::json> ipv4Addresses; 1411f476acbfSRatan Gupta std::optional<nlohmann::json> ipv6Addresses; 1412f85837bfSRAJESWARAN THILLAIGOVINDAN std::optional<std::vector<std::string>> staticNameServers; 14135112e9b4SRAJESWARAN THILLAIGOVINDAN std::optional<std::vector<std::string>> nameServers; 1414*da131a9aSJennifer Lee std::optional<nlohmann::json> dhcpv4; 14150627a2c7SEd Tanous 1416fda13ad2SSunitha Harish if (!json_util::readJson( 1417fda13ad2SSunitha Harish req, res, "HostName", hostname, "IPv4Addresses", ipv4Addresses, 1418f85837bfSRAJESWARAN THILLAIGOVINDAN "IPv6Addresses", ipv6Addresses, "MACAddress", macAddress, 14199a6fc6feSRavi Teja "StaticNameServers", staticNameServers, "IPv6DefaultGateway", 1420*da131a9aSJennifer Lee ipv6DefaultGateway, "NameServers", nameServers, "DHCPv4", 1421*da131a9aSJennifer Lee dhcpv4)) 14221abe55efSEd Tanous { 1423588c3f0dSKowalski, Kamil return; 1424588c3f0dSKowalski, Kamil } 1425f15aad37SRatan Gupta 1426*da131a9aSJennifer Lee if (dhcpv4) 1427*da131a9aSJennifer Lee { 1428*da131a9aSJennifer Lee handleDHCPv4Patch(iface_id, *dhcpv4, asyncResp); 1429*da131a9aSJennifer Lee } 1430*da131a9aSJennifer Lee 14314a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1432588c3f0dSKowalski, Kamil // preparation 14334a0cb85cSEd Tanous getEthernetIfaceData( 14344a0cb85cSEd Tanous iface_id, 1435fda13ad2SSunitha Harish [this, asyncResp, iface_id, hostname = std::move(hostname), 1436fda13ad2SSunitha Harish macAddress = std::move(macAddress), 14370627a2c7SEd Tanous ipv4Addresses = std::move(ipv4Addresses), 1438f85837bfSRAJESWARAN THILLAIGOVINDAN ipv6Addresses = std::move(ipv6Addresses), 14399a6fc6feSRavi Teja ipv6DefaultGateway = std::move(ipv6DefaultGateway), 14405112e9b4SRAJESWARAN THILLAIGOVINDAN staticNameServers = std::move(staticNameServers), 14415112e9b4SRAJESWARAN THILLAIGOVINDAN nameServers = std::move(nameServers)]( 14424a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 14434a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 14441abe55efSEd Tanous if (!success) 14451abe55efSEd Tanous { 1446588c3f0dSKowalski, Kamil // ... otherwise return error 14471abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 14481abe55efSEd Tanous // object, and other errors 1449fda13ad2SSunitha Harish messages::resourceNotFound(asyncResp->res, 1450fda13ad2SSunitha Harish "Ethernet Interface", iface_id); 1451588c3f0dSKowalski, Kamil return; 1452588c3f0dSKowalski, Kamil } 1453588c3f0dSKowalski, Kamil 14540f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 14550f74e643SEd Tanous ipv4Data); 1456588c3f0dSKowalski, Kamil 14570627a2c7SEd Tanous if (hostname) 14581abe55efSEd Tanous { 14590627a2c7SEd Tanous handleHostnamePatch(*hostname, asyncResp); 14601abe55efSEd Tanous } 14610627a2c7SEd Tanous 1462d577665bSRatan Gupta if (macAddress) 1463d577665bSRatan Gupta { 1464d577665bSRatan Gupta handleMACAddressPatch(iface_id, *macAddress, asyncResp); 1465d577665bSRatan Gupta } 1466d577665bSRatan Gupta 14670627a2c7SEd Tanous if (ipv4Addresses) 14681abe55efSEd Tanous { 1469537174c4SEd Tanous // TODO(ed) for some reason the capture of ipv4Addresses 1470537174c4SEd Tanous // above is returning a const value, not a non-const value. 1471537174c4SEd Tanous // This doesn't really work for us, as we need to be able to 1472537174c4SEd Tanous // efficiently move out the intermedia nlohmann::json 1473537174c4SEd Tanous // objects. This makes a copy of the structure, and operates 1474537174c4SEd Tanous // on that, but could be done more efficiently 1475f476acbfSRatan Gupta nlohmann::json ipv4 = std::move(*ipv4Addresses); 1476537174c4SEd Tanous handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp); 14771abe55efSEd Tanous } 14780627a2c7SEd Tanous 14795112e9b4SRAJESWARAN THILLAIGOVINDAN if (nameServers) 14805112e9b4SRAJESWARAN THILLAIGOVINDAN { 14815112e9b4SRAJESWARAN THILLAIGOVINDAN // Data.Permissions is read-only 14825112e9b4SRAJESWARAN THILLAIGOVINDAN messages::propertyNotWritable(asyncResp->res, 14835112e9b4SRAJESWARAN THILLAIGOVINDAN "NameServers"); 14845112e9b4SRAJESWARAN THILLAIGOVINDAN } 14855112e9b4SRAJESWARAN THILLAIGOVINDAN 14860627a2c7SEd Tanous if (ipv6Addresses) 14871abe55efSEd Tanous { 1488179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1489a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, 14900627a2c7SEd Tanous "IPv6Addresses"); 1491588c3f0dSKowalski, Kamil } 1492f85837bfSRAJESWARAN THILLAIGOVINDAN 1493f85837bfSRAJESWARAN THILLAIGOVINDAN if (staticNameServers) 1494f85837bfSRAJESWARAN THILLAIGOVINDAN { 1495f85837bfSRAJESWARAN THILLAIGOVINDAN handleStaticNameServersPatch(iface_id, *staticNameServers, 1496f85837bfSRAJESWARAN THILLAIGOVINDAN asyncResp); 1497f85837bfSRAJESWARAN THILLAIGOVINDAN } 14989a6fc6feSRavi Teja 14999a6fc6feSRavi Teja if (ipv6DefaultGateway) 15009a6fc6feSRavi Teja { 15019a6fc6feSRavi Teja messages::propertyNotWritable(asyncResp->res, 15029a6fc6feSRavi Teja "IPv6DefaultGateway"); 15039a6fc6feSRavi Teja } 1504588c3f0dSKowalski, Kamil }); 1505588c3f0dSKowalski, Kamil } 15069391bb9cSRapkiewicz, Pawel }; 15079391bb9cSRapkiewicz, Pawel 1508e439f0f8SKowalski, Kamil /** 15094a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 15104a0cb85cSEd Tanous * Schema 1511e439f0f8SKowalski, Kamil */ 15121abe55efSEd Tanous class VlanNetworkInterface : public Node 15131abe55efSEd Tanous { 1514e439f0f8SKowalski, Kamil public: 1515e439f0f8SKowalski, Kamil /* 1516e439f0f8SKowalski, Kamil * Default Constructor 1517e439f0f8SKowalski, Kamil */ 1518e439f0f8SKowalski, Kamil template <typename CrowApp> 15191abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 15204a0cb85cSEd Tanous Node(app, 15210f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>", 15221abe55efSEd Tanous std::string(), std::string()) 15231abe55efSEd Tanous { 1524e439f0f8SKowalski, Kamil entityPrivileges = { 1525e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1526e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1527e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1528e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1529e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1530e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1531e439f0f8SKowalski, Kamil } 1532e439f0f8SKowalski, Kamil 1533e439f0f8SKowalski, Kamil private: 15340f74e643SEd Tanous void parseInterfaceData( 15350f74e643SEd Tanous nlohmann::json &json_response, const std::string &parent_iface_id, 15360f74e643SEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 15374a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 15381abe55efSEd Tanous { 1539e439f0f8SKowalski, Kamil // Fill out obvious data... 15404a0cb85cSEd Tanous json_response["Id"] = iface_id; 15414a0cb85cSEd Tanous json_response["@odata.id"] = 15424a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 15434a0cb85cSEd Tanous "/VLANs/" + iface_id; 1544e439f0f8SKowalski, Kamil 15454a0cb85cSEd Tanous json_response["VLANEnable"] = true; 1546fda13ad2SSunitha Harish if (!ethData.vlan_id.empty()) 15474a0cb85cSEd Tanous { 1548fda13ad2SSunitha Harish json_response["VLANId"] = ethData.vlan_id.back(); 15494a0cb85cSEd Tanous } 1550e439f0f8SKowalski, Kamil } 1551e439f0f8SKowalski, Kamil 1552fda13ad2SSunitha Harish bool verifyNames(const std::string &parent, const std::string &iface) 15531abe55efSEd Tanous { 15541abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 15551abe55efSEd Tanous { 1556927a505aSKowalski, Kamil return false; 15571abe55efSEd Tanous } 15581abe55efSEd Tanous else 15591abe55efSEd Tanous { 1560927a505aSKowalski, Kamil return true; 1561927a505aSKowalski, Kamil } 1562927a505aSKowalski, Kamil } 1563927a505aSKowalski, Kamil 1564e439f0f8SKowalski, Kamil /** 1565e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1566e439f0f8SKowalski, Kamil */ 156755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 15681abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15691abe55efSEd Tanous { 15704a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15714a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1572e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1573e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1574e439f0f8SKowalski, Kamil // impossible. 15751abe55efSEd Tanous if (params.size() != 2) 15761abe55efSEd Tanous { 1577f12894f8SJason M. Bills messages::internalError(res); 1578e439f0f8SKowalski, Kamil res.end(); 1579e439f0f8SKowalski, Kamil return; 1580e439f0f8SKowalski, Kamil } 1581e439f0f8SKowalski, Kamil 15824a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 15834a0cb85cSEd Tanous const std::string &iface_id = params[1]; 15840f74e643SEd Tanous res.jsonValue["@odata.type"] = 15850f74e643SEd Tanous "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 15860f74e643SEd Tanous res.jsonValue["@odata.context"] = 15870f74e643SEd Tanous "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 15880f74e643SEd Tanous res.jsonValue["Name"] = "VLAN Network Interface"; 1589e439f0f8SKowalski, Kamil 1590fda13ad2SSunitha Harish if (!verifyNames(parent_iface_id, iface_id)) 15911abe55efSEd Tanous { 1592a434f2bdSEd Tanous return; 1593a434f2bdSEd Tanous } 1594a434f2bdSEd Tanous 1595e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1596e439f0f8SKowalski, Kamil // preparation 15974a0cb85cSEd Tanous getEthernetIfaceData( 1598fda13ad2SSunitha Harish params[1], 1599fda13ad2SSunitha Harish [this, asyncResp, parent_iface_id{std::string(params[0])}, 1600fda13ad2SSunitha Harish iface_id{std::string(params[1])}]( 16014a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 16024a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 1603fda13ad2SSunitha Harish if (success && ethData.vlan_id.size() != 0) 16041abe55efSEd Tanous { 16050f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, 16060f74e643SEd Tanous parent_iface_id, iface_id, ethData, 16070f74e643SEd Tanous ipv4Data); 16081abe55efSEd Tanous } 16091abe55efSEd Tanous else 16101abe55efSEd Tanous { 1611e439f0f8SKowalski, Kamil // ... otherwise return error 16121abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 16131abe55efSEd Tanous // object, and other errors 1614f12894f8SJason M. Bills messages::resourceNotFound( 1615f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1616e439f0f8SKowalski, Kamil } 1617e439f0f8SKowalski, Kamil }); 1618e439f0f8SKowalski, Kamil } 1619e439f0f8SKowalski, Kamil 162055c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 16211abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16221abe55efSEd Tanous { 16234a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16241abe55efSEd Tanous if (params.size() != 2) 16251abe55efSEd Tanous { 1626f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1627e439f0f8SKowalski, Kamil return; 1628e439f0f8SKowalski, Kamil } 1629e439f0f8SKowalski, Kamil 1630d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 163155c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1632927a505aSKowalski, Kamil 1633fda13ad2SSunitha Harish if (!verifyNames(parentIfaceId, ifaceId)) 16341abe55efSEd Tanous { 1635fda13ad2SSunitha Harish messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1636fda13ad2SSunitha Harish ifaceId); 1637927a505aSKowalski, Kamil return; 1638927a505aSKowalski, Kamil } 1639927a505aSKowalski, Kamil 16400627a2c7SEd Tanous bool vlanEnable = false; 16410627a2c7SEd Tanous uint64_t vlanId = 0; 16420627a2c7SEd Tanous 16430627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId", 16440627a2c7SEd Tanous vlanId)) 16451abe55efSEd Tanous { 1646927a505aSKowalski, Kamil return; 1647927a505aSKowalski, Kamil } 1648927a505aSKowalski, Kamil 1649927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1650927a505aSKowalski, Kamil // preparation 165108244d02SSunitha Harish getEthernetIfaceData(params[1], [this, asyncResp, 165208244d02SSunitha Harish parentIfaceId{std::string(params[0])}, 165308244d02SSunitha Harish ifaceId{std::string(params[1])}, 165408244d02SSunitha Harish &vlanEnable, &vlanId]( 165508244d02SSunitha Harish const bool &success, 165608244d02SSunitha Harish const EthernetInterfaceData 165708244d02SSunitha Harish ðData, 165808244d02SSunitha Harish const boost::container::flat_set< 165908244d02SSunitha Harish IPv4AddressData> &ipv4Data) { 166008244d02SSunitha Harish if (success && !ethData.vlan_id.empty()) 166108244d02SSunitha Harish { 166208244d02SSunitha Harish parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 166308244d02SSunitha Harish ifaceId, ethData, ipv4Data); 166408244d02SSunitha Harish auto callback = 166508244d02SSunitha Harish [asyncResp](const boost::system::error_code ec) { 166608244d02SSunitha Harish if (ec) 166708244d02SSunitha Harish { 166808244d02SSunitha Harish messages::internalError(asyncResp->res); 166908244d02SSunitha Harish } 167008244d02SSunitha Harish }; 167108244d02SSunitha Harish 167208244d02SSunitha Harish if (vlanEnable == true) 167308244d02SSunitha Harish { 167408244d02SSunitha Harish crow::connections::systemBus->async_method_call( 167508244d02SSunitha Harish std::move(callback), "xyz.openbmc_project.Network", 167608244d02SSunitha Harish "/xyz/openbmc_project/network/" + ifaceId, 167708244d02SSunitha Harish "org.freedesktop.DBus.Properties", "Set", 167808244d02SSunitha Harish "xyz.openbmc_project.Network.VLAN", "Id", 167908244d02SSunitha Harish std::variant<uint32_t>(vlanId)); 168008244d02SSunitha Harish } 168108244d02SSunitha Harish else 168208244d02SSunitha Harish { 168308244d02SSunitha Harish BMCWEB_LOG_DEBUG 168408244d02SSunitha Harish << "vlanEnable is false. Deleting the vlan interface"; 168508244d02SSunitha Harish crow::connections::systemBus->async_method_call( 168608244d02SSunitha Harish std::move(callback), "xyz.openbmc_project.Network", 168708244d02SSunitha Harish std::string("/xyz/openbmc_project/network/") + ifaceId, 168808244d02SSunitha Harish "xyz.openbmc_project.Object.Delete", "Delete"); 168908244d02SSunitha Harish } 169008244d02SSunitha Harish } 169108244d02SSunitha Harish else 16921abe55efSEd Tanous { 16931abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 16941abe55efSEd Tanous // object, and other errors 169508244d02SSunitha Harish messages::resourceNotFound(asyncResp->res, 169608244d02SSunitha Harish "VLAN Network Interface", ifaceId); 1697927a505aSKowalski, Kamil return; 1698927a505aSKowalski, Kamil } 1699927a505aSKowalski, Kamil }); 1700e439f0f8SKowalski, Kamil } 1701e439f0f8SKowalski, Kamil 170255c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 17031abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17041abe55efSEd Tanous { 17054a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17061abe55efSEd Tanous if (params.size() != 2) 17071abe55efSEd Tanous { 1708f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1709e439f0f8SKowalski, Kamil return; 1710e439f0f8SKowalski, Kamil } 1711e439f0f8SKowalski, Kamil 1712d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 171355c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1714927a505aSKowalski, Kamil 1715fda13ad2SSunitha Harish if (!verifyNames(parentIfaceId, ifaceId)) 17161abe55efSEd Tanous { 1717fda13ad2SSunitha Harish messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1718fda13ad2SSunitha Harish ifaceId); 1719927a505aSKowalski, Kamil return; 1720927a505aSKowalski, Kamil } 1721927a505aSKowalski, Kamil 1722927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1723927a505aSKowalski, Kamil // preparation 1724f12894f8SJason M. Bills getEthernetIfaceData( 1725fda13ad2SSunitha Harish params[1], 1726fda13ad2SSunitha Harish [this, asyncResp, parentIfaceId{std::string(params[0])}, 1727fda13ad2SSunitha Harish ifaceId{std::string(params[1])}]( 1728f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1729f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 1730fda13ad2SSunitha Harish if (success && !ethData.vlan_id.empty()) 17311abe55efSEd Tanous { 17320f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 17330f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1734927a505aSKowalski, Kamil 1735f12894f8SJason M. Bills auto callback = 1736f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 17371abe55efSEd Tanous if (ec) 17381abe55efSEd Tanous { 1739f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1740927a505aSKowalski, Kamil } 17414a0cb85cSEd Tanous }; 17424a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 17434a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 17444a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 17454a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 17461abe55efSEd Tanous } 17471abe55efSEd Tanous else 17481abe55efSEd Tanous { 1749927a505aSKowalski, Kamil // ... otherwise return error 1750f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1751f12894f8SJason M. Bills // object, and other errors 1752f12894f8SJason M. Bills messages::resourceNotFound( 1753f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1754927a505aSKowalski, Kamil } 1755927a505aSKowalski, Kamil }); 1756e439f0f8SKowalski, Kamil } 1757e439f0f8SKowalski, Kamil }; 1758e439f0f8SKowalski, Kamil 1759e439f0f8SKowalski, Kamil /** 1760e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1761e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1762e439f0f8SKowalski, Kamil */ 17631abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 17641abe55efSEd Tanous { 1765e439f0f8SKowalski, Kamil public: 1766e439f0f8SKowalski, Kamil template <typename CrowApp> 17671abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 17684a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 17694a0cb85cSEd Tanous std::string()) 17701abe55efSEd Tanous { 1771e439f0f8SKowalski, Kamil entityPrivileges = { 1772e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1773e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1774e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1775e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1776e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1777e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1778e439f0f8SKowalski, Kamil } 1779e439f0f8SKowalski, Kamil 1780e439f0f8SKowalski, Kamil private: 1781e439f0f8SKowalski, Kamil /** 1782e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1783e439f0f8SKowalski, Kamil */ 178455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 17851abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17861abe55efSEd Tanous { 17874a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17881abe55efSEd Tanous if (params.size() != 1) 17891abe55efSEd Tanous { 1790e439f0f8SKowalski, Kamil // This means there is a problem with the router 1791f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1792e439f0f8SKowalski, Kamil return; 1793e439f0f8SKowalski, Kamil } 1794e439f0f8SKowalski, Kamil 17954a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1796e439f0f8SKowalski, Kamil 17974a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 17981abe55efSEd Tanous // preparation 1799f12894f8SJason M. Bills getEthernetIfaceList( 180043b761d0SEd Tanous [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}]( 18011abe55efSEd Tanous const bool &success, 18024c9afe43SEd Tanous const boost::container::flat_set<std::string> &iface_list) { 18034a0cb85cSEd Tanous if (!success) 18041abe55efSEd Tanous { 1805f12894f8SJason M. Bills messages::internalError(asyncResp->res); 18064a0cb85cSEd Tanous return; 18071abe55efSEd Tanous } 18084c9afe43SEd Tanous 18094c9afe43SEd Tanous if (iface_list.find(rootInterfaceName) == iface_list.end()) 18104c9afe43SEd Tanous { 18114c9afe43SEd Tanous messages::resourceNotFound(asyncResp->res, 18124c9afe43SEd Tanous "VLanNetworkInterfaceCollection", 18134c9afe43SEd Tanous rootInterfaceName); 18144c9afe43SEd Tanous return; 18154c9afe43SEd Tanous } 18164c9afe43SEd Tanous 18170f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 18180f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 18190f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 18200f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 18210f74e643SEd Tanous "/redfish/v1/$metadata" 18220f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 18230f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 18240f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = 18250f74e643SEd Tanous "VLAN Network Interface Collection"; 18264a0cb85cSEd Tanous 18274a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 18284a0cb85cSEd Tanous 18294a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 18301abe55efSEd Tanous { 18314a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 18324a0cb85cSEd Tanous { 18334a0cb85cSEd Tanous iface_array.push_back( 18344a0cb85cSEd Tanous {{"@odata.id", 18354a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 18364a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1837e439f0f8SKowalski, Kamil } 1838e439f0f8SKowalski, Kamil } 1839e439f0f8SKowalski, Kamil 18404a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 18414a0cb85cSEd Tanous iface_array.size(); 18424a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 18434a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 18444a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 18454a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1846e439f0f8SKowalski, Kamil }); 1847e439f0f8SKowalski, Kamil } 1848e439f0f8SKowalski, Kamil 184955c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 18501abe55efSEd Tanous const std::vector<std::string> ¶ms) override 18511abe55efSEd Tanous { 18524a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 18531abe55efSEd Tanous if (params.size() != 1) 18541abe55efSEd Tanous { 1855f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1856e439f0f8SKowalski, Kamil return; 1857e439f0f8SKowalski, Kamil } 1858fda13ad2SSunitha Harish bool vlanEnable = false; 18590627a2c7SEd Tanous uint32_t vlanId = 0; 1860fda13ad2SSunitha Harish if (!json_util::readJson(req, res, "VLANId", vlanId, "VLANEnable", 1861fda13ad2SSunitha Harish vlanEnable)) 18621abe55efSEd Tanous { 18634a0cb85cSEd Tanous return; 1864e439f0f8SKowalski, Kamil } 1865fda13ad2SSunitha Harish // Need both vlanId and vlanEnable to service this request 1866fda13ad2SSunitha Harish if (!vlanId) 1867fda13ad2SSunitha Harish { 1868fda13ad2SSunitha Harish messages::propertyMissing(asyncResp->res, "VLANId"); 1869fda13ad2SSunitha Harish } 1870fda13ad2SSunitha Harish if (!vlanEnable) 1871fda13ad2SSunitha Harish { 1872fda13ad2SSunitha Harish messages::propertyMissing(asyncResp->res, "VLANEnable"); 1873fda13ad2SSunitha Harish } 1874fda13ad2SSunitha Harish if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable)) 1875fda13ad2SSunitha Harish { 1876fda13ad2SSunitha Harish return; 1877fda13ad2SSunitha Harish } 1878fda13ad2SSunitha Harish 18794a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 18804a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 18811abe55efSEd Tanous if (ec) 18821abe55efSEd Tanous { 18834a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 18844a0cb85cSEd Tanous // phosphor-network responses 1885f12894f8SJason M. Bills messages::internalError(asyncResp->res); 18864a0cb85cSEd Tanous return; 18871abe55efSEd Tanous } 1888f12894f8SJason M. Bills messages::created(asyncResp->res); 1889e439f0f8SKowalski, Kamil }; 18904a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 18914a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 18924a0cb85cSEd Tanous "/xyz/openbmc_project/network", 18934a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 18940627a2c7SEd Tanous rootInterfaceName, vlanId); 18954a0cb85cSEd Tanous } 18964a0cb85cSEd Tanous }; 18979391bb9cSRapkiewicz, Pawel } // namespace redfish 1898