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; 844a0cb85cSEd Tanous std::string mac_address; 85a24526dcSEd Tanous std::optional<uint32_t> vlan_id; 86029573d4SEd Tanous std::vector<std::string> nameservers; 879391bb9cSRapkiewicz, Pawel }; 889391bb9cSRapkiewicz, Pawel 899391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 909391bb9cSRapkiewicz, Pawel // into full dot notation 911abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 921abe55efSEd Tanous { 939391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 949391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 959391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 969391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 979391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 989391bb9cSRapkiewicz, Pawel return netmask; 999391bb9cSRapkiewicz, Pawel } 1009391bb9cSRapkiewicz, Pawel 1014a0cb85cSEd Tanous inline std::string 1024a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(const std::string &inputOrigin, 1034a0cb85cSEd Tanous bool isIPv4) 1041abe55efSEd Tanous { 1054a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 1061abe55efSEd Tanous { 1074a0cb85cSEd Tanous return "Static"; 1089391bb9cSRapkiewicz, Pawel } 1094a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal") 1101abe55efSEd Tanous { 1114a0cb85cSEd Tanous if (isIPv4) 1121abe55efSEd Tanous { 1134a0cb85cSEd Tanous return "IPv4LinkLocal"; 1141abe55efSEd Tanous } 1151abe55efSEd Tanous else 1161abe55efSEd Tanous { 1174a0cb85cSEd Tanous return "LinkLocal"; 1189391bb9cSRapkiewicz, Pawel } 1199391bb9cSRapkiewicz, Pawel } 1204a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1211abe55efSEd Tanous { 1224a0cb85cSEd Tanous if (isIPv4) 1234a0cb85cSEd Tanous { 1244a0cb85cSEd Tanous return "DHCP"; 1254a0cb85cSEd Tanous } 1264a0cb85cSEd Tanous else 1274a0cb85cSEd Tanous { 1284a0cb85cSEd Tanous return "DHCPv6"; 1294a0cb85cSEd Tanous } 1304a0cb85cSEd Tanous } 1314a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC") 1324a0cb85cSEd Tanous { 1334a0cb85cSEd Tanous return "SLAAC"; 1344a0cb85cSEd Tanous } 1354a0cb85cSEd Tanous return ""; 1364a0cb85cSEd Tanous } 1374a0cb85cSEd Tanous 1384a0cb85cSEd Tanous inline std::string 1394a0cb85cSEd Tanous translateAddressOriginRedfishToDbus(const std::string &inputOrigin) 1404a0cb85cSEd Tanous { 1414a0cb85cSEd Tanous if (inputOrigin == "Static") 1424a0cb85cSEd Tanous { 1434a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 1444a0cb85cSEd Tanous } 1454a0cb85cSEd Tanous if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6") 1464a0cb85cSEd Tanous { 1474a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 1484a0cb85cSEd Tanous } 1494a0cb85cSEd Tanous if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal") 1504a0cb85cSEd Tanous { 1514a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal"; 1524a0cb85cSEd Tanous } 1534a0cb85cSEd Tanous if (inputOrigin == "SLAAC") 1544a0cb85cSEd Tanous { 1554a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC"; 1564a0cb85cSEd Tanous } 1574a0cb85cSEd Tanous return ""; 1584a0cb85cSEd Tanous } 1594a0cb85cSEd Tanous 1604a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string ðiface_id, 1614a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 1624a0cb85cSEd Tanous EthernetInterfaceData ðData) 1634a0cb85cSEd Tanous { 1644a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 1654a0cb85cSEd Tanous { 1664a0cb85cSEd Tanous for (const auto &ifacePair : objpath.second) 1674a0cb85cSEd Tanous { 168029573d4SEd Tanous if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id) 169029573d4SEd Tanous { 1704a0cb85cSEd Tanous if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 1714a0cb85cSEd Tanous { 1724a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1734a0cb85cSEd Tanous { 1744a0cb85cSEd Tanous if (propertyPair.first == "MACAddress") 1754a0cb85cSEd Tanous { 1764a0cb85cSEd Tanous const std::string *mac = 177abf2add6SEd Tanous std::get_if<std::string>(&propertyPair.second); 1784a0cb85cSEd Tanous if (mac != nullptr) 1794a0cb85cSEd Tanous { 1804a0cb85cSEd Tanous ethData.mac_address = *mac; 1814a0cb85cSEd Tanous } 1824a0cb85cSEd Tanous } 1834a0cb85cSEd Tanous } 1844a0cb85cSEd Tanous } 1854a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 1864a0cb85cSEd Tanous { 1874a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 1884a0cb85cSEd Tanous { 1894a0cb85cSEd Tanous if (propertyPair.first == "Id") 1904a0cb85cSEd Tanous { 1911b6b96c5SEd Tanous const uint32_t *id = 192abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 1934a0cb85cSEd Tanous if (id != nullptr) 1944a0cb85cSEd Tanous { 1954a0cb85cSEd Tanous ethData.vlan_id = *id; 1964a0cb85cSEd Tanous } 1974a0cb85cSEd Tanous } 1984a0cb85cSEd Tanous } 1994a0cb85cSEd Tanous } 2004a0cb85cSEd Tanous else if (ifacePair.first == 2014a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 2024a0cb85cSEd Tanous { 2034a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2044a0cb85cSEd Tanous { 2054a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 2064a0cb85cSEd Tanous { 2074a0cb85cSEd Tanous const bool *auto_neg = 208abf2add6SEd Tanous std::get_if<bool>(&propertyPair.second); 2094a0cb85cSEd Tanous if (auto_neg != nullptr) 2104a0cb85cSEd Tanous { 2114a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 2124a0cb85cSEd Tanous } 2134a0cb85cSEd Tanous } 2144a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 2154a0cb85cSEd Tanous { 2164a0cb85cSEd Tanous const uint32_t *speed = 217abf2add6SEd Tanous std::get_if<uint32_t>(&propertyPair.second); 2184a0cb85cSEd Tanous if (speed != nullptr) 2194a0cb85cSEd Tanous { 2204a0cb85cSEd Tanous ethData.speed = *speed; 2214a0cb85cSEd Tanous } 2224a0cb85cSEd Tanous } 223029573d4SEd Tanous else if (propertyPair.first == "NameServers") 224029573d4SEd Tanous { 225029573d4SEd Tanous const std::vector<std::string> *nameservers = 226029573d4SEd Tanous sdbusplus::message::variant_ns::get_if< 227029573d4SEd Tanous std::vector<std::string>>( 228029573d4SEd Tanous &propertyPair.second); 229029573d4SEd Tanous if (nameservers != nullptr) 230029573d4SEd Tanous { 231029573d4SEd Tanous ethData.nameservers = std::move(*nameservers); 2324a0cb85cSEd Tanous } 2334a0cb85cSEd Tanous } 2342a133282Smanojkiraneda else if (propertyPair.first == "DHCPEnabled") 2352a133282Smanojkiraneda { 2362a133282Smanojkiraneda const bool *DHCPEnabled = 2372a133282Smanojkiraneda std::get_if<bool>(&propertyPair.second); 2382a133282Smanojkiraneda if (DHCPEnabled != nullptr) 2392a133282Smanojkiraneda { 2402a133282Smanojkiraneda ethData.DHCPEnabled = *DHCPEnabled; 2412a133282Smanojkiraneda } 2422a133282Smanojkiraneda } 243029573d4SEd Tanous } 244029573d4SEd Tanous } 245029573d4SEd Tanous } 246029573d4SEd Tanous // System configuration shows up in the global namespace, so no need 247029573d4SEd Tanous // to check eth number 248029573d4SEd Tanous if (ifacePair.first == 2494a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 2504a0cb85cSEd Tanous { 2514a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 2524a0cb85cSEd Tanous { 2534a0cb85cSEd Tanous if (propertyPair.first == "HostName") 2544a0cb85cSEd Tanous { 2554a0cb85cSEd Tanous const std::string *hostname = 256029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 257029573d4SEd Tanous &propertyPair.second); 2584a0cb85cSEd Tanous if (hostname != nullptr) 2594a0cb85cSEd Tanous { 2604a0cb85cSEd Tanous ethData.hostname = *hostname; 2614a0cb85cSEd Tanous } 2624a0cb85cSEd Tanous } 2634a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 2644a0cb85cSEd Tanous { 2654a0cb85cSEd Tanous const std::string *defaultGateway = 266029573d4SEd Tanous sdbusplus::message::variant_ns::get_if<std::string>( 267029573d4SEd Tanous &propertyPair.second); 2684a0cb85cSEd Tanous if (defaultGateway != nullptr) 2694a0cb85cSEd Tanous { 2704a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 2714a0cb85cSEd Tanous } 2724a0cb85cSEd Tanous } 2734a0cb85cSEd Tanous } 2744a0cb85cSEd Tanous } 2754a0cb85cSEd Tanous } 2764a0cb85cSEd Tanous } 2774a0cb85cSEd Tanous } 2784a0cb85cSEd Tanous 2794a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 2804a0cb85cSEd Tanous inline void 2814a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 2824a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 2834a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 2844a0cb85cSEd Tanous { 2854a0cb85cSEd Tanous const std::string ipv4PathStart = 2864a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 2874a0cb85cSEd Tanous 2884a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 2894a0cb85cSEd Tanous // single ethernet interface, loop over all of them 2904a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 2914a0cb85cSEd Tanous { 2924a0cb85cSEd Tanous // Check if proper pattern for object path appears 2934a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 2944a0cb85cSEd Tanous { 2954a0cb85cSEd Tanous for (auto &interface : objpath.second) 2964a0cb85cSEd Tanous { 2974a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 2984a0cb85cSEd Tanous { 2994a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 3004a0cb85cSEd Tanous // appropriate 3014a0cb85cSEd Tanous std::pair< 3024a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 3034a0cb85cSEd Tanous bool> 3044a0cb85cSEd Tanous it = ipv4_config.insert( 3054a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 3064a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 3074a0cb85cSEd Tanous for (auto &property : interface.second) 3084a0cb85cSEd Tanous { 3094a0cb85cSEd Tanous if (property.first == "Address") 3104a0cb85cSEd Tanous { 3114a0cb85cSEd Tanous const std::string *address = 312abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3134a0cb85cSEd Tanous if (address != nullptr) 3144a0cb85cSEd Tanous { 3154a0cb85cSEd Tanous ipv4_address.address = *address; 3164a0cb85cSEd Tanous } 3174a0cb85cSEd Tanous } 3184a0cb85cSEd Tanous else if (property.first == "Gateway") 3194a0cb85cSEd Tanous { 3204a0cb85cSEd Tanous const std::string *gateway = 321abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3224a0cb85cSEd Tanous if (gateway != nullptr) 3234a0cb85cSEd Tanous { 3244a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 3254a0cb85cSEd Tanous } 3264a0cb85cSEd Tanous } 3274a0cb85cSEd Tanous else if (property.first == "Origin") 3284a0cb85cSEd Tanous { 3294a0cb85cSEd Tanous const std::string *origin = 330abf2add6SEd Tanous std::get_if<std::string>(&property.second); 3314a0cb85cSEd Tanous if (origin != nullptr) 3324a0cb85cSEd Tanous { 3334a0cb85cSEd Tanous ipv4_address.origin = 3344a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 3354a0cb85cSEd Tanous true); 3364a0cb85cSEd Tanous } 3374a0cb85cSEd Tanous } 3384a0cb85cSEd Tanous else if (property.first == "PrefixLength") 3394a0cb85cSEd Tanous { 3404a0cb85cSEd Tanous const uint8_t *mask = 341abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 3424a0cb85cSEd Tanous if (mask != nullptr) 3434a0cb85cSEd Tanous { 3444a0cb85cSEd Tanous // convert it to the string 3454a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 3464a0cb85cSEd Tanous } 3474a0cb85cSEd Tanous } 3484a0cb85cSEd Tanous else 3494a0cb85cSEd Tanous { 3504a0cb85cSEd Tanous BMCWEB_LOG_ERROR 3514a0cb85cSEd Tanous << "Got extra property: " << property.first 3524a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 3534a0cb85cSEd Tanous } 3544a0cb85cSEd Tanous } 3554a0cb85cSEd Tanous // Check if given address is local, or global 3564a0cb85cSEd Tanous ipv4_address.linktype = 3574a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 3584a0cb85cSEd Tanous ? LinkType::Global 3594a0cb85cSEd Tanous : LinkType::Local; 3604a0cb85cSEd Tanous } 3614a0cb85cSEd Tanous } 3624a0cb85cSEd Tanous } 3634a0cb85cSEd Tanous } 3644a0cb85cSEd Tanous } 365588c3f0dSKowalski, Kamil 366588c3f0dSKowalski, Kamil /** 367588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 368588c3f0dSKowalski, Kamil * 369588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 370588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 371588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 372588c3f0dSKowalski, Kamil * 373588c3f0dSKowalski, Kamil * @return None. 374588c3f0dSKowalski, Kamil */ 375588c3f0dSKowalski, Kamil template <typename CallbackFunc> 3764a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3771abe55efSEd Tanous CallbackFunc &&callback) 3781abe55efSEd Tanous { 37955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 380588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 381588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 382588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 383588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 384abf2add6SEd Tanous std::variant<uint32_t>(inputVlanId)); 3854a0cb85cSEd Tanous } 386588c3f0dSKowalski, Kamil 387588c3f0dSKowalski, Kamil /** 388179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 389179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 390179db1d7SKowalski, Kamil * bit count for Subnet Mask. 391179db1d7SKowalski, Kamil * 392179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 393179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 394179db1d7SKowalski, Kamil * 395179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 396179db1d7SKowalski, Kamil */ 3974a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3981abe55efSEd Tanous uint8_t *bits = nullptr) 3991abe55efSEd Tanous { 400179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 401179db1d7SKowalski, Kamil 402179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 403179db1d7SKowalski, Kamil 4044a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 4051abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 4061abe55efSEd Tanous { 407179db1d7SKowalski, Kamil return false; 408179db1d7SKowalski, Kamil } 409179db1d7SKowalski, Kamil 4101abe55efSEd Tanous if (bits != nullptr) 4111abe55efSEd Tanous { 412179db1d7SKowalski, Kamil *bits = 0; 413179db1d7SKowalski, Kamil } 414179db1d7SKowalski, Kamil 415179db1d7SKowalski, Kamil char *endPtr; 416179db1d7SKowalski, Kamil long previousValue = 255; 417179db1d7SKowalski, Kamil bool firstZeroInByteHit; 4181abe55efSEd Tanous for (const std::string &byte : bytesInMask) 4191abe55efSEd Tanous { 4201abe55efSEd Tanous if (byte.empty()) 4211abe55efSEd Tanous { 4221db9ca37SKowalski, Kamil return false; 4231db9ca37SKowalski, Kamil } 4241db9ca37SKowalski, Kamil 425179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4261db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 427179db1d7SKowalski, Kamil 4284a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 4294a0cb85cSEd Tanous // is not 100% number 4301abe55efSEd Tanous if (*endPtr != '\0') 4311abe55efSEd Tanous { 432179db1d7SKowalski, Kamil return false; 433179db1d7SKowalski, Kamil } 434179db1d7SKowalski, Kamil 435179db1d7SKowalski, Kamil // Value should be contained in byte 4361abe55efSEd Tanous if (value < 0 || value > 255) 4371abe55efSEd Tanous { 438179db1d7SKowalski, Kamil return false; 439179db1d7SKowalski, Kamil } 440179db1d7SKowalski, Kamil 4411abe55efSEd Tanous if (bits != nullptr) 4421abe55efSEd Tanous { 443179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4441abe55efSEd Tanous if (previousValue != 255 && value != 0) 4451abe55efSEd Tanous { 446179db1d7SKowalski, Kamil return false; 447179db1d7SKowalski, Kamil } 448179db1d7SKowalski, Kamil 449179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 450179db1d7SKowalski, Kamil firstZeroInByteHit = false; 451179db1d7SKowalski, Kamil 452179db1d7SKowalski, Kamil // Count bits 4531abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4541abe55efSEd Tanous { 4551abe55efSEd Tanous if (value & (1 << bitIdx)) 4561abe55efSEd Tanous { 4571abe55efSEd Tanous if (firstZeroInByteHit) 4581abe55efSEd Tanous { 459179db1d7SKowalski, Kamil // Continuity not preserved 460179db1d7SKowalski, Kamil return false; 4611abe55efSEd Tanous } 4621abe55efSEd Tanous else 4631abe55efSEd Tanous { 464179db1d7SKowalski, Kamil (*bits)++; 465179db1d7SKowalski, Kamil } 4661abe55efSEd Tanous } 4671abe55efSEd Tanous else 4681abe55efSEd Tanous { 469179db1d7SKowalski, Kamil firstZeroInByteHit = true; 470179db1d7SKowalski, Kamil } 471179db1d7SKowalski, Kamil } 472179db1d7SKowalski, Kamil } 473179db1d7SKowalski, Kamil 474179db1d7SKowalski, Kamil previousValue = value; 475179db1d7SKowalski, Kamil } 476179db1d7SKowalski, Kamil 477179db1d7SKowalski, Kamil return true; 478179db1d7SKowalski, Kamil } 479179db1d7SKowalski, Kamil 480179db1d7SKowalski, Kamil /** 481179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 482179db1d7SKowalski, Kamil * 483179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 4844a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 485179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 486179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 487179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 488179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 489179db1d7SKowalski, Kamil * 490179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 491179db1d7SKowalski, Kamil * otherwise 492179db1d7SKowalski, Kamil */ 4934a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 4944a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 4954a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 4964a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4971abe55efSEd Tanous { 4984a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 4994a0cb85cSEd Tanous newValue{std::move(newValue)}]( 5001abe55efSEd Tanous const boost::system::error_code ec) { 5011abe55efSEd Tanous if (ec) 5021abe55efSEd Tanous { 503a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5041abe55efSEd Tanous } 5051abe55efSEd Tanous else 5061abe55efSEd Tanous { 5074a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 508179db1d7SKowalski, Kamil } 509179db1d7SKowalski, Kamil }; 510179db1d7SKowalski, Kamil 51155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 512179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 513179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 514179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 515179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 516abf2add6SEd Tanous std::variant<std::string>(newValue)); 5174a0cb85cSEd Tanous } 518179db1d7SKowalski, Kamil 519179db1d7SKowalski, Kamil /** 520179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 521179db1d7SKowalski, Kamil * 522179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5234a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5241abe55efSEd Tanous * modified 525179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 526179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 527179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 528179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 529179db1d7SKowalski, Kamil * 530179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 531179db1d7SKowalski, Kamil * otherwise 532179db1d7SKowalski, Kamil */ 5334a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5341abe55efSEd Tanous const std::string &ipHash, 5351abe55efSEd Tanous const std::string &newValue, 536179db1d7SKowalski, Kamil const std::string &newValueDbus, 5374a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5381abe55efSEd Tanous { 5394a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5401abe55efSEd Tanous const boost::system::error_code ec) { 5411abe55efSEd Tanous if (ec) 5421abe55efSEd Tanous { 543a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5441abe55efSEd Tanous } 5451abe55efSEd Tanous else 5461abe55efSEd Tanous { 5474a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 548179db1d7SKowalski, Kamil newValue; 549179db1d7SKowalski, Kamil } 550179db1d7SKowalski, Kamil }; 551179db1d7SKowalski, Kamil 55255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 553179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 554179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 555179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 556179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 557abf2add6SEd Tanous std::variant<std::string>(newValueDbus)); 5584a0cb85cSEd Tanous } 559179db1d7SKowalski, Kamil 560179db1d7SKowalski, Kamil /** 561179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 562179db1d7SKowalski, Kamil * 563179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 5644a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5651abe55efSEd Tanous * modified 566179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 567179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 568179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 569179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 570179db1d7SKowalski, Kamil * 571179db1d7SKowalski, Kamil * @return None 572179db1d7SKowalski, Kamil */ 5734a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 5744a0cb85cSEd Tanous const std::string &ipHash, 5754a0cb85cSEd Tanous const std::string &newValueStr, 5764a0cb85cSEd Tanous uint8_t &newValue, 5774a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5781abe55efSEd Tanous { 5794a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5801abe55efSEd Tanous const boost::system::error_code ec) { 5811abe55efSEd Tanous if (ec) 5821abe55efSEd Tanous { 583a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5841abe55efSEd Tanous } 5851abe55efSEd Tanous else 5861abe55efSEd Tanous { 58755c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 588179db1d7SKowalski, Kamil newValueStr; 589179db1d7SKowalski, Kamil } 590179db1d7SKowalski, Kamil }; 591179db1d7SKowalski, Kamil 59255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 593179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 594179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 595179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 596179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 597abf2add6SEd Tanous std::variant<uint8_t>(newValue)); 5984a0cb85cSEd Tanous } 599588c3f0dSKowalski, Kamil 600588c3f0dSKowalski, Kamil /** 601179db1d7SKowalski, Kamil * @brief Deletes given IPv4 602179db1d7SKowalski, Kamil * 603179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6044a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 605179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 606179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 607179db1d7SKowalski, Kamil * 608179db1d7SKowalski, Kamil * @return None 609179db1d7SKowalski, Kamil */ 6104a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 611179db1d7SKowalski, Kamil unsigned int ipIdx, 6124a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6131abe55efSEd Tanous { 61455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6154a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6161abe55efSEd Tanous if (ec) 6171abe55efSEd Tanous { 618a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 6191abe55efSEd Tanous } 6201abe55efSEd Tanous else 6211abe55efSEd Tanous { 62255c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 623179db1d7SKowalski, Kamil } 624179db1d7SKowalski, Kamil }, 625179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 626179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 627179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 628179db1d7SKowalski, Kamil } 629179db1d7SKowalski, Kamil 630179db1d7SKowalski, Kamil /** 631179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 632179db1d7SKowalski, Kamil * 633179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 6344a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 635179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 636179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 637179db1d7SKowalski, Kamil * 638179db1d7SKowalski, Kamil * @return None 639179db1d7SKowalski, Kamil */ 6404a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 641179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 642179db1d7SKowalski, Kamil const std::string &address, 6434a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6441abe55efSEd Tanous { 64543b761d0SEd Tanous auto createIpHandler = [asyncResp](const boost::system::error_code ec) { 6461abe55efSEd Tanous if (ec) 6471abe55efSEd Tanous { 648a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 649179db1d7SKowalski, Kamil } 650179db1d7SKowalski, Kamil }; 651179db1d7SKowalski, Kamil 65255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 653179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 654179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 655179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 656179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 657179db1d7SKowalski, Kamil gateway); 658179db1d7SKowalski, Kamil } 6592a133282Smanojkiraneda using GetAllPropertiesType = 6602a133282Smanojkiraneda boost::container::flat_map<std::string, sdbusplus::message::variant<bool>>; 6612a133282Smanojkiraneda 6622a133282Smanojkiraneda inline void getDHCPConfigData(const std::shared_ptr<AsyncResp> asyncResp) 6632a133282Smanojkiraneda { 6642a133282Smanojkiraneda auto getConfig = [asyncResp](const boost::system::error_code error_code, 6652a133282Smanojkiraneda const GetAllPropertiesType &dbus_data) { 6662a133282Smanojkiraneda if (error_code) 6672a133282Smanojkiraneda { 6682a133282Smanojkiraneda BMCWEB_LOG_ERROR << "D-Bus response error: " << error_code; 6692a133282Smanojkiraneda messages::internalError(asyncResp->res); 6702a133282Smanojkiraneda return; 6712a133282Smanojkiraneda } 6722a133282Smanojkiraneda nlohmann::json &DHCPConfigTypeJson = 6732a133282Smanojkiraneda asyncResp->res.jsonValue["DHCPv4Configuration"]; 6742a133282Smanojkiraneda for (const auto &property : dbus_data) 6752a133282Smanojkiraneda { 6762a133282Smanojkiraneda auto value = 6772a133282Smanojkiraneda sdbusplus::message::variant_ns::get_if<bool>(&property.second); 6782a133282Smanojkiraneda 6792a133282Smanojkiraneda if (value == nullptr) 6802a133282Smanojkiraneda { 6812a133282Smanojkiraneda continue; 6822a133282Smanojkiraneda } 6832a133282Smanojkiraneda if (property.first == "DNSEnabled") 6842a133282Smanojkiraneda { 6852a133282Smanojkiraneda DHCPConfigTypeJson["UseDNSServers"] = *value; 6862a133282Smanojkiraneda } 6872a133282Smanojkiraneda else if (property.first == "HostNameEnabled") 6882a133282Smanojkiraneda { 6892a133282Smanojkiraneda DHCPConfigTypeJson["UseDomainName"] = *value; 6902a133282Smanojkiraneda } 6912a133282Smanojkiraneda else if (property.first == "NTPEnabled") 6922a133282Smanojkiraneda { 6932a133282Smanojkiraneda DHCPConfigTypeJson["UseNTPServers"] = *value; 6942a133282Smanojkiraneda } 6952a133282Smanojkiraneda } 6962a133282Smanojkiraneda }; 6972a133282Smanojkiraneda crow::connections::systemBus->async_method_call( 6982a133282Smanojkiraneda std::move(getConfig), "xyz.openbmc_project.Network", 6992a133282Smanojkiraneda "/xyz/openbmc_project/network/config/dhcp", 7002a133282Smanojkiraneda "org.freedesktop.DBus.Properties", "GetAll", 7012a133282Smanojkiraneda "xyz.openbmc_project.Network.DHCPConfiguration"); 7022a133282Smanojkiraneda } 703179db1d7SKowalski, Kamil 704179db1d7SKowalski, Kamil /** 705179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 706179db1d7SKowalski, Kamil * Object 707179db1d7SKowalski, Kamil * from EntityManager Network Manager 7084a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 709179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 710179db1d7SKowalski, Kamil * into JSON 711179db1d7SKowalski, Kamil */ 712179db1d7SKowalski, Kamil template <typename CallbackFunc> 7134a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 7141abe55efSEd Tanous CallbackFunc &&callback) 7151abe55efSEd Tanous { 71655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7174a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 7181abe55efSEd Tanous const boost::system::error_code error_code, 7194a0cb85cSEd Tanous const GetManagedObjects &resp) { 72055c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 7214a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 722179db1d7SKowalski, Kamil 7231abe55efSEd Tanous if (error_code) 7241abe55efSEd Tanous { 72555c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 726179db1d7SKowalski, Kamil return; 727179db1d7SKowalski, Kamil } 728179db1d7SKowalski, Kamil 7294a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 7304a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 731179db1d7SKowalski, Kamil 732179db1d7SKowalski, Kamil // Fix global GW 7331abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 7341abe55efSEd Tanous { 7354a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 7364a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 7371abe55efSEd Tanous { 7384a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 739179db1d7SKowalski, Kamil } 740179db1d7SKowalski, Kamil } 741179db1d7SKowalski, Kamil 7424a0cb85cSEd Tanous // Finally make a callback with usefull data 74355c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 744179db1d7SKowalski, Kamil }, 745179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 746179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 747179db1d7SKowalski, Kamil }; 748179db1d7SKowalski, Kamil 749179db1d7SKowalski, Kamil /** 7509391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7519391bb9cSRapkiewicz, Pawel * Manager 7521abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7531abe55efSEd Tanous * into JSON. 7549391bb9cSRapkiewicz, Pawel */ 7559391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7561abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7571abe55efSEd Tanous { 75855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7594a0cb85cSEd Tanous [callback{std::move(callback)}]( 7609391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 7614a0cb85cSEd Tanous GetManagedObjects &resp) { 7621abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7631abe55efSEd Tanous // ethernet interfaces 7644a0cb85cSEd Tanous std::vector<std::string> iface_list; 7654a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7661abe55efSEd Tanous if (error_code) 7671abe55efSEd Tanous { 7684a0cb85cSEd Tanous callback(false, iface_list); 7699391bb9cSRapkiewicz, Pawel return; 7709391bb9cSRapkiewicz, Pawel } 7719391bb9cSRapkiewicz, Pawel 7729391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 7734a0cb85cSEd Tanous for (const auto &objpath : resp) 7741abe55efSEd Tanous { 7759391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 7764a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7771abe55efSEd Tanous { 7781abe55efSEd Tanous // If interface is 7794a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 7804a0cb85cSEd Tanous // what we're looking for. 7819391bb9cSRapkiewicz, Pawel if (interface.first == 7821abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7831abe55efSEd Tanous { 7844a0cb85cSEd Tanous // Cut out everyting until last "/", ... 7854a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 7864a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 7874a0cb85cSEd Tanous if (last_pos != std::string::npos) 7881abe55efSEd Tanous { 7899391bb9cSRapkiewicz, Pawel // and put it into output vector. 7904a0cb85cSEd Tanous iface_list.emplace_back( 7914a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7929391bb9cSRapkiewicz, Pawel } 7939391bb9cSRapkiewicz, Pawel } 7949391bb9cSRapkiewicz, Pawel } 7959391bb9cSRapkiewicz, Pawel } 796a434f2bdSEd Tanous // Finally make a callback with useful data 7974a0cb85cSEd Tanous callback(true, iface_list); 7989391bb9cSRapkiewicz, Pawel }, 799aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 800aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 8019391bb9cSRapkiewicz, Pawel }; 8029391bb9cSRapkiewicz, Pawel 8039391bb9cSRapkiewicz, Pawel /** 8049391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 8059391bb9cSRapkiewicz, Pawel */ 8061abe55efSEd Tanous class EthernetCollection : public Node 8071abe55efSEd Tanous { 8089391bb9cSRapkiewicz, Pawel public: 8094a0cb85cSEd Tanous template <typename CrowApp> 8101abe55efSEd Tanous EthernetCollection(CrowApp &app) : 8114a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 8121abe55efSEd Tanous { 813588c3f0dSKowalski, Kamil entityPrivileges = { 814588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 815e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 816e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 817e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 818e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 819e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8209391bb9cSRapkiewicz, Pawel } 8219391bb9cSRapkiewicz, Pawel 8229391bb9cSRapkiewicz, Pawel private: 8239391bb9cSRapkiewicz, Pawel /** 8249391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 8259391bb9cSRapkiewicz, Pawel */ 82655c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 8271abe55efSEd Tanous const std::vector<std::string> ¶ms) override 8281abe55efSEd Tanous { 8290f74e643SEd Tanous res.jsonValue["@odata.type"] = 8300f74e643SEd Tanous "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 8310f74e643SEd Tanous res.jsonValue["@odata.context"] = 8320f74e643SEd Tanous "/redfish/v1/" 8330f74e643SEd Tanous "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 8340f74e643SEd Tanous res.jsonValue["@odata.id"] = 8350f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8360f74e643SEd Tanous res.jsonValue["Name"] = "Ethernet Network Interface Collection"; 8370f74e643SEd Tanous res.jsonValue["Description"] = 8380f74e643SEd Tanous "Collection of EthernetInterfaces for this Manager"; 8390f74e643SEd Tanous 8404a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 8411abe55efSEd Tanous // preparation 842f12894f8SJason M. Bills getEthernetIfaceList( 843f12894f8SJason M. Bills [&res](const bool &success, 8441abe55efSEd Tanous const std::vector<std::string> &iface_list) { 8454a0cb85cSEd Tanous if (!success) 8461abe55efSEd Tanous { 847f12894f8SJason M. Bills messages::internalError(res); 8484a0cb85cSEd Tanous res.end(); 8494a0cb85cSEd Tanous return; 8504a0cb85cSEd Tanous } 8514a0cb85cSEd Tanous 8524a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 8534a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 8544a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8551abe55efSEd Tanous { 8564a0cb85cSEd Tanous iface_array.push_back( 8574a0cb85cSEd Tanous {{"@odata.id", 8584a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 8594a0cb85cSEd Tanous iface_item}}); 8609391bb9cSRapkiewicz, Pawel } 8614a0cb85cSEd Tanous 8624a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 8634a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 8644a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8659391bb9cSRapkiewicz, Pawel res.end(); 8669391bb9cSRapkiewicz, Pawel }); 8679391bb9cSRapkiewicz, Pawel } 8689391bb9cSRapkiewicz, Pawel }; 8699391bb9cSRapkiewicz, Pawel 8709391bb9cSRapkiewicz, Pawel /** 8719391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8729391bb9cSRapkiewicz, Pawel */ 8731abe55efSEd Tanous class EthernetInterface : public Node 8741abe55efSEd Tanous { 8759391bb9cSRapkiewicz, Pawel public: 8769391bb9cSRapkiewicz, Pawel /* 8779391bb9cSRapkiewicz, Pawel * Default Constructor 8789391bb9cSRapkiewicz, Pawel */ 8794a0cb85cSEd Tanous template <typename CrowApp> 8801abe55efSEd Tanous EthernetInterface(CrowApp &app) : 8814a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8821abe55efSEd Tanous std::string()) 8831abe55efSEd Tanous { 884588c3f0dSKowalski, Kamil entityPrivileges = { 885588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 886e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 887e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 888e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 889e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 890e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8919391bb9cSRapkiewicz, Pawel } 8929391bb9cSRapkiewicz, Pawel 893e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 8940627a2c7SEd Tanous static void handleVlanPatch(const std::string &ifaceId, bool vlanEnable, 8950627a2c7SEd Tanous uint64_t vlanId, 8964a0cb85cSEd Tanous const EthernetInterfaceData ðData, 8974a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8981abe55efSEd Tanous { 8994a0cb85cSEd Tanous if (!ethData.vlan_id) 9001abe55efSEd Tanous { 901e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 902e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 903a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, "VLANEnable"); 904588c3f0dSKowalski, Kamil 905588c3f0dSKowalski, Kamil return; 906588c3f0dSKowalski, Kamil } 907588c3f0dSKowalski, Kamil 908588c3f0dSKowalski, Kamil // VLAN is configured on the interface 9090627a2c7SEd Tanous if (vlanEnable == true) 9101abe55efSEd Tanous { 911588c3f0dSKowalski, Kamil // Change VLAN Id 9120627a2c7SEd Tanous asyncResp->res.jsonValue["VLANId"] = vlanId; 9134a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9141abe55efSEd Tanous if (ec) 9151abe55efSEd Tanous { 916f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9171abe55efSEd Tanous } 9181abe55efSEd Tanous else 9191abe55efSEd Tanous { 9204a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 921e439f0f8SKowalski, Kamil } 9224a0cb85cSEd Tanous }; 9234a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9244a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9254a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9264a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 9274a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 928abf2add6SEd Tanous std::variant<uint32_t>(vlanId)); 9291abe55efSEd Tanous } 9304a0cb85cSEd Tanous else 9311abe55efSEd Tanous { 9324a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9331abe55efSEd Tanous if (ec) 9341abe55efSEd Tanous { 935f12894f8SJason M. Bills messages::internalError(asyncResp->res); 9364a0cb85cSEd Tanous return; 9371abe55efSEd Tanous } 9384a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 9394a0cb85cSEd Tanous }; 9404a0cb85cSEd Tanous 9414a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 9424a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 9434a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 9444a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 945588c3f0dSKowalski, Kamil } 946588c3f0dSKowalski, Kamil } 947588c3f0dSKowalski, Kamil 948e439f0f8SKowalski, Kamil private: 949bc0bd6e0SEd Tanous void handleHostnamePatch(const std::string &hostname, 9504a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9511abe55efSEd Tanous { 952bc0bd6e0SEd Tanous asyncResp->res.jsonValue["HostName"] = hostname; 953bc0bd6e0SEd Tanous crow::connections::systemBus->async_method_call( 954bc0bd6e0SEd Tanous [asyncResp](const boost::system::error_code ec) { 9554a0cb85cSEd Tanous if (ec) 9564a0cb85cSEd Tanous { 957a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 9581abe55efSEd Tanous } 959bc0bd6e0SEd Tanous }, 960bc0bd6e0SEd Tanous "xyz.openbmc_project.Network", 961bc0bd6e0SEd Tanous "/xyz/openbmc_project/network/config", 962bc0bd6e0SEd Tanous "org.freedesktop.DBus.Properties", "Set", 963bc0bd6e0SEd Tanous "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 964abf2add6SEd Tanous std::variant<std::string>(hostname)); 965588c3f0dSKowalski, Kamil } 966588c3f0dSKowalski, Kamil 967*d577665bSRatan Gupta void handleMACAddressPatch(const std::string &ifaceId, 968*d577665bSRatan Gupta const std::string &macAddress, 969*d577665bSRatan Gupta const std::shared_ptr<AsyncResp> &asyncResp) 970*d577665bSRatan Gupta { 971*d577665bSRatan Gupta crow::connections::systemBus->async_method_call( 972*d577665bSRatan Gupta [asyncResp, macAddress](const boost::system::error_code ec) { 973*d577665bSRatan Gupta if (ec) 974*d577665bSRatan Gupta { 975*d577665bSRatan Gupta messages::internalError(asyncResp->res); 976*d577665bSRatan Gupta return; 977*d577665bSRatan Gupta } 978*d577665bSRatan Gupta asyncResp->res.jsonValue["MACAddress"] = std::move(macAddress); 979*d577665bSRatan Gupta }, 980*d577665bSRatan Gupta "xyz.openbmc_project.Network", 981*d577665bSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId, 982*d577665bSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 983*d577665bSRatan Gupta "xyz.openbmc_project.Network.MACAddress", "MACAddress", 984*d577665bSRatan Gupta std::variant<std::string>(macAddress)); 985*d577665bSRatan Gupta } 986*d577665bSRatan Gupta 9874a0cb85cSEd Tanous void handleIPv4Patch( 988f476acbfSRatan Gupta const std::string &ifaceId, nlohmann::json &input, 9894a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 9904a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9911abe55efSEd Tanous { 992f476acbfSRatan Gupta if (!input.is_array()) 993f476acbfSRatan Gupta { 994f476acbfSRatan Gupta messages::propertyValueTypeError(asyncResp->res, input.dump(), 995f476acbfSRatan Gupta "IPv4Addresses"); 996f476acbfSRatan Gupta return; 997f476acbfSRatan Gupta } 998f476acbfSRatan Gupta 9994a0cb85cSEd Tanous int entryIdx = 0; 10004a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 10014a0cb85cSEd Tanous ipv4Data.begin(); 1002537174c4SEd Tanous for (nlohmann::json &thisJson : input) 10031abe55efSEd Tanous { 10044a0cb85cSEd Tanous std::string pathString = 1005a08b46ccSJason M. Bills "IPv4Addresses/" + std::to_string(entryIdx); 1006179db1d7SKowalski, Kamil 1007f476acbfSRatan Gupta if (thisJson.is_null()) 1008f476acbfSRatan Gupta { 1009f476acbfSRatan Gupta if (thisData != ipv4Data.end()) 1010f476acbfSRatan Gupta { 1011f476acbfSRatan Gupta deleteIPv4(ifaceId, thisData->id, entryIdx, asyncResp); 1012f476acbfSRatan Gupta thisData++; 1013f476acbfSRatan Gupta } 1014f476acbfSRatan Gupta else 1015f476acbfSRatan Gupta { 1016f476acbfSRatan Gupta messages::propertyValueFormatError( 1017f476acbfSRatan Gupta asyncResp->res, input.dump(), pathString); 1018f476acbfSRatan Gupta return; 1019f476acbfSRatan Gupta // TODO(ratagupt) Not sure about the property where value is 1020f476acbfSRatan Gupta // list and if unable to update one of the 1021f476acbfSRatan Gupta // list value then should we proceed further or 1022f476acbfSRatan Gupta // break there, would ask in the redfish forum 1023f476acbfSRatan Gupta // till then we stop processing the next list item. 1024f476acbfSRatan Gupta } 1025f476acbfSRatan Gupta entryIdx++; 1026f476acbfSRatan Gupta continue; // not an error as per the redfish spec. 1027f476acbfSRatan Gupta } 1028f476acbfSRatan Gupta 10299474b378SRatan Gupta if (thisJson.empty()) 10309474b378SRatan Gupta { 10319474b378SRatan Gupta if (thisData != ipv4Data.end()) 10329474b378SRatan Gupta { 10339474b378SRatan Gupta thisData++; 10349474b378SRatan Gupta } 10359474b378SRatan Gupta else 10369474b378SRatan Gupta { 10379474b378SRatan Gupta messages::propertyMissing(asyncResp->res, 10389474b378SRatan Gupta pathString + "/Address"); 10399474b378SRatan Gupta return; 1040f476acbfSRatan Gupta // TODO(ratagupt) Not sure about the property where value is 10419474b378SRatan Gupta // list and if unable to update one of the 10429474b378SRatan Gupta // list value then should we proceed further or 10439474b378SRatan Gupta // break there, would ask in the redfish forum 10449474b378SRatan Gupta // till then we stop processing the next list item. 10459474b378SRatan Gupta } 10469474b378SRatan Gupta entryIdx++; 10479474b378SRatan Gupta continue; // not an error as per the redfish spec. 10489474b378SRatan Gupta } 10499474b378SRatan Gupta 1050537174c4SEd Tanous std::optional<std::string> address; 1051537174c4SEd Tanous std::optional<std::string> addressOrigin; 1052537174c4SEd Tanous std::optional<std::string> subnetMask; 1053537174c4SEd Tanous std::optional<std::string> gateway; 1054537174c4SEd Tanous 1055537174c4SEd Tanous if (!json_util::readJson(thisJson, asyncResp->res, "Address", 1056537174c4SEd Tanous address, "AddressOrigin", addressOrigin, 1057537174c4SEd Tanous "SubnetMask", subnetMask, "Gateway", 1058537174c4SEd Tanous gateway)) 1059537174c4SEd Tanous { 1060537174c4SEd Tanous return; 1061179db1d7SKowalski, Kamil } 1062179db1d7SKowalski, Kamil 1063537174c4SEd Tanous if (address) 10641abe55efSEd Tanous { 1065537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*address)) 10661abe55efSEd Tanous { 1067537174c4SEd Tanous messages::propertyValueFormatError(asyncResp->res, *address, 10684a0cb85cSEd Tanous pathString + "/Address"); 1069537174c4SEd Tanous return; 10704a0cb85cSEd Tanous } 10714a0cb85cSEd Tanous } 10724a0cb85cSEd Tanous 1073537174c4SEd Tanous uint8_t prefixLength = 0; 1074537174c4SEd Tanous if (subnetMask) 10754a0cb85cSEd Tanous { 1076537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) 10774a0cb85cSEd Tanous { 1078f12894f8SJason M. Bills messages::propertyValueFormatError( 1079537174c4SEd Tanous asyncResp->res, *subnetMask, 10804a0cb85cSEd Tanous pathString + "/SubnetMask"); 1081537174c4SEd Tanous return; 10824a0cb85cSEd Tanous } 10834a0cb85cSEd Tanous } 10844a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 1085537174c4SEd Tanous if (addressOrigin) 10864a0cb85cSEd Tanous { 10874a0cb85cSEd Tanous // Get Address origin in proper format 10884a0cb85cSEd Tanous addressOriginInDBusFormat = 1089537174c4SEd Tanous translateAddressOriginRedfishToDbus(*addressOrigin); 10904a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 10914a0cb85cSEd Tanous { 10924a0cb85cSEd Tanous messages::propertyValueNotInList( 1093537174c4SEd Tanous asyncResp->res, *addressOrigin, 1094a08b46ccSJason M. Bills pathString + "/AddressOrigin"); 1095537174c4SEd Tanous return; 10964a0cb85cSEd Tanous } 10974a0cb85cSEd Tanous } 10984a0cb85cSEd Tanous 1099537174c4SEd Tanous if (gateway) 11004a0cb85cSEd Tanous { 1101537174c4SEd Tanous if (!ipv4VerifyIpAndGetBitcount(*gateway)) 11024a0cb85cSEd Tanous { 1103537174c4SEd Tanous messages::propertyValueFormatError(asyncResp->res, *gateway, 1104537174c4SEd Tanous pathString + "/Gateway"); 1105537174c4SEd Tanous return; 11064a0cb85cSEd Tanous } 11074a0cb85cSEd Tanous } 11084a0cb85cSEd Tanous 1109f476acbfSRatan Gupta // if IP address exist then modify it. 11104a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 11114a0cb85cSEd Tanous { 1112179db1d7SKowalski, Kamil // Apply changes 1113537174c4SEd Tanous if (address) 11141abe55efSEd Tanous { 1115f476acbfSRatan Gupta auto callback = [asyncResp, entryIdx, 1116f476acbfSRatan Gupta address{std::string(*address)}]( 11174a0cb85cSEd Tanous const boost::system::error_code ec) { 11184a0cb85cSEd Tanous if (ec) 11191abe55efSEd Tanous { 1120a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11214a0cb85cSEd Tanous return; 11224a0cb85cSEd Tanous } 1123f476acbfSRatan Gupta asyncResp->res 1124f476acbfSRatan Gupta .jsonValue["IPv4Addresses"][entryIdx]["Address"] = 1125f476acbfSRatan Gupta std::move(address); 11264a0cb85cSEd Tanous }; 11274a0cb85cSEd Tanous 11284a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11294a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1130f476acbfSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 1131f476acbfSRatan Gupta thisData->id, 11324a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11334a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 1134537174c4SEd Tanous std::variant<std::string>(*address)); 1135179db1d7SKowalski, Kamil } 1136179db1d7SKowalski, Kamil 1137537174c4SEd Tanous if (subnetMask) 11381abe55efSEd Tanous { 11394a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 1140537174c4SEd Tanous thisData->id, *subnetMask, 1141537174c4SEd Tanous prefixLength, asyncResp); 1142179db1d7SKowalski, Kamil } 1143179db1d7SKowalski, Kamil 1144537174c4SEd Tanous if (addressOrigin) 11451abe55efSEd Tanous { 11464a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 1147f476acbfSRatan Gupta *addressOrigin, addressOriginInDBusFormat, 1148f476acbfSRatan Gupta asyncResp); 1149179db1d7SKowalski, Kamil } 1150179db1d7SKowalski, Kamil 1151537174c4SEd Tanous if (gateway) 11521abe55efSEd Tanous { 1153f476acbfSRatan Gupta auto callback = [asyncResp, entryIdx, 1154537174c4SEd Tanous gateway{std::string(*gateway)}]( 11554a0cb85cSEd Tanous const boost::system::error_code ec) { 11564a0cb85cSEd Tanous if (ec) 11571abe55efSEd Tanous { 1158a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 11594a0cb85cSEd Tanous return; 11604a0cb85cSEd Tanous } 1161f476acbfSRatan Gupta asyncResp->res 1162f476acbfSRatan Gupta .jsonValue["IPv4Addresses"][entryIdx]["Gateway"] = 1163537174c4SEd Tanous std::move(gateway); 11644a0cb85cSEd Tanous }; 11654a0cb85cSEd Tanous 11664a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 11674a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1168f476acbfSRatan Gupta "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 1169f476acbfSRatan Gupta thisData->id, 11704a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 11714a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 1172537174c4SEd Tanous std::variant<std::string>(*gateway)); 11734a0cb85cSEd Tanous } 1174f476acbfSRatan Gupta 11754a0cb85cSEd Tanous thisData++; 11761abe55efSEd Tanous } 11771abe55efSEd Tanous else 11781abe55efSEd Tanous { 11794a0cb85cSEd Tanous // Create IPv4 with provided data 1180537174c4SEd Tanous if (!gateway) 11811abe55efSEd Tanous { 1182a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11834a0cb85cSEd Tanous pathString + "/Gateway"); 11844a0cb85cSEd Tanous continue; 11854a0cb85cSEd Tanous } 11864a0cb85cSEd Tanous 1187537174c4SEd Tanous if (!address) 11881abe55efSEd Tanous { 1189a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11904a0cb85cSEd Tanous pathString + "/Address"); 11914a0cb85cSEd Tanous continue; 11924a0cb85cSEd Tanous } 11934a0cb85cSEd Tanous 1194537174c4SEd Tanous if (!subnetMask) 11951abe55efSEd Tanous { 1196a08b46ccSJason M. Bills messages::propertyMissing(asyncResp->res, 11974a0cb85cSEd Tanous pathString + "/SubnetMask"); 11984a0cb85cSEd Tanous continue; 1199588c3f0dSKowalski, Kamil } 1200588c3f0dSKowalski, Kamil 1201537174c4SEd Tanous createIPv4(ifaceId, entryIdx, prefixLength, *gateway, *address, 1202537174c4SEd Tanous asyncResp); 12034a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 12044a0cb85cSEd Tanous } 12054a0cb85cSEd Tanous entryIdx++; 12064a0cb85cSEd Tanous } 12074a0cb85cSEd Tanous } 12084a0cb85cSEd Tanous 12090f74e643SEd Tanous void parseInterfaceData( 12100f74e643SEd Tanous nlohmann::json &json_response, const std::string &iface_id, 12110f74e643SEd Tanous const EthernetInterfaceData ðData, 12124a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 12134a0cb85cSEd Tanous { 12144a0cb85cSEd Tanous json_response["Id"] = iface_id; 12154a0cb85cSEd Tanous json_response["@odata.id"] = 12164a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 1217029573d4SEd Tanous json_response["InterfaceEnabled"] = true; 1218029573d4SEd Tanous if (ethData.speed == 0) 1219029573d4SEd Tanous { 1220029573d4SEd Tanous json_response["LinkStatus"] = "NoLink"; 1221029573d4SEd Tanous json_response["Status"] = { 1222029573d4SEd Tanous {"Health", "OK"}, 1223029573d4SEd Tanous {"State", "Disabled"}, 1224029573d4SEd Tanous }; 1225029573d4SEd Tanous } 1226029573d4SEd Tanous else 1227029573d4SEd Tanous { 1228029573d4SEd Tanous json_response["LinkStatus"] = "LinkUp"; 1229029573d4SEd Tanous json_response["Status"] = { 1230029573d4SEd Tanous {"Health", "OK"}, 1231029573d4SEd Tanous {"State", "Enabled"}, 1232029573d4SEd Tanous }; 1233029573d4SEd Tanous } 12344a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 12354a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 12362a133282Smanojkiraneda json_response["DHCPv4Configuration"]["DHCPEnabled"] = 12372a133282Smanojkiraneda ethData.DHCPEnabled; 12382a133282Smanojkiraneda 12394a0cb85cSEd Tanous if (!ethData.hostname.empty()) 12404a0cb85cSEd Tanous { 12414a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 12424a0cb85cSEd Tanous } 12434a0cb85cSEd Tanous 12444a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 12454a0cb85cSEd Tanous if (ethData.vlan_id) 12464a0cb85cSEd Tanous { 12474a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 12484a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 12494a0cb85cSEd Tanous } 12504a0cb85cSEd Tanous else 12514a0cb85cSEd Tanous { 12524a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 12534a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 12544a0cb85cSEd Tanous } 1255029573d4SEd Tanous json_response["NameServers"] = ethData.nameservers; 12564a0cb85cSEd Tanous 12574a0cb85cSEd Tanous if (ipv4Data.size() > 0) 12584a0cb85cSEd Tanous { 12594a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 12604a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 12614a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 12624a0cb85cSEd Tanous { 12634a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 12644a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 1265029573d4SEd Tanous {"Address", ipv4_config.address}, 1266029573d4SEd Tanous {"Gateway", ipv4_config.gateway}}); 12674a0cb85cSEd Tanous } 12684a0cb85cSEd Tanous } 1269588c3f0dSKowalski, Kamil } 1270588c3f0dSKowalski, Kamil 12719391bb9cSRapkiewicz, Pawel /** 12729391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 12739391bb9cSRapkiewicz, Pawel */ 127455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 12751abe55efSEd Tanous const std::vector<std::string> ¶ms) override 12761abe55efSEd Tanous { 12774a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 12781abe55efSEd Tanous if (params.size() != 1) 12791abe55efSEd Tanous { 1280f12894f8SJason M. Bills messages::internalError(asyncResp->res); 12819391bb9cSRapkiewicz, Pawel return; 12829391bb9cSRapkiewicz, Pawel } 12839391bb9cSRapkiewicz, Pawel 12844a0cb85cSEd Tanous getEthernetIfaceData( 12854a0cb85cSEd Tanous params[0], 12864a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 12874a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 12884a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 12894a0cb85cSEd Tanous if (!success) 12901abe55efSEd Tanous { 12911abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 12921abe55efSEd Tanous // object, and other errors 1293f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, 1294f12894f8SJason M. Bills "EthernetInterface", iface_id); 12954a0cb85cSEd Tanous return; 12969391bb9cSRapkiewicz, Pawel } 12970f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 12980f74e643SEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 12990f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 13000f74e643SEd Tanous "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 13010f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; 13020f74e643SEd Tanous asyncResp->res.jsonValue["Description"] = 13030f74e643SEd Tanous "Management Network Interface"; 13040f74e643SEd Tanous 13050f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13060f74e643SEd Tanous ipv4Data); 13079391bb9cSRapkiewicz, Pawel }); 13082a133282Smanojkiraneda getDHCPConfigData(asyncResp); 13099391bb9cSRapkiewicz, Pawel } 13109391bb9cSRapkiewicz, Pawel 131155c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 13121abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13131abe55efSEd Tanous { 13144a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13151abe55efSEd Tanous if (params.size() != 1) 13161abe55efSEd Tanous { 1317f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1318588c3f0dSKowalski, Kamil return; 1319588c3f0dSKowalski, Kamil } 1320588c3f0dSKowalski, Kamil 13214a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1322588c3f0dSKowalski, Kamil 13230627a2c7SEd Tanous std::optional<nlohmann::json> vlan; 1324bc0bd6e0SEd Tanous std::optional<std::string> hostname; 1325*d577665bSRatan Gupta std::optional<std::string> macAddress; 1326f476acbfSRatan Gupta std::optional<nlohmann::json> ipv4Addresses; 1327f476acbfSRatan Gupta std::optional<nlohmann::json> ipv6Addresses; 13280627a2c7SEd Tanous 13290627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLAN", vlan, "HostName", hostname, 13300627a2c7SEd Tanous "IPv4Addresses", ipv4Addresses, 1331*d577665bSRatan Gupta "IPv6Addresses", ipv6Addresses, "MACAddress", 1332*d577665bSRatan Gupta macAddress)) 13331abe55efSEd Tanous { 1334588c3f0dSKowalski, Kamil return; 1335588c3f0dSKowalski, Kamil } 1336f15aad37SRatan Gupta 1337f15aad37SRatan Gupta std::optional<uint64_t> vlanId; 1338f15aad37SRatan Gupta std::optional<bool> vlanEnable; 1339f15aad37SRatan Gupta 13400627a2c7SEd Tanous if (vlan) 13410627a2c7SEd Tanous { 13420627a2c7SEd Tanous if (!json_util::readJson(*vlan, res, "VLANEnable", vlanEnable, 13430627a2c7SEd Tanous "VLANId", vlanId)) 13440627a2c7SEd Tanous { 13450627a2c7SEd Tanous return; 13460627a2c7SEd Tanous } 13470627a2c7SEd Tanous // Need both vlanId and vlanEnable to service this request 13480627a2c7SEd Tanous if (static_cast<bool>(vlanId) ^ static_cast<bool>(vlanEnable)) 13490627a2c7SEd Tanous { 13500627a2c7SEd Tanous if (vlanId) 13510627a2c7SEd Tanous { 13520627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANEnable"); 13530627a2c7SEd Tanous } 13540627a2c7SEd Tanous else 13550627a2c7SEd Tanous { 13560627a2c7SEd Tanous messages::propertyMissing(asyncResp->res, "VLANId"); 13570627a2c7SEd Tanous } 13580627a2c7SEd Tanous 13590627a2c7SEd Tanous return; 13600627a2c7SEd Tanous } 13610627a2c7SEd Tanous } 1362588c3f0dSKowalski, Kamil 13634a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1364588c3f0dSKowalski, Kamil // preparation 13654a0cb85cSEd Tanous getEthernetIfaceData( 13664a0cb85cSEd Tanous iface_id, 13670627a2c7SEd Tanous [this, asyncResp, iface_id, vlanId, vlanEnable, 1368*d577665bSRatan Gupta hostname = std::move(hostname), macAddress = std::move(macAddress), 13690627a2c7SEd Tanous ipv4Addresses = std::move(ipv4Addresses), 13700627a2c7SEd Tanous ipv6Addresses = std::move(ipv6Addresses)]( 13714a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 13724a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 13731abe55efSEd Tanous if (!success) 13741abe55efSEd Tanous { 1375588c3f0dSKowalski, Kamil // ... otherwise return error 13761abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13771abe55efSEd Tanous // object, and other errors 1378f12894f8SJason M. Bills messages::resourceNotFound( 1379f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1380588c3f0dSKowalski, Kamil return; 1381588c3f0dSKowalski, Kamil } 1382588c3f0dSKowalski, Kamil 13830f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, iface_id, ethData, 13840f74e643SEd Tanous ipv4Data); 1385588c3f0dSKowalski, Kamil 13860627a2c7SEd Tanous if (vlanId && vlanEnable) 13871abe55efSEd Tanous { 13880627a2c7SEd Tanous handleVlanPatch(iface_id, *vlanId, *vlanEnable, ethData, 13894a0cb85cSEd Tanous asyncResp); 13901abe55efSEd Tanous } 13910627a2c7SEd Tanous 13920627a2c7SEd Tanous if (hostname) 13931abe55efSEd Tanous { 13940627a2c7SEd Tanous handleHostnamePatch(*hostname, asyncResp); 13951abe55efSEd Tanous } 13960627a2c7SEd Tanous 1397*d577665bSRatan Gupta if (macAddress) 1398*d577665bSRatan Gupta { 1399*d577665bSRatan Gupta handleMACAddressPatch(iface_id, *macAddress, asyncResp); 1400*d577665bSRatan Gupta } 1401*d577665bSRatan Gupta 14020627a2c7SEd Tanous if (ipv4Addresses) 14031abe55efSEd Tanous { 1404537174c4SEd Tanous // TODO(ed) for some reason the capture of ipv4Addresses 1405537174c4SEd Tanous // above is returning a const value, not a non-const value. 1406537174c4SEd Tanous // This doesn't really work for us, as we need to be able to 1407537174c4SEd Tanous // efficiently move out the intermedia nlohmann::json 1408537174c4SEd Tanous // objects. This makes a copy of the structure, and operates 1409537174c4SEd Tanous // on that, but could be done more efficiently 1410f476acbfSRatan Gupta nlohmann::json ipv4 = std::move(*ipv4Addresses); 1411537174c4SEd Tanous handleIPv4Patch(iface_id, ipv4, ipv4Data, asyncResp); 14121abe55efSEd Tanous } 14130627a2c7SEd Tanous 14140627a2c7SEd Tanous if (ipv6Addresses) 14151abe55efSEd Tanous { 1416179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1417a08b46ccSJason M. Bills messages::propertyNotWritable(asyncResp->res, 14180627a2c7SEd Tanous "IPv6Addresses"); 1419588c3f0dSKowalski, Kamil } 1420588c3f0dSKowalski, Kamil }); 1421588c3f0dSKowalski, Kamil } 14229391bb9cSRapkiewicz, Pawel }; 14239391bb9cSRapkiewicz, Pawel 1424e439f0f8SKowalski, Kamil /** 14254a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 14264a0cb85cSEd Tanous * Schema 1427e439f0f8SKowalski, Kamil */ 14281abe55efSEd Tanous class VlanNetworkInterface : public Node 14291abe55efSEd Tanous { 1430e439f0f8SKowalski, Kamil public: 1431e439f0f8SKowalski, Kamil /* 1432e439f0f8SKowalski, Kamil * Default Constructor 1433e439f0f8SKowalski, Kamil */ 1434e439f0f8SKowalski, Kamil template <typename CrowApp> 14351abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 14364a0cb85cSEd Tanous Node(app, 14370f74e643SEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>", 14381abe55efSEd Tanous std::string(), std::string()) 14391abe55efSEd Tanous { 1440e439f0f8SKowalski, Kamil entityPrivileges = { 1441e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1442e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1443e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1444e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1445e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1446e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1447e439f0f8SKowalski, Kamil } 1448e439f0f8SKowalski, Kamil 1449e439f0f8SKowalski, Kamil private: 14500f74e643SEd Tanous void parseInterfaceData( 14510f74e643SEd Tanous nlohmann::json &json_response, const std::string &parent_iface_id, 14520f74e643SEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 14534a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 14541abe55efSEd Tanous { 1455e439f0f8SKowalski, Kamil // Fill out obvious data... 14564a0cb85cSEd Tanous json_response["Id"] = iface_id; 14574a0cb85cSEd Tanous json_response["@odata.id"] = 14584a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 14594a0cb85cSEd Tanous "/VLANs/" + iface_id; 1460e439f0f8SKowalski, Kamil 14614a0cb85cSEd Tanous json_response["VLANEnable"] = true; 14624a0cb85cSEd Tanous if (ethData.vlan_id) 14634a0cb85cSEd Tanous { 14644a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 14654a0cb85cSEd Tanous } 1466e439f0f8SKowalski, Kamil } 1467e439f0f8SKowalski, Kamil 146855c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 14691abe55efSEd Tanous const std::string &iface) 14701abe55efSEd Tanous { 1471f12894f8SJason M. Bills std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14721abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 14731abe55efSEd Tanous { 1474f12894f8SJason M. Bills messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", 1475f12894f8SJason M. Bills iface); 1476927a505aSKowalski, Kamil return false; 14771abe55efSEd Tanous } 14781abe55efSEd Tanous else 14791abe55efSEd Tanous { 1480927a505aSKowalski, Kamil return true; 1481927a505aSKowalski, Kamil } 1482927a505aSKowalski, Kamil } 1483927a505aSKowalski, Kamil 1484e439f0f8SKowalski, Kamil /** 1485e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1486e439f0f8SKowalski, Kamil */ 148755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 14881abe55efSEd Tanous const std::vector<std::string> ¶ms) override 14891abe55efSEd Tanous { 14904a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 14914a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1492e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1493e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1494e439f0f8SKowalski, Kamil // impossible. 14951abe55efSEd Tanous if (params.size() != 2) 14961abe55efSEd Tanous { 1497f12894f8SJason M. Bills messages::internalError(res); 1498e439f0f8SKowalski, Kamil res.end(); 1499e439f0f8SKowalski, Kamil return; 1500e439f0f8SKowalski, Kamil } 1501e439f0f8SKowalski, Kamil 15024a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 15034a0cb85cSEd Tanous const std::string &iface_id = params[1]; 15040f74e643SEd Tanous res.jsonValue["@odata.type"] = 15050f74e643SEd Tanous "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 15060f74e643SEd Tanous res.jsonValue["@odata.context"] = 15070f74e643SEd Tanous "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 15080f74e643SEd Tanous res.jsonValue["Name"] = "VLAN Network Interface"; 1509e439f0f8SKowalski, Kamil 15104a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 15111abe55efSEd Tanous { 1512a434f2bdSEd Tanous return; 1513a434f2bdSEd Tanous } 1514a434f2bdSEd Tanous 1515e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1516e439f0f8SKowalski, Kamil // preparation 15174a0cb85cSEd Tanous getEthernetIfaceData( 15184a0cb85cSEd Tanous iface_id, 15194a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 15204a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15214a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15224a0cb85cSEd Tanous if (success && ethData.vlan_id) 15231abe55efSEd Tanous { 15240f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, 15250f74e643SEd Tanous parent_iface_id, iface_id, ethData, 15260f74e643SEd Tanous ipv4Data); 15271abe55efSEd Tanous } 15281abe55efSEd Tanous else 15291abe55efSEd Tanous { 1530e439f0f8SKowalski, Kamil // ... otherwise return error 15311abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15321abe55efSEd Tanous // object, and other errors 1533f12894f8SJason M. Bills messages::resourceNotFound( 1534f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", iface_id); 1535e439f0f8SKowalski, Kamil } 1536e439f0f8SKowalski, Kamil }); 1537e439f0f8SKowalski, Kamil } 1538e439f0f8SKowalski, Kamil 153955c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 15401abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15411abe55efSEd Tanous { 15424a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15431abe55efSEd Tanous if (params.size() != 2) 15441abe55efSEd Tanous { 1545f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1546e439f0f8SKowalski, Kamil return; 1547e439f0f8SKowalski, Kamil } 1548e439f0f8SKowalski, Kamil 1549d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 155055c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1551927a505aSKowalski, Kamil 15521abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 15531abe55efSEd Tanous { 1554927a505aSKowalski, Kamil return; 1555927a505aSKowalski, Kamil } 1556927a505aSKowalski, Kamil 15570627a2c7SEd Tanous bool vlanEnable = false; 15580627a2c7SEd Tanous uint64_t vlanId = 0; 15590627a2c7SEd Tanous 15600627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANEnable", vlanEnable, "VLANId", 15610627a2c7SEd Tanous vlanId)) 15621abe55efSEd Tanous { 1563927a505aSKowalski, Kamil return; 1564927a505aSKowalski, Kamil } 1565927a505aSKowalski, Kamil 1566927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1567927a505aSKowalski, Kamil // preparation 15684a0cb85cSEd Tanous getEthernetIfaceData( 15691abe55efSEd Tanous ifaceId, 15700627a2c7SEd Tanous [this, asyncResp, parentIfaceId, ifaceId, vlanEnable, vlanId]( 15714a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 15724a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 15731abe55efSEd Tanous if (!success) 15741abe55efSEd Tanous { 15751abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 15761abe55efSEd Tanous // object, and other errors 1577f12894f8SJason M. Bills messages::resourceNotFound( 1578f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1579927a505aSKowalski, Kamil 1580927a505aSKowalski, Kamil return; 1581927a505aSKowalski, Kamil } 1582927a505aSKowalski, Kamil 15830f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 15840f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1585927a505aSKowalski, Kamil 15860627a2c7SEd Tanous EthernetInterface::handleVlanPatch(ifaceId, vlanId, vlanEnable, 15870627a2c7SEd Tanous ethData, asyncResp); 1588927a505aSKowalski, Kamil }); 1589e439f0f8SKowalski, Kamil } 1590e439f0f8SKowalski, Kamil 159155c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 15921abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15931abe55efSEd Tanous { 15944a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 15951abe55efSEd Tanous if (params.size() != 2) 15961abe55efSEd Tanous { 1597f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1598e439f0f8SKowalski, Kamil return; 1599e439f0f8SKowalski, Kamil } 1600e439f0f8SKowalski, Kamil 1601d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 160255c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1603927a505aSKowalski, Kamil 16044a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 16051abe55efSEd Tanous { 1606927a505aSKowalski, Kamil return; 1607927a505aSKowalski, Kamil } 1608927a505aSKowalski, Kamil 1609927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1610927a505aSKowalski, Kamil // preparation 1611f12894f8SJason M. Bills getEthernetIfaceData( 1612f12894f8SJason M. Bills ifaceId, 1613f12894f8SJason M. Bills [this, asyncResp, parentIfaceId{std::string(parentIfaceId)}, 16144a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1615f12894f8SJason M. Bills const bool &success, const EthernetInterfaceData ðData, 1616f12894f8SJason M. Bills const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 16174a0cb85cSEd Tanous if (success && ethData.vlan_id) 16181abe55efSEd Tanous { 16190f74e643SEd Tanous parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, 16200f74e643SEd Tanous ifaceId, ethData, ipv4Data); 1621927a505aSKowalski, Kamil 1622f12894f8SJason M. Bills auto callback = 1623f12894f8SJason M. Bills [asyncResp](const boost::system::error_code ec) { 16241abe55efSEd Tanous if (ec) 16251abe55efSEd Tanous { 1626f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1627927a505aSKowalski, Kamil } 16284a0cb85cSEd Tanous }; 16294a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 16304a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 16314a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 16324a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 16331abe55efSEd Tanous } 16341abe55efSEd Tanous else 16351abe55efSEd Tanous { 1636927a505aSKowalski, Kamil // ... otherwise return error 1637f12894f8SJason M. Bills // TODO(Pawel)consider distinguish between non existing 1638f12894f8SJason M. Bills // object, and other errors 1639f12894f8SJason M. Bills messages::resourceNotFound( 1640f12894f8SJason M. Bills asyncResp->res, "VLAN Network Interface", ifaceId); 1641927a505aSKowalski, Kamil } 1642927a505aSKowalski, Kamil }); 1643e439f0f8SKowalski, Kamil } 1644e439f0f8SKowalski, Kamil }; 1645e439f0f8SKowalski, Kamil 1646e439f0f8SKowalski, Kamil /** 1647e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1648e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1649e439f0f8SKowalski, Kamil */ 16501abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 16511abe55efSEd Tanous { 1652e439f0f8SKowalski, Kamil public: 1653e439f0f8SKowalski, Kamil template <typename CrowApp> 16541abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 16554a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 16564a0cb85cSEd Tanous std::string()) 16571abe55efSEd Tanous { 1658e439f0f8SKowalski, Kamil entityPrivileges = { 1659e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1660e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1661e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1662e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1663e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1664e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1665e439f0f8SKowalski, Kamil } 1666e439f0f8SKowalski, Kamil 1667e439f0f8SKowalski, Kamil private: 1668e439f0f8SKowalski, Kamil /** 1669e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1670e439f0f8SKowalski, Kamil */ 167155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 16721abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16731abe55efSEd Tanous { 16744a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16751abe55efSEd Tanous if (params.size() != 1) 16761abe55efSEd Tanous { 1677e439f0f8SKowalski, Kamil // This means there is a problem with the router 1678f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1679e439f0f8SKowalski, Kamil return; 1680e439f0f8SKowalski, Kamil } 1681e439f0f8SKowalski, Kamil 16824a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1683e439f0f8SKowalski, Kamil 16844a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 16851abe55efSEd Tanous // preparation 1686f12894f8SJason M. Bills getEthernetIfaceList( 168743b761d0SEd Tanous [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}]( 16881abe55efSEd Tanous const bool &success, 16891abe55efSEd Tanous const std::vector<std::string> &iface_list) { 16904a0cb85cSEd Tanous if (!success) 16911abe55efSEd Tanous { 1692f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16934a0cb85cSEd Tanous return; 16941abe55efSEd Tanous } 16950f74e643SEd Tanous asyncResp->res.jsonValue["@odata.type"] = 16960f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 16970f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 16980f74e643SEd Tanous asyncResp->res.jsonValue["@odata.context"] = 16990f74e643SEd Tanous "/redfish/v1/$metadata" 17000f74e643SEd Tanous "#VLanNetworkInterfaceCollection." 17010f74e643SEd Tanous "VLanNetworkInterfaceCollection"; 17020f74e643SEd Tanous asyncResp->res.jsonValue["Name"] = 17030f74e643SEd Tanous "VLAN Network Interface Collection"; 17044a0cb85cSEd Tanous 17054a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 17064a0cb85cSEd Tanous 17074a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 17081abe55efSEd Tanous { 17094a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 17104a0cb85cSEd Tanous { 17114a0cb85cSEd Tanous iface_array.push_back( 17124a0cb85cSEd Tanous {{"@odata.id", 17134a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17144a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1715e439f0f8SKowalski, Kamil } 1716e439f0f8SKowalski, Kamil } 1717e439f0f8SKowalski, Kamil 17184a0cb85cSEd Tanous if (iface_array.empty()) 17191abe55efSEd Tanous { 1720f12894f8SJason M. Bills messages::resourceNotFound( 1721f12894f8SJason M. Bills asyncResp->res, "EthernetInterface", rootInterfaceName); 17224a0cb85cSEd Tanous return; 1723e439f0f8SKowalski, Kamil } 17244a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 17254a0cb85cSEd Tanous iface_array.size(); 17264a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 17274a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17284a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 17294a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1730e439f0f8SKowalski, Kamil }); 1731e439f0f8SKowalski, Kamil } 1732e439f0f8SKowalski, Kamil 173355c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 17341abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17351abe55efSEd Tanous { 17364a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17371abe55efSEd Tanous if (params.size() != 1) 17381abe55efSEd Tanous { 1739f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1740e439f0f8SKowalski, Kamil return; 1741e439f0f8SKowalski, Kamil } 1742e439f0f8SKowalski, Kamil 17430627a2c7SEd Tanous uint32_t vlanId = 0; 17440627a2c7SEd Tanous if (!json_util::readJson(req, res, "VLANId", vlanId)) 17451abe55efSEd Tanous { 17464a0cb85cSEd Tanous return; 1747e439f0f8SKowalski, Kamil } 17484a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 17494a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 17501abe55efSEd Tanous if (ec) 17511abe55efSEd Tanous { 17524a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 17534a0cb85cSEd Tanous // phosphor-network responses 1754f12894f8SJason M. Bills messages::internalError(asyncResp->res); 17554a0cb85cSEd Tanous return; 17561abe55efSEd Tanous } 1757f12894f8SJason M. Bills messages::created(asyncResp->res); 1758e439f0f8SKowalski, Kamil }; 17594a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 17604a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 17614a0cb85cSEd Tanous "/xyz/openbmc_project/network", 17624a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 17630627a2c7SEd Tanous rootInterfaceName, vlanId); 17644a0cb85cSEd Tanous } 17654a0cb85cSEd Tanous }; 17669391bb9cSRapkiewicz, Pawel } // namespace redfish 1767