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> 19*4a0cb85cSEd Tanous #include <boost/container/flat_set.hpp> 20*4a0cb85cSEd Tanous #include <boost/optional.hpp> 21179db1d7SKowalski, Kamil #include <dbus_singleton.hpp> 22588c3f0dSKowalski, Kamil #include <error_messages.hpp> 23179db1d7SKowalski, Kamil #include <node.hpp> 24588c3f0dSKowalski, Kamil #include <utils/json_utils.hpp> 259391bb9cSRapkiewicz, Pawel 261abe55efSEd Tanous namespace redfish 271abe55efSEd Tanous { 289391bb9cSRapkiewicz, Pawel 299391bb9cSRapkiewicz, Pawel /** 309391bb9cSRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 319391bb9cSRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 329391bb9cSRapkiewicz, Pawel */ 33aa2e59c1SEd Tanous using PropertiesMapType = boost::container::flat_map< 34aa2e59c1SEd Tanous std::string, 35aa2e59c1SEd Tanous sdbusplus::message::variant<std::string, bool, uint8_t, int16_t, uint16_t, 36aa2e59c1SEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>; 379391bb9cSRapkiewicz, Pawel 38*4a0cb85cSEd Tanous using GetManagedObjects = std::vector<std::pair< 39aa2e59c1SEd Tanous sdbusplus::message::object_path, 40*4a0cb85cSEd Tanous std::vector<std::pair< 41aa2e59c1SEd Tanous std::string, 42aa2e59c1SEd Tanous boost::container::flat_map< 43aa2e59c1SEd Tanous std::string, sdbusplus::message::variant< 44aa2e59c1SEd Tanous std::string, bool, uint8_t, int16_t, uint16_t, 45*4a0cb85cSEd Tanous int32_t, uint32_t, int64_t, uint64_t, double>>>>>>; 46*4a0cb85cSEd Tanous 47*4a0cb85cSEd Tanous enum class LinkType 48*4a0cb85cSEd Tanous { 49*4a0cb85cSEd Tanous Local, 50*4a0cb85cSEd Tanous Global 51*4a0cb85cSEd Tanous }; 529391bb9cSRapkiewicz, Pawel 539391bb9cSRapkiewicz, Pawel /** 549391bb9cSRapkiewicz, Pawel * Structure for keeping IPv4 data required by Redfish 559391bb9cSRapkiewicz, Pawel */ 561abe55efSEd Tanous struct IPv4AddressData 571abe55efSEd Tanous { 58179db1d7SKowalski, Kamil std::string id; 59*4a0cb85cSEd Tanous std::string address; 60*4a0cb85cSEd Tanous std::string domain; 61*4a0cb85cSEd Tanous std::string gateway; 629391bb9cSRapkiewicz, Pawel std::string netmask; 639391bb9cSRapkiewicz, Pawel std::string origin; 64*4a0cb85cSEd Tanous LinkType linktype; 65*4a0cb85cSEd Tanous 661abe55efSEd Tanous bool operator<(const IPv4AddressData &obj) const 671abe55efSEd Tanous { 68*4a0cb85cSEd Tanous return id < obj.id; 691abe55efSEd Tanous } 709391bb9cSRapkiewicz, Pawel }; 719391bb9cSRapkiewicz, Pawel 729391bb9cSRapkiewicz, Pawel /** 739391bb9cSRapkiewicz, Pawel * Structure for keeping basic single Ethernet Interface information 749391bb9cSRapkiewicz, Pawel * available from DBus 759391bb9cSRapkiewicz, Pawel */ 761abe55efSEd Tanous struct EthernetInterfaceData 771abe55efSEd Tanous { 78*4a0cb85cSEd Tanous uint32_t speed; 79*4a0cb85cSEd Tanous bool auto_neg; 80*4a0cb85cSEd Tanous std::string hostname; 81*4a0cb85cSEd Tanous std::string default_gateway; 82*4a0cb85cSEd Tanous std::string mac_address; 83*4a0cb85cSEd Tanous boost::optional<uint32_t> vlan_id; 849391bb9cSRapkiewicz, Pawel }; 859391bb9cSRapkiewicz, Pawel 869391bb9cSRapkiewicz, Pawel // Helper function that changes bits netmask notation (i.e. /24) 879391bb9cSRapkiewicz, Pawel // into full dot notation 881abe55efSEd Tanous inline std::string getNetmask(unsigned int bits) 891abe55efSEd Tanous { 909391bb9cSRapkiewicz, Pawel uint32_t value = 0xffffffff << (32 - bits); 919391bb9cSRapkiewicz, Pawel std::string netmask = std::to_string((value >> 24) & 0xff) + "." + 929391bb9cSRapkiewicz, Pawel std::to_string((value >> 16) & 0xff) + "." + 939391bb9cSRapkiewicz, Pawel std::to_string((value >> 8) & 0xff) + "." + 949391bb9cSRapkiewicz, Pawel std::to_string(value & 0xff); 959391bb9cSRapkiewicz, Pawel return netmask; 969391bb9cSRapkiewicz, Pawel } 979391bb9cSRapkiewicz, Pawel 98*4a0cb85cSEd Tanous inline std::string 99*4a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(const std::string &inputOrigin, 100*4a0cb85cSEd Tanous bool isIPv4) 1011abe55efSEd Tanous { 102*4a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 1031abe55efSEd Tanous { 104*4a0cb85cSEd Tanous return "Static"; 1059391bb9cSRapkiewicz, Pawel } 106*4a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal") 1071abe55efSEd Tanous { 108*4a0cb85cSEd Tanous if (isIPv4) 1091abe55efSEd Tanous { 110*4a0cb85cSEd Tanous return "IPv4LinkLocal"; 1111abe55efSEd Tanous } 1121abe55efSEd Tanous else 1131abe55efSEd Tanous { 114*4a0cb85cSEd Tanous return "LinkLocal"; 1159391bb9cSRapkiewicz, Pawel } 1169391bb9cSRapkiewicz, Pawel } 117*4a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1181abe55efSEd Tanous { 119*4a0cb85cSEd Tanous if (isIPv4) 120*4a0cb85cSEd Tanous { 121*4a0cb85cSEd Tanous return "DHCP"; 122*4a0cb85cSEd Tanous } 123*4a0cb85cSEd Tanous else 124*4a0cb85cSEd Tanous { 125*4a0cb85cSEd Tanous return "DHCPv6"; 126*4a0cb85cSEd Tanous } 127*4a0cb85cSEd Tanous } 128*4a0cb85cSEd Tanous if (inputOrigin == "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC") 129*4a0cb85cSEd Tanous { 130*4a0cb85cSEd Tanous return "SLAAC"; 131*4a0cb85cSEd Tanous } 132*4a0cb85cSEd Tanous return ""; 133*4a0cb85cSEd Tanous } 134*4a0cb85cSEd Tanous 135*4a0cb85cSEd Tanous inline std::string 136*4a0cb85cSEd Tanous translateAddressOriginRedfishToDbus(const std::string &inputOrigin) 137*4a0cb85cSEd Tanous { 138*4a0cb85cSEd Tanous if (inputOrigin == "Static") 139*4a0cb85cSEd Tanous { 140*4a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 141*4a0cb85cSEd Tanous } 142*4a0cb85cSEd Tanous if (inputOrigin == "DHCP" || inputOrigin == "DHCPv6") 143*4a0cb85cSEd Tanous { 144*4a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 145*4a0cb85cSEd Tanous } 146*4a0cb85cSEd Tanous if (inputOrigin == "IPv4LinkLocal" || inputOrigin == "LinkLocal") 147*4a0cb85cSEd Tanous { 148*4a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal"; 149*4a0cb85cSEd Tanous } 150*4a0cb85cSEd Tanous if (inputOrigin == "SLAAC") 151*4a0cb85cSEd Tanous { 152*4a0cb85cSEd Tanous return "xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC"; 153*4a0cb85cSEd Tanous } 154*4a0cb85cSEd Tanous return ""; 155*4a0cb85cSEd Tanous } 156*4a0cb85cSEd Tanous 157*4a0cb85cSEd Tanous inline void extractEthernetInterfaceData(const std::string ðiface_id, 158*4a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 159*4a0cb85cSEd Tanous EthernetInterfaceData ðData) 160*4a0cb85cSEd Tanous { 161*4a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 162*4a0cb85cSEd Tanous { 163*4a0cb85cSEd Tanous if (objpath.first == "/xyz/openbmc_project/network/" + ethiface_id) 164*4a0cb85cSEd Tanous { 165*4a0cb85cSEd Tanous for (const auto &ifacePair : objpath.second) 166*4a0cb85cSEd Tanous { 167*4a0cb85cSEd Tanous if (ifacePair.first == "xyz.openbmc_project.Network.MACAddress") 168*4a0cb85cSEd Tanous { 169*4a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 170*4a0cb85cSEd Tanous { 171*4a0cb85cSEd Tanous if (propertyPair.first == "MACAddress") 172*4a0cb85cSEd Tanous { 173*4a0cb85cSEd Tanous const std::string *mac = 174*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 175*4a0cb85cSEd Tanous propertyPair.second); 176*4a0cb85cSEd Tanous if (mac != nullptr) 177*4a0cb85cSEd Tanous { 178*4a0cb85cSEd Tanous ethData.mac_address = *mac; 179*4a0cb85cSEd Tanous } 180*4a0cb85cSEd Tanous } 181*4a0cb85cSEd Tanous } 182*4a0cb85cSEd Tanous } 183*4a0cb85cSEd Tanous else if (ifacePair.first == "xyz.openbmc_project.Network.VLAN") 184*4a0cb85cSEd Tanous { 185*4a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 186*4a0cb85cSEd Tanous { 187*4a0cb85cSEd Tanous if (propertyPair.first == "Id") 188*4a0cb85cSEd Tanous { 189*4a0cb85cSEd Tanous const uint32_t *id = mapbox::getPtr<const uint32_t>( 190*4a0cb85cSEd Tanous propertyPair.second); 191*4a0cb85cSEd Tanous if (id != nullptr) 192*4a0cb85cSEd Tanous { 193*4a0cb85cSEd Tanous ethData.vlan_id = *id; 194*4a0cb85cSEd Tanous } 195*4a0cb85cSEd Tanous } 196*4a0cb85cSEd Tanous } 197*4a0cb85cSEd Tanous } 198*4a0cb85cSEd Tanous else if (ifacePair.first == 199*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 200*4a0cb85cSEd Tanous { 201*4a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 202*4a0cb85cSEd Tanous { 203*4a0cb85cSEd Tanous if (propertyPair.first == "AutoNeg") 204*4a0cb85cSEd Tanous { 205*4a0cb85cSEd Tanous const bool *auto_neg = 206*4a0cb85cSEd Tanous mapbox::getPtr<const bool>(propertyPair.second); 207*4a0cb85cSEd Tanous if (auto_neg != nullptr) 208*4a0cb85cSEd Tanous { 209*4a0cb85cSEd Tanous ethData.auto_neg = *auto_neg; 210*4a0cb85cSEd Tanous } 211*4a0cb85cSEd Tanous } 212*4a0cb85cSEd Tanous else if (propertyPair.first == "Speed") 213*4a0cb85cSEd Tanous { 214*4a0cb85cSEd Tanous const uint32_t *speed = 215*4a0cb85cSEd Tanous mapbox::getPtr<const uint32_t>( 216*4a0cb85cSEd Tanous propertyPair.second); 217*4a0cb85cSEd Tanous if (speed != nullptr) 218*4a0cb85cSEd Tanous { 219*4a0cb85cSEd Tanous ethData.speed = *speed; 220*4a0cb85cSEd Tanous } 221*4a0cb85cSEd Tanous } 222*4a0cb85cSEd Tanous } 223*4a0cb85cSEd Tanous } 224*4a0cb85cSEd Tanous else if (ifacePair.first == 225*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.SystemConfiguration") 226*4a0cb85cSEd Tanous { 227*4a0cb85cSEd Tanous for (const auto &propertyPair : ifacePair.second) 228*4a0cb85cSEd Tanous { 229*4a0cb85cSEd Tanous if (propertyPair.first == "HostName") 230*4a0cb85cSEd Tanous { 231*4a0cb85cSEd Tanous const std::string *hostname = 232*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 233*4a0cb85cSEd Tanous propertyPair.second); 234*4a0cb85cSEd Tanous if (hostname != nullptr) 235*4a0cb85cSEd Tanous { 236*4a0cb85cSEd Tanous ethData.hostname = *hostname; 237*4a0cb85cSEd Tanous } 238*4a0cb85cSEd Tanous } 239*4a0cb85cSEd Tanous else if (propertyPair.first == "DefaultGateway") 240*4a0cb85cSEd Tanous { 241*4a0cb85cSEd Tanous const std::string *defaultGateway = 242*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 243*4a0cb85cSEd Tanous propertyPair.second); 244*4a0cb85cSEd Tanous if (defaultGateway != nullptr) 245*4a0cb85cSEd Tanous { 246*4a0cb85cSEd Tanous ethData.default_gateway = *defaultGateway; 247*4a0cb85cSEd Tanous } 248*4a0cb85cSEd Tanous } 249*4a0cb85cSEd Tanous } 250*4a0cb85cSEd Tanous } 251*4a0cb85cSEd Tanous } 252*4a0cb85cSEd Tanous } 253*4a0cb85cSEd Tanous } 254*4a0cb85cSEd Tanous } 255*4a0cb85cSEd Tanous 256*4a0cb85cSEd Tanous // Helper function that extracts data for single ethernet ipv4 address 257*4a0cb85cSEd Tanous inline void 258*4a0cb85cSEd Tanous extractIPData(const std::string ðiface_id, 259*4a0cb85cSEd Tanous const GetManagedObjects &dbus_data, 260*4a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> &ipv4_config) 261*4a0cb85cSEd Tanous { 262*4a0cb85cSEd Tanous const std::string ipv4PathStart = 263*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ethiface_id + "/ipv4/"; 264*4a0cb85cSEd Tanous 265*4a0cb85cSEd Tanous // Since there might be several IPv4 configurations aligned with 266*4a0cb85cSEd Tanous // single ethernet interface, loop over all of them 267*4a0cb85cSEd Tanous for (const auto &objpath : dbus_data) 268*4a0cb85cSEd Tanous { 269*4a0cb85cSEd Tanous // Check if proper pattern for object path appears 270*4a0cb85cSEd Tanous if (boost::starts_with(objpath.first.str, ipv4PathStart)) 271*4a0cb85cSEd Tanous { 272*4a0cb85cSEd Tanous for (auto &interface : objpath.second) 273*4a0cb85cSEd Tanous { 274*4a0cb85cSEd Tanous if (interface.first == "xyz.openbmc_project.Network.IP") 275*4a0cb85cSEd Tanous { 276*4a0cb85cSEd Tanous // Instance IPv4AddressData structure, and set as 277*4a0cb85cSEd Tanous // appropriate 278*4a0cb85cSEd Tanous std::pair< 279*4a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::iterator, 280*4a0cb85cSEd Tanous bool> 281*4a0cb85cSEd Tanous it = ipv4_config.insert( 282*4a0cb85cSEd Tanous {objpath.first.str.substr(ipv4PathStart.size())}); 283*4a0cb85cSEd Tanous IPv4AddressData &ipv4_address = *it.first; 284*4a0cb85cSEd Tanous for (auto &property : interface.second) 285*4a0cb85cSEd Tanous { 286*4a0cb85cSEd Tanous if (property.first == "Address") 287*4a0cb85cSEd Tanous { 288*4a0cb85cSEd Tanous const std::string *address = 289*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 290*4a0cb85cSEd Tanous property.second); 291*4a0cb85cSEd Tanous if (address != nullptr) 292*4a0cb85cSEd Tanous { 293*4a0cb85cSEd Tanous ipv4_address.address = *address; 294*4a0cb85cSEd Tanous } 295*4a0cb85cSEd Tanous } 296*4a0cb85cSEd Tanous else if (property.first == "Gateway") 297*4a0cb85cSEd Tanous { 298*4a0cb85cSEd Tanous const std::string *gateway = 299*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 300*4a0cb85cSEd Tanous property.second); 301*4a0cb85cSEd Tanous if (gateway != nullptr) 302*4a0cb85cSEd Tanous { 303*4a0cb85cSEd Tanous ipv4_address.gateway = *gateway; 304*4a0cb85cSEd Tanous } 305*4a0cb85cSEd Tanous } 306*4a0cb85cSEd Tanous else if (property.first == "Origin") 307*4a0cb85cSEd Tanous { 308*4a0cb85cSEd Tanous const std::string *origin = 309*4a0cb85cSEd Tanous mapbox::getPtr<const std::string>( 310*4a0cb85cSEd Tanous property.second); 311*4a0cb85cSEd Tanous if (origin != nullptr) 312*4a0cb85cSEd Tanous { 313*4a0cb85cSEd Tanous ipv4_address.origin = 314*4a0cb85cSEd Tanous translateAddressOriginDbusToRedfish(*origin, 315*4a0cb85cSEd Tanous true); 316*4a0cb85cSEd Tanous } 317*4a0cb85cSEd Tanous } 318*4a0cb85cSEd Tanous else if (property.first == "PrefixLength") 319*4a0cb85cSEd Tanous { 320*4a0cb85cSEd Tanous const uint8_t *mask = 321*4a0cb85cSEd Tanous mapbox::getPtr<uint8_t>(property.second); 322*4a0cb85cSEd Tanous if (mask != nullptr) 323*4a0cb85cSEd Tanous { 324*4a0cb85cSEd Tanous // convert it to the string 325*4a0cb85cSEd Tanous ipv4_address.netmask = getNetmask(*mask); 326*4a0cb85cSEd Tanous } 327*4a0cb85cSEd Tanous } 328*4a0cb85cSEd Tanous else 329*4a0cb85cSEd Tanous { 330*4a0cb85cSEd Tanous BMCWEB_LOG_ERROR 331*4a0cb85cSEd Tanous << "Got extra property: " << property.first 332*4a0cb85cSEd Tanous << " on the " << objpath.first.str << " object"; 333*4a0cb85cSEd Tanous } 334*4a0cb85cSEd Tanous } 335*4a0cb85cSEd Tanous // Check if given address is local, or global 336*4a0cb85cSEd Tanous ipv4_address.linktype = 337*4a0cb85cSEd Tanous boost::starts_with(ipv4_address.address, "169.254.") 338*4a0cb85cSEd Tanous ? LinkType::Global 339*4a0cb85cSEd Tanous : LinkType::Local; 340*4a0cb85cSEd Tanous } 341*4a0cb85cSEd Tanous } 342*4a0cb85cSEd Tanous } 343*4a0cb85cSEd Tanous } 344*4a0cb85cSEd Tanous } 345588c3f0dSKowalski, Kamil 346588c3f0dSKowalski, Kamil /** 347588c3f0dSKowalski, Kamil * @brief Sets given Id on the given VLAN interface through D-Bus 348588c3f0dSKowalski, Kamil * 349588c3f0dSKowalski, Kamil * @param[in] ifaceId Id of VLAN interface that should be modified 350588c3f0dSKowalski, Kamil * @param[in] inputVlanId New ID of the VLAN 351588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 352588c3f0dSKowalski, Kamil * 353588c3f0dSKowalski, Kamil * @return None. 354588c3f0dSKowalski, Kamil */ 355588c3f0dSKowalski, Kamil template <typename CallbackFunc> 356*4a0cb85cSEd Tanous void changeVlanId(const std::string &ifaceId, const uint32_t &inputVlanId, 3571abe55efSEd Tanous CallbackFunc &&callback) 3581abe55efSEd Tanous { 35955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 360588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 361588c3f0dSKowalski, Kamil std::string("/xyz/openbmc_project/network/") + ifaceId, 362588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 363588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.VLAN", "Id", 364588c3f0dSKowalski, Kamil sdbusplus::message::variant<uint32_t>(inputVlanId)); 365*4a0cb85cSEd Tanous } 366588c3f0dSKowalski, Kamil 367588c3f0dSKowalski, Kamil /** 368179db1d7SKowalski, Kamil * @brief Helper function that verifies IP address to check if it is in 369179db1d7SKowalski, Kamil * proper format. If bits pointer is provided, also calculates active 370179db1d7SKowalski, Kamil * bit count for Subnet Mask. 371179db1d7SKowalski, Kamil * 372179db1d7SKowalski, Kamil * @param[in] ip IP that will be verified 373179db1d7SKowalski, Kamil * @param[out] bits Calculated mask in bits notation 374179db1d7SKowalski, Kamil * 375179db1d7SKowalski, Kamil * @return true in case of success, false otherwise 376179db1d7SKowalski, Kamil */ 377*4a0cb85cSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string &ip, 3781abe55efSEd Tanous uint8_t *bits = nullptr) 3791abe55efSEd Tanous { 380179db1d7SKowalski, Kamil std::vector<std::string> bytesInMask; 381179db1d7SKowalski, Kamil 382179db1d7SKowalski, Kamil boost::split(bytesInMask, ip, boost::is_any_of(".")); 383179db1d7SKowalski, Kamil 384*4a0cb85cSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 3851abe55efSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 3861abe55efSEd Tanous { 387179db1d7SKowalski, Kamil return false; 388179db1d7SKowalski, Kamil } 389179db1d7SKowalski, Kamil 3901abe55efSEd Tanous if (bits != nullptr) 3911abe55efSEd Tanous { 392179db1d7SKowalski, Kamil *bits = 0; 393179db1d7SKowalski, Kamil } 394179db1d7SKowalski, Kamil 395179db1d7SKowalski, Kamil char *endPtr; 396179db1d7SKowalski, Kamil long previousValue = 255; 397179db1d7SKowalski, Kamil bool firstZeroInByteHit; 3981abe55efSEd Tanous for (const std::string &byte : bytesInMask) 3991abe55efSEd Tanous { 4001abe55efSEd Tanous if (byte.empty()) 4011abe55efSEd Tanous { 4021db9ca37SKowalski, Kamil return false; 4031db9ca37SKowalski, Kamil } 4041db9ca37SKowalski, Kamil 405179db1d7SKowalski, Kamil // Use strtol instead of stroi to avoid exceptions 4061db9ca37SKowalski, Kamil long value = std::strtol(byte.c_str(), &endPtr, 10); 407179db1d7SKowalski, Kamil 408*4a0cb85cSEd Tanous // endPtr should point to the end of the string, otherwise given string 409*4a0cb85cSEd Tanous // is not 100% number 4101abe55efSEd Tanous if (*endPtr != '\0') 4111abe55efSEd Tanous { 412179db1d7SKowalski, Kamil return false; 413179db1d7SKowalski, Kamil } 414179db1d7SKowalski, Kamil 415179db1d7SKowalski, Kamil // Value should be contained in byte 4161abe55efSEd Tanous if (value < 0 || value > 255) 4171abe55efSEd Tanous { 418179db1d7SKowalski, Kamil return false; 419179db1d7SKowalski, Kamil } 420179db1d7SKowalski, Kamil 4211abe55efSEd Tanous if (bits != nullptr) 4221abe55efSEd Tanous { 423179db1d7SKowalski, Kamil // Mask has to be continuous between bytes 4241abe55efSEd Tanous if (previousValue != 255 && value != 0) 4251abe55efSEd Tanous { 426179db1d7SKowalski, Kamil return false; 427179db1d7SKowalski, Kamil } 428179db1d7SKowalski, Kamil 429179db1d7SKowalski, Kamil // Mask has to be continuous inside bytes 430179db1d7SKowalski, Kamil firstZeroInByteHit = false; 431179db1d7SKowalski, Kamil 432179db1d7SKowalski, Kamil // Count bits 4331abe55efSEd Tanous for (int bitIdx = 7; bitIdx >= 0; bitIdx--) 4341abe55efSEd Tanous { 4351abe55efSEd Tanous if (value & (1 << bitIdx)) 4361abe55efSEd Tanous { 4371abe55efSEd Tanous if (firstZeroInByteHit) 4381abe55efSEd Tanous { 439179db1d7SKowalski, Kamil // Continuity not preserved 440179db1d7SKowalski, Kamil return false; 4411abe55efSEd Tanous } 4421abe55efSEd Tanous else 4431abe55efSEd Tanous { 444179db1d7SKowalski, Kamil (*bits)++; 445179db1d7SKowalski, Kamil } 4461abe55efSEd Tanous } 4471abe55efSEd Tanous else 4481abe55efSEd Tanous { 449179db1d7SKowalski, Kamil firstZeroInByteHit = true; 450179db1d7SKowalski, Kamil } 451179db1d7SKowalski, Kamil } 452179db1d7SKowalski, Kamil } 453179db1d7SKowalski, Kamil 454179db1d7SKowalski, Kamil previousValue = value; 455179db1d7SKowalski, Kamil } 456179db1d7SKowalski, Kamil 457179db1d7SKowalski, Kamil return true; 458179db1d7SKowalski, Kamil } 459179db1d7SKowalski, Kamil 460179db1d7SKowalski, Kamil /** 461179db1d7SKowalski, Kamil * @brief Changes IPv4 address type property (Address, Gateway) 462179db1d7SKowalski, Kamil * 463179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 464*4a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be modified 465179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 466179db1d7SKowalski, Kamil * @param[in] name Name of field in JSON representation 467179db1d7SKowalski, Kamil * @param[in] newValue New value that should be written 468179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 469179db1d7SKowalski, Kamil * 470179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 471179db1d7SKowalski, Kamil * otherwise 472179db1d7SKowalski, Kamil */ 473*4a0cb85cSEd Tanous inline void changeIPv4AddressProperty( 474*4a0cb85cSEd Tanous const std::string &ifaceId, int ipIdx, const std::string &ipHash, 475*4a0cb85cSEd Tanous const std::string &name, const std::string &newValue, 476*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 4771abe55efSEd Tanous { 478*4a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, name{std::string(name)}, 479*4a0cb85cSEd Tanous newValue{std::move(newValue)}]( 4801abe55efSEd Tanous const boost::system::error_code ec) { 4811abe55efSEd Tanous if (ec) 4821abe55efSEd Tanous { 483179db1d7SKowalski, Kamil messages::addMessageToJson( 48455c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 485179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name); 4861abe55efSEd Tanous } 4871abe55efSEd Tanous else 4881abe55efSEd Tanous { 489*4a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue; 490179db1d7SKowalski, Kamil } 491179db1d7SKowalski, Kamil }; 492179db1d7SKowalski, Kamil 49355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 494179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 495179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 496179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 497179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", name, 498179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValue)); 499*4a0cb85cSEd Tanous } 500179db1d7SKowalski, Kamil 501179db1d7SKowalski, Kamil /** 502179db1d7SKowalski, Kamil * @brief Changes IPv4 address origin property 503179db1d7SKowalski, Kamil * 504179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 505*4a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5061abe55efSEd Tanous * modified 507179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 508179db1d7SKowalski, Kamil * @param[in] newValue New value in Redfish format 509179db1d7SKowalski, Kamil * @param[in] newValueDbus New value in D-Bus format 510179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 511179db1d7SKowalski, Kamil * 512179db1d7SKowalski, Kamil * @return true if give IP is valid and has been sent do D-Bus, false 513179db1d7SKowalski, Kamil * otherwise 514179db1d7SKowalski, Kamil */ 515*4a0cb85cSEd Tanous inline void changeIPv4Origin(const std::string &ifaceId, int ipIdx, 5161abe55efSEd Tanous const std::string &ipHash, 5171abe55efSEd Tanous const std::string &newValue, 518179db1d7SKowalski, Kamil const std::string &newValueDbus, 519*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 5201abe55efSEd Tanous { 521*4a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValue{std::move(newValue)}]( 5221abe55efSEd Tanous const boost::system::error_code ec) { 5231abe55efSEd Tanous if (ec) 5241abe55efSEd Tanous { 525179db1d7SKowalski, Kamil messages::addMessageToJson( 52655c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 527*4a0cb85cSEd Tanous "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin"); 5281abe55efSEd Tanous } 5291abe55efSEd Tanous else 5301abe55efSEd Tanous { 531*4a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] = 532179db1d7SKowalski, Kamil newValue; 533179db1d7SKowalski, Kamil } 534179db1d7SKowalski, Kamil }; 535179db1d7SKowalski, Kamil 53655c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 537179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 538179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 539179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 540179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "Origin", 541179db1d7SKowalski, Kamil sdbusplus::message::variant<std::string>(newValueDbus)); 542*4a0cb85cSEd Tanous } 543179db1d7SKowalski, Kamil 544179db1d7SKowalski, Kamil /** 545179db1d7SKowalski, Kamil * @brief Modifies SubnetMask for given IP 546179db1d7SKowalski, Kamil * 547179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be modified 548*4a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be 5491abe55efSEd Tanous * modified 550179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of modified IP 551179db1d7SKowalski, Kamil * @param[in] newValueStr Mask in dot notation as string 552179db1d7SKowalski, Kamil * @param[in] newValue Mask as PrefixLength in bitcount 553179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 554179db1d7SKowalski, Kamil * 555179db1d7SKowalski, Kamil * @return None 556179db1d7SKowalski, Kamil */ 557*4a0cb85cSEd Tanous inline void changeIPv4SubnetMaskProperty(const std::string &ifaceId, int ipIdx, 558*4a0cb85cSEd Tanous const std::string &ipHash, 559*4a0cb85cSEd Tanous const std::string &newValueStr, 560*4a0cb85cSEd Tanous uint8_t &newValue, 561*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 5621abe55efSEd Tanous { 563*4a0cb85cSEd Tanous auto callback = [asyncResp, ipIdx, newValueStr{std::move(newValueStr)}]( 5641abe55efSEd Tanous const boost::system::error_code ec) { 5651abe55efSEd Tanous if (ec) 5661abe55efSEd Tanous { 567179db1d7SKowalski, Kamil messages::addMessageToJson( 56855c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 569179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask"); 5701abe55efSEd Tanous } 5711abe55efSEd Tanous else 5721abe55efSEd Tanous { 57355c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] = 574179db1d7SKowalski, Kamil newValueStr; 575179db1d7SKowalski, Kamil } 576179db1d7SKowalski, Kamil }; 577179db1d7SKowalski, Kamil 57855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 579179db1d7SKowalski, Kamil std::move(callback), "xyz.openbmc_project.Network", 580179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 581179db1d7SKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 582179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP", "PrefixLength", 583179db1d7SKowalski, Kamil sdbusplus::message::variant<uint8_t>(newValue)); 584*4a0cb85cSEd Tanous } 585588c3f0dSKowalski, Kamil 586588c3f0dSKowalski, Kamil /** 587588c3f0dSKowalski, Kamil * @brief Sets given HostName of the machine through D-Bus 588588c3f0dSKowalski, Kamil * 589588c3f0dSKowalski, Kamil * @param[in] newHostname New name that HostName will be changed to 590588c3f0dSKowalski, Kamil * @param[in] callback Function that will be called after the operation 591588c3f0dSKowalski, Kamil * 592588c3f0dSKowalski, Kamil * @return None. 593588c3f0dSKowalski, Kamil */ 594588c3f0dSKowalski, Kamil template <typename CallbackFunc> 5951abe55efSEd Tanous void setHostName(const std::string &newHostname, CallbackFunc &&callback) 5961abe55efSEd Tanous { 59755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 598588c3f0dSKowalski, Kamil callback, "xyz.openbmc_project.Network", 599588c3f0dSKowalski, Kamil "/xyz/openbmc_project/network/config", 600588c3f0dSKowalski, Kamil "org.freedesktop.DBus.Properties", "Set", 601588c3f0dSKowalski, Kamil "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 602588c3f0dSKowalski, Kamil sdbusplus::message::variant<std::string>(newHostname)); 603*4a0cb85cSEd Tanous } 604588c3f0dSKowalski, Kamil 605588c3f0dSKowalski, Kamil /** 606179db1d7SKowalski, Kamil * @brief Deletes given IPv4 607179db1d7SKowalski, Kamil * 608179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 609*4a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 610179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 611179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 612179db1d7SKowalski, Kamil * 613179db1d7SKowalski, Kamil * @return None 614179db1d7SKowalski, Kamil */ 615*4a0cb85cSEd Tanous inline void deleteIPv4(const std::string &ifaceId, const std::string &ipHash, 616179db1d7SKowalski, Kamil unsigned int ipIdx, 617*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 6181abe55efSEd Tanous { 61955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 620*4a0cb85cSEd Tanous [ipIdx, asyncResp](const boost::system::error_code ec) { 6211abe55efSEd Tanous if (ec) 6221abe55efSEd Tanous { 623179db1d7SKowalski, Kamil messages::addMessageToJson( 62455c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 625179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 6261abe55efSEd Tanous } 6271abe55efSEd Tanous else 6281abe55efSEd Tanous { 62955c7b7a2SEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr; 630179db1d7SKowalski, Kamil } 631179db1d7SKowalski, Kamil }, 632179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", 633179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash, 634179db1d7SKowalski, Kamil "xyz.openbmc_project.Object.Delete", "Delete"); 635179db1d7SKowalski, Kamil } 636179db1d7SKowalski, Kamil 637179db1d7SKowalski, Kamil /** 638179db1d7SKowalski, Kamil * @brief Creates IPv4 with given data 639179db1d7SKowalski, Kamil * 640179db1d7SKowalski, Kamil * @param[in] ifaceId Id of interface whose IP should be deleted 641*4a0cb85cSEd Tanous * @param[in] ipIdx Index of IP in input array that should be deleted 642179db1d7SKowalski, Kamil * @param[in] ipHash DBus Hash id of IP that should be deleted 643179db1d7SKowalski, Kamil * @param[io] asyncResp Response object that will be returned to client 644179db1d7SKowalski, Kamil * 645179db1d7SKowalski, Kamil * @return None 646179db1d7SKowalski, Kamil */ 647*4a0cb85cSEd Tanous inline void createIPv4(const std::string &ifaceId, unsigned int ipIdx, 648179db1d7SKowalski, Kamil uint8_t subnetMask, const std::string &gateway, 649179db1d7SKowalski, Kamil const std::string &address, 650*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp) 6511abe55efSEd Tanous { 652*4a0cb85cSEd Tanous auto createIpHandler = [ipIdx, 653*4a0cb85cSEd Tanous asyncResp](const boost::system::error_code ec) { 6541abe55efSEd Tanous if (ec) 6551abe55efSEd Tanous { 656179db1d7SKowalski, Kamil messages::addMessageToJson( 65755c7b7a2SEd Tanous asyncResp->res.jsonValue, messages::internalError(), 658179db1d7SKowalski, Kamil "/IPv4Addresses/" + std::to_string(ipIdx) + "/"); 659179db1d7SKowalski, Kamil } 660179db1d7SKowalski, Kamil }; 661179db1d7SKowalski, Kamil 66255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 663179db1d7SKowalski, Kamil std::move(createIpHandler), "xyz.openbmc_project.Network", 664179db1d7SKowalski, Kamil "/xyz/openbmc_project/network/" + ifaceId, 665179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Create", "IP", 666179db1d7SKowalski, Kamil "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask, 667179db1d7SKowalski, Kamil gateway); 668179db1d7SKowalski, Kamil } 669179db1d7SKowalski, Kamil 670179db1d7SKowalski, Kamil /** 671179db1d7SKowalski, Kamil * Function that retrieves all properties for given Ethernet Interface 672179db1d7SKowalski, Kamil * Object 673179db1d7SKowalski, Kamil * from EntityManager Network Manager 674*4a0cb85cSEd Tanous * @param ethiface_id a eth interface id to query on DBus 675179db1d7SKowalski, Kamil * @param callback a function that shall be called to convert Dbus output 676179db1d7SKowalski, Kamil * into JSON 677179db1d7SKowalski, Kamil */ 678179db1d7SKowalski, Kamil template <typename CallbackFunc> 679*4a0cb85cSEd Tanous void getEthernetIfaceData(const std::string ðiface_id, 6801abe55efSEd Tanous CallbackFunc &&callback) 6811abe55efSEd Tanous { 68255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 683*4a0cb85cSEd Tanous [ethiface_id{std::string{ethiface_id}}, callback{std::move(callback)}]( 6841abe55efSEd Tanous const boost::system::error_code error_code, 685*4a0cb85cSEd Tanous const GetManagedObjects &resp) { 68655c7b7a2SEd Tanous EthernetInterfaceData ethData{}; 687*4a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData> ipv4Data; 688179db1d7SKowalski, Kamil 6891abe55efSEd Tanous if (error_code) 6901abe55efSEd Tanous { 69155c7b7a2SEd Tanous callback(false, ethData, ipv4Data); 692179db1d7SKowalski, Kamil return; 693179db1d7SKowalski, Kamil } 694179db1d7SKowalski, Kamil 695*4a0cb85cSEd Tanous extractEthernetInterfaceData(ethiface_id, resp, ethData); 696*4a0cb85cSEd Tanous extractIPData(ethiface_id, resp, ipv4Data); 697179db1d7SKowalski, Kamil 698179db1d7SKowalski, Kamil // Fix global GW 6991abe55efSEd Tanous for (IPv4AddressData &ipv4 : ipv4Data) 7001abe55efSEd Tanous { 701*4a0cb85cSEd Tanous if ((ipv4.linktype == LinkType::Global) && 702*4a0cb85cSEd Tanous (ipv4.gateway == "0.0.0.0")) 7031abe55efSEd Tanous { 704*4a0cb85cSEd Tanous ipv4.gateway = ethData.default_gateway; 705179db1d7SKowalski, Kamil } 706179db1d7SKowalski, Kamil } 707179db1d7SKowalski, Kamil 708*4a0cb85cSEd Tanous // Finally make a callback with usefull data 70955c7b7a2SEd Tanous callback(true, ethData, ipv4Data); 710179db1d7SKowalski, Kamil }, 711179db1d7SKowalski, Kamil "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 712179db1d7SKowalski, Kamil "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 713179db1d7SKowalski, Kamil }; 714179db1d7SKowalski, Kamil 715179db1d7SKowalski, Kamil /** 7169391bb9cSRapkiewicz, Pawel * Function that retrieves all Ethernet Interfaces available through Network 7179391bb9cSRapkiewicz, Pawel * Manager 7181abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 7191abe55efSEd Tanous * into JSON. 7209391bb9cSRapkiewicz, Pawel */ 7219391bb9cSRapkiewicz, Pawel template <typename CallbackFunc> 7221abe55efSEd Tanous void getEthernetIfaceList(CallbackFunc &&callback) 7231abe55efSEd Tanous { 72455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 725*4a0cb85cSEd Tanous [callback{std::move(callback)}]( 7269391bb9cSRapkiewicz, Pawel const boost::system::error_code error_code, 727*4a0cb85cSEd Tanous GetManagedObjects &resp) { 7281abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 7291abe55efSEd Tanous // ethernet interfaces 730*4a0cb85cSEd Tanous std::vector<std::string> iface_list; 731*4a0cb85cSEd Tanous iface_list.reserve(resp.size()); 7321abe55efSEd Tanous if (error_code) 7331abe55efSEd Tanous { 734*4a0cb85cSEd Tanous callback(false, iface_list); 7359391bb9cSRapkiewicz, Pawel return; 7369391bb9cSRapkiewicz, Pawel } 7379391bb9cSRapkiewicz, Pawel 7389391bb9cSRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 739*4a0cb85cSEd Tanous for (const auto &objpath : resp) 7401abe55efSEd Tanous { 7419391bb9cSRapkiewicz, Pawel // And all interfaces available for certain ObjectPath. 742*4a0cb85cSEd Tanous for (const auto &interface : objpath.second) 7431abe55efSEd Tanous { 7441abe55efSEd Tanous // If interface is 745*4a0cb85cSEd Tanous // xyz.openbmc_project.Network.EthernetInterface, this is 746*4a0cb85cSEd Tanous // what we're looking for. 7479391bb9cSRapkiewicz, Pawel if (interface.first == 7481abe55efSEd Tanous "xyz.openbmc_project.Network.EthernetInterface") 7491abe55efSEd Tanous { 750*4a0cb85cSEd Tanous // Cut out everyting until last "/", ... 751*4a0cb85cSEd Tanous const std::string &iface_id = objpath.first.str; 752*4a0cb85cSEd Tanous std::size_t last_pos = iface_id.rfind("/"); 753*4a0cb85cSEd Tanous if (last_pos != std::string::npos) 7541abe55efSEd Tanous { 7559391bb9cSRapkiewicz, Pawel // and put it into output vector. 756*4a0cb85cSEd Tanous iface_list.emplace_back( 757*4a0cb85cSEd Tanous iface_id.substr(last_pos + 1)); 7589391bb9cSRapkiewicz, Pawel } 7599391bb9cSRapkiewicz, Pawel } 7609391bb9cSRapkiewicz, Pawel } 7619391bb9cSRapkiewicz, Pawel } 762a434f2bdSEd Tanous // Finally make a callback with useful data 763*4a0cb85cSEd Tanous callback(true, iface_list); 7649391bb9cSRapkiewicz, Pawel }, 765aa2e59c1SEd Tanous "xyz.openbmc_project.Network", "/xyz/openbmc_project/network", 766aa2e59c1SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7679391bb9cSRapkiewicz, Pawel }; 7689391bb9cSRapkiewicz, Pawel 7699391bb9cSRapkiewicz, Pawel /** 7709391bb9cSRapkiewicz, Pawel * EthernetCollection derived class for delivering Ethernet Collection Schema 7719391bb9cSRapkiewicz, Pawel */ 7721abe55efSEd Tanous class EthernetCollection : public Node 7731abe55efSEd Tanous { 7749391bb9cSRapkiewicz, Pawel public: 775*4a0cb85cSEd Tanous template <typename CrowApp> 7761abe55efSEd Tanous EthernetCollection(CrowApp &app) : 777*4a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") 7781abe55efSEd Tanous { 7799391bb9cSRapkiewicz, Pawel Node::json["@odata.type"] = 7809391bb9cSRapkiewicz, Pawel "#EthernetInterfaceCollection.EthernetInterfaceCollection"; 7819391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 7829391bb9cSRapkiewicz, Pawel "/redfish/v1/" 7839391bb9cSRapkiewicz, Pawel "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection"; 784*4a0cb85cSEd Tanous Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces"; 7859391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Ethernet Network Interface Collection"; 7869391bb9cSRapkiewicz, Pawel Node::json["Description"] = 7879391bb9cSRapkiewicz, Pawel "Collection of EthernetInterfaces for this Manager"; 7889391bb9cSRapkiewicz, Pawel 789588c3f0dSKowalski, Kamil entityPrivileges = { 790588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 791e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 792e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 793e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 794e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 795e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 7969391bb9cSRapkiewicz, Pawel } 7979391bb9cSRapkiewicz, Pawel 7989391bb9cSRapkiewicz, Pawel private: 7999391bb9cSRapkiewicz, Pawel /** 8009391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 8019391bb9cSRapkiewicz, Pawel */ 80255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 8031abe55efSEd Tanous const std::vector<std::string> ¶ms) override 8041abe55efSEd Tanous { 805*4a0cb85cSEd Tanous res.jsonValue = Node::json; 806*4a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 8071abe55efSEd Tanous // preparation 808*4a0cb85cSEd Tanous getEthernetIfaceList([&res]( 8091abe55efSEd Tanous const bool &success, 8101abe55efSEd Tanous const std::vector<std::string> &iface_list) { 811*4a0cb85cSEd Tanous if (!success) 8121abe55efSEd Tanous { 813*4a0cb85cSEd Tanous res.result(boost::beast::http::status::internal_server_error); 814*4a0cb85cSEd Tanous res.end(); 815*4a0cb85cSEd Tanous return; 816*4a0cb85cSEd Tanous } 817*4a0cb85cSEd Tanous 818*4a0cb85cSEd Tanous nlohmann::json &iface_array = res.jsonValue["Members"]; 819*4a0cb85cSEd Tanous iface_array = nlohmann::json::array(); 820*4a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 8211abe55efSEd Tanous { 822*4a0cb85cSEd Tanous iface_array.push_back( 823*4a0cb85cSEd Tanous {{"@odata.id", 824*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 825*4a0cb85cSEd Tanous iface_item}}); 8269391bb9cSRapkiewicz, Pawel } 827*4a0cb85cSEd Tanous 828*4a0cb85cSEd Tanous res.jsonValue["Members@odata.count"] = iface_array.size(); 829*4a0cb85cSEd Tanous res.jsonValue["@odata.id"] = 830*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces"; 8319391bb9cSRapkiewicz, Pawel res.end(); 8329391bb9cSRapkiewicz, Pawel }); 8339391bb9cSRapkiewicz, Pawel } 8349391bb9cSRapkiewicz, Pawel }; 8359391bb9cSRapkiewicz, Pawel 8369391bb9cSRapkiewicz, Pawel /** 8379391bb9cSRapkiewicz, Pawel * EthernetInterface derived class for delivering Ethernet Schema 8389391bb9cSRapkiewicz, Pawel */ 8391abe55efSEd Tanous class EthernetInterface : public Node 8401abe55efSEd Tanous { 8419391bb9cSRapkiewicz, Pawel public: 8429391bb9cSRapkiewicz, Pawel /* 8439391bb9cSRapkiewicz, Pawel * Default Constructor 8449391bb9cSRapkiewicz, Pawel */ 845*4a0cb85cSEd Tanous template <typename CrowApp> 8461abe55efSEd Tanous EthernetInterface(CrowApp &app) : 847*4a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", 8481abe55efSEd Tanous std::string()) 8491abe55efSEd Tanous { 8501abe55efSEd Tanous Node::json["@odata.type"] = 8511abe55efSEd Tanous "#EthernetInterface.v1_2_0.EthernetInterface"; 8529391bb9cSRapkiewicz, Pawel Node::json["@odata.context"] = 8539391bb9cSRapkiewicz, Pawel "/redfish/v1/$metadata#EthernetInterface.EthernetInterface"; 8549391bb9cSRapkiewicz, Pawel Node::json["Name"] = "Manager Ethernet Interface"; 8559391bb9cSRapkiewicz, Pawel Node::json["Description"] = "Management Network Interface"; 8569391bb9cSRapkiewicz, Pawel 857588c3f0dSKowalski, Kamil entityPrivileges = { 858588c3f0dSKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 859e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 860e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 861e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 862e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 863e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 8649391bb9cSRapkiewicz, Pawel } 8659391bb9cSRapkiewicz, Pawel 866e439f0f8SKowalski, Kamil // TODO(kkowalsk) Find a suitable class/namespace for this 867e439f0f8SKowalski, Kamil static void handleVlanPatch(const std::string &ifaceId, 868e439f0f8SKowalski, Kamil const nlohmann::json &input, 869*4a0cb85cSEd Tanous const EthernetInterfaceData ðData, 870*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 8711abe55efSEd Tanous { 8721abe55efSEd Tanous if (!input.is_object()) 8731abe55efSEd Tanous { 874588c3f0dSKowalski, Kamil messages::addMessageToJson( 87555c7b7a2SEd Tanous asyncResp->res.jsonValue, 876*4a0cb85cSEd Tanous messages::propertyValueTypeError(input.dump(), "VLAN"), "/"); 877588c3f0dSKowalski, Kamil return; 878588c3f0dSKowalski, Kamil } 879588c3f0dSKowalski, Kamil 880*4a0cb85cSEd Tanous nlohmann::json::const_iterator vlanEnable = input.find("VLANEnable"); 881*4a0cb85cSEd Tanous if (vlanEnable == input.end()) 8821abe55efSEd Tanous { 883*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 884*4a0cb85cSEd Tanous messages::propertyMissing("VLANEnable"), 885*4a0cb85cSEd Tanous "/VLANEnable"); 886*4a0cb85cSEd Tanous return; 887*4a0cb85cSEd Tanous } 888*4a0cb85cSEd Tanous const bool *vlanEnableBool = vlanEnable->get_ptr<const bool *>(); 889*4a0cb85cSEd Tanous if (vlanEnableBool == nullptr) 890*4a0cb85cSEd Tanous { 891*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 892*4a0cb85cSEd Tanous messages::propertyValueTypeError( 893*4a0cb85cSEd Tanous vlanEnable->dump(), "VLANEnable"), 894*4a0cb85cSEd Tanous "/VLANEnable"); 895588c3f0dSKowalski, Kamil return; 896588c3f0dSKowalski, Kamil } 897588c3f0dSKowalski, Kamil 898*4a0cb85cSEd Tanous nlohmann::json::const_iterator vlanId = input.find("VLANId"); 899*4a0cb85cSEd Tanous if (vlanId == input.end()) 900*4a0cb85cSEd Tanous { 901*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 902*4a0cb85cSEd Tanous messages::propertyMissing("VLANId"), 903*4a0cb85cSEd Tanous "/VLANId"); 904*4a0cb85cSEd Tanous return; 905*4a0cb85cSEd Tanous } 906*4a0cb85cSEd Tanous const uint64_t *vlanIdUint = vlanId->get_ptr<const uint64_t *>(); 907*4a0cb85cSEd Tanous if (vlanIdUint == nullptr) 908*4a0cb85cSEd Tanous { 909*4a0cb85cSEd Tanous messages::addMessageToJson( 910*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 911*4a0cb85cSEd Tanous messages::propertyValueTypeError(vlanId->dump(), "VLANId"), 912*4a0cb85cSEd Tanous "/VLANId"); 913*4a0cb85cSEd Tanous return; 914*4a0cb85cSEd Tanous } 915*4a0cb85cSEd Tanous 916*4a0cb85cSEd Tanous if (!ethData.vlan_id) 9171abe55efSEd Tanous { 918e439f0f8SKowalski, Kamil // This interface is not a VLAN. Cannot do anything with it 919e439f0f8SKowalski, Kamil // TODO(kkowalsk) Change this message 920*4a0cb85cSEd Tanous messages::addMessageToJson( 921*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 922*4a0cb85cSEd Tanous messages::propertyNotWritable("VLANEnable"), "/VLANEnable"); 923588c3f0dSKowalski, Kamil 924588c3f0dSKowalski, Kamil return; 925588c3f0dSKowalski, Kamil } 926588c3f0dSKowalski, Kamil 927588c3f0dSKowalski, Kamil // VLAN is configured on the interface 928*4a0cb85cSEd Tanous if (*vlanEnableBool == true) 9291abe55efSEd Tanous { 930588c3f0dSKowalski, Kamil // Change VLAN Id 931*4a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANId"] = *vlanIdUint; 932*4a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9331abe55efSEd Tanous if (ec) 9341abe55efSEd Tanous { 93555c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 936*4a0cb85cSEd Tanous messages::internalError(), "/"); 9371abe55efSEd Tanous } 9381abe55efSEd Tanous else 9391abe55efSEd Tanous { 940*4a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = true; 941e439f0f8SKowalski, Kamil } 942*4a0cb85cSEd Tanous }; 943*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 944*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 945*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 946*4a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 947*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN", "Id", 948*4a0cb85cSEd Tanous sdbusplus::message::variant<uint32_t>(*vlanIdUint)); 9491abe55efSEd Tanous } 950*4a0cb85cSEd Tanous else 9511abe55efSEd Tanous { 952*4a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 9531abe55efSEd Tanous if (ec) 9541abe55efSEd Tanous { 95555c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 956*4a0cb85cSEd Tanous messages::internalError(), "/"); 957*4a0cb85cSEd Tanous return; 9581abe55efSEd Tanous } 959*4a0cb85cSEd Tanous asyncResp->res.jsonValue["VLANEnable"] = false; 960*4a0cb85cSEd Tanous }; 961*4a0cb85cSEd Tanous 962*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 963*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 964*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId, 965*4a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 966588c3f0dSKowalski, Kamil } 967588c3f0dSKowalski, Kamil } 968588c3f0dSKowalski, Kamil 969e439f0f8SKowalski, Kamil private: 970588c3f0dSKowalski, Kamil void handleHostnamePatch(const nlohmann::json &input, 971*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 9721abe55efSEd Tanous { 973*4a0cb85cSEd Tanous const std::string *newHostname = input.get_ptr<const std::string *>(); 974*4a0cb85cSEd Tanous if (newHostname == nullptr) 9751abe55efSEd Tanous { 9761abe55efSEd Tanous messages::addMessageToJson( 9771abe55efSEd Tanous asyncResp->res.jsonValue, 978*4a0cb85cSEd Tanous messages::propertyValueTypeError(input.dump(), "HostName"), 979*4a0cb85cSEd Tanous "/HostName"); 980*4a0cb85cSEd Tanous return; 981*4a0cb85cSEd Tanous } 982*4a0cb85cSEd Tanous 983*4a0cb85cSEd Tanous // Change hostname 984*4a0cb85cSEd Tanous setHostName( 985*4a0cb85cSEd Tanous *newHostname, [asyncResp, newHostname{std::string(*newHostname)}]( 986*4a0cb85cSEd Tanous const boost::system::error_code ec) { 987*4a0cb85cSEd Tanous if (ec) 988*4a0cb85cSEd Tanous { 989*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 990*4a0cb85cSEd Tanous messages::internalError(), 991*4a0cb85cSEd Tanous "/HostName"); 9921abe55efSEd Tanous } 9931abe55efSEd Tanous else 9941abe55efSEd Tanous { 99555c7b7a2SEd Tanous asyncResp->res.jsonValue["HostName"] = newHostname; 996588c3f0dSKowalski, Kamil } 997588c3f0dSKowalski, Kamil }); 998588c3f0dSKowalski, Kamil } 999588c3f0dSKowalski, Kamil 1000*4a0cb85cSEd Tanous void handleIPv4Patch( 1001*4a0cb85cSEd Tanous const std::string &ifaceId, const nlohmann::json &input, 1002*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data, 1003*4a0cb85cSEd Tanous const std::shared_ptr<AsyncResp> asyncResp) 10041abe55efSEd Tanous { 10051abe55efSEd Tanous if (!input.is_array()) 10061abe55efSEd Tanous { 1007179db1d7SKowalski, Kamil messages::addMessageToJson( 100855c7b7a2SEd Tanous asyncResp->res.jsonValue, 1009179db1d7SKowalski, Kamil messages::propertyValueTypeError(input.dump(), "IPv4Addresses"), 1010179db1d7SKowalski, Kamil "/IPv4Addresses"); 1011179db1d7SKowalski, Kamil return; 1012179db1d7SKowalski, Kamil } 1013179db1d7SKowalski, Kamil 1014179db1d7SKowalski, Kamil // According to Redfish PATCH definition, size must be at least equal 1015*4a0cb85cSEd Tanous if (input.size() < ipv4Data.size()) 10161abe55efSEd Tanous { 10171abe55efSEd Tanous // TODO(kkowalsk) This should be a message indicating that not 10181abe55efSEd Tanous // enough data has been provided 101955c7b7a2SEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 10201abe55efSEd Tanous messages::internalError(), 10211abe55efSEd Tanous "/IPv4Addresses"); 1022179db1d7SKowalski, Kamil return; 1023179db1d7SKowalski, Kamil } 1024179db1d7SKowalski, Kamil 1025*4a0cb85cSEd Tanous int entryIdx = 0; 1026*4a0cb85cSEd Tanous boost::container::flat_set<IPv4AddressData>::const_iterator thisData = 1027*4a0cb85cSEd Tanous ipv4Data.begin(); 1028*4a0cb85cSEd Tanous for (const nlohmann::json &thisJson : input) 10291abe55efSEd Tanous { 1030*4a0cb85cSEd Tanous std::string pathString = 1031*4a0cb85cSEd Tanous "/IPv4Addresses/" + std::to_string(entryIdx); 1032179db1d7SKowalski, Kamil // Check that entry is not of some unexpected type 1033*4a0cb85cSEd Tanous if (!thisJson.is_object() && !thisJson.is_null()) 10341abe55efSEd Tanous { 1035*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1036*4a0cb85cSEd Tanous messages::propertyValueTypeError( 1037*4a0cb85cSEd Tanous thisJson.dump(), "IPv4Address"), 1038*4a0cb85cSEd Tanous pathString); 1039179db1d7SKowalski, Kamil 1040179db1d7SKowalski, Kamil continue; 1041179db1d7SKowalski, Kamil } 1042179db1d7SKowalski, Kamil 1043*4a0cb85cSEd Tanous nlohmann::json::const_iterator addressFieldIt = 1044*4a0cb85cSEd Tanous thisJson.find("Address"); 1045*4a0cb85cSEd Tanous const std::string *addressField = nullptr; 1046*4a0cb85cSEd Tanous if (addressFieldIt != thisJson.end()) 10471abe55efSEd Tanous { 1048*4a0cb85cSEd Tanous addressField = addressFieldIt->get_ptr<const std::string *>(); 1049*4a0cb85cSEd Tanous if (addressField == nullptr) 10501abe55efSEd Tanous { 1051179db1d7SKowalski, Kamil messages::addMessageToJson( 105255c7b7a2SEd Tanous asyncResp->res.jsonValue, 1053*4a0cb85cSEd Tanous messages::propertyValueFormatError( 1054*4a0cb85cSEd Tanous addressFieldIt->dump(), "Address"), 1055*4a0cb85cSEd Tanous pathString + "/Address"); 1056179db1d7SKowalski, Kamil continue; 1057179db1d7SKowalski, Kamil } 10581abe55efSEd Tanous else 10591abe55efSEd Tanous { 1060*4a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*addressField)) 1061*4a0cb85cSEd Tanous { 1062*4a0cb85cSEd Tanous messages::addMessageToJson( 1063*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1064*4a0cb85cSEd Tanous messages::propertyValueFormatError(*addressField, 1065*4a0cb85cSEd Tanous "Address"), 1066*4a0cb85cSEd Tanous pathString + "/Address"); 1067*4a0cb85cSEd Tanous continue; 1068*4a0cb85cSEd Tanous } 1069*4a0cb85cSEd Tanous } 1070*4a0cb85cSEd Tanous } 1071*4a0cb85cSEd Tanous 1072*4a0cb85cSEd Tanous boost::optional<uint8_t> prefixLength; 1073*4a0cb85cSEd Tanous const std::string *subnetField = nullptr; 1074*4a0cb85cSEd Tanous nlohmann::json::const_iterator subnetFieldIt = 1075*4a0cb85cSEd Tanous thisJson.find("SubnetMask"); 1076*4a0cb85cSEd Tanous if (subnetFieldIt != thisJson.end()) 1077*4a0cb85cSEd Tanous { 1078*4a0cb85cSEd Tanous subnetField = subnetFieldIt->get_ptr<const std::string *>(); 1079*4a0cb85cSEd Tanous if (subnetField == nullptr) 1080*4a0cb85cSEd Tanous { 1081*4a0cb85cSEd Tanous messages::addMessageToJson( 1082*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1083*4a0cb85cSEd Tanous messages::propertyValueFormatError(*subnetField, 1084*4a0cb85cSEd Tanous "SubnetMask"), 1085*4a0cb85cSEd Tanous pathString + "/SubnetMask"); 1086*4a0cb85cSEd Tanous continue; 1087*4a0cb85cSEd Tanous } 1088*4a0cb85cSEd Tanous else 1089*4a0cb85cSEd Tanous { 1090*4a0cb85cSEd Tanous prefixLength = 0; 1091*4a0cb85cSEd Tanous if (!ipv4VerifyIpAndGetBitcount(*subnetField, 1092*4a0cb85cSEd Tanous &*prefixLength)) 1093*4a0cb85cSEd Tanous { 1094*4a0cb85cSEd Tanous messages::addMessageToJson( 1095*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1096*4a0cb85cSEd Tanous messages::propertyValueFormatError(*subnetField, 1097*4a0cb85cSEd Tanous "SubnetMask"), 1098*4a0cb85cSEd Tanous pathString + "/SubnetMask"); 1099*4a0cb85cSEd Tanous continue; 1100*4a0cb85cSEd Tanous } 1101*4a0cb85cSEd Tanous } 1102*4a0cb85cSEd Tanous } 1103*4a0cb85cSEd Tanous 1104*4a0cb85cSEd Tanous std::string addressOriginInDBusFormat; 1105*4a0cb85cSEd Tanous const std::string *addressOriginField = nullptr; 1106*4a0cb85cSEd Tanous nlohmann::json::const_iterator addressOriginFieldIt = 1107*4a0cb85cSEd Tanous thisJson.find("AddressOrigin"); 1108*4a0cb85cSEd Tanous if (addressOriginFieldIt != thisJson.end()) 1109*4a0cb85cSEd Tanous { 1110*4a0cb85cSEd Tanous const std::string *addressOriginField = 1111*4a0cb85cSEd Tanous addressOriginFieldIt->get_ptr<const std::string *>(); 1112*4a0cb85cSEd Tanous if (addressOriginField == nullptr) 1113*4a0cb85cSEd Tanous { 1114*4a0cb85cSEd Tanous messages::addMessageToJson( 1115*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1116*4a0cb85cSEd Tanous messages::propertyValueFormatError(*addressOriginField, 1117*4a0cb85cSEd Tanous "AddressOrigin"), 1118*4a0cb85cSEd Tanous pathString + "/AddressOrigin"); 1119*4a0cb85cSEd Tanous continue; 1120*4a0cb85cSEd Tanous } 1121*4a0cb85cSEd Tanous else 1122*4a0cb85cSEd Tanous { 1123*4a0cb85cSEd Tanous // Get Address origin in proper format 1124*4a0cb85cSEd Tanous addressOriginInDBusFormat = 1125*4a0cb85cSEd Tanous translateAddressOriginRedfishToDbus( 1126*4a0cb85cSEd Tanous *addressOriginField); 1127*4a0cb85cSEd Tanous if (addressOriginInDBusFormat.empty()) 1128*4a0cb85cSEd Tanous { 1129*4a0cb85cSEd Tanous messages::addMessageToJson( 1130*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1131*4a0cb85cSEd Tanous messages::propertyValueNotInList( 1132*4a0cb85cSEd Tanous *addressOriginField, "AddressOrigin"), 1133*4a0cb85cSEd Tanous pathString + "/AddressOrigin"); 1134*4a0cb85cSEd Tanous continue; 1135*4a0cb85cSEd Tanous } 1136*4a0cb85cSEd Tanous } 1137*4a0cb85cSEd Tanous } 1138*4a0cb85cSEd Tanous 1139*4a0cb85cSEd Tanous nlohmann::json::const_iterator gatewayFieldIt = 1140*4a0cb85cSEd Tanous thisJson.find("Gateway"); 1141*4a0cb85cSEd Tanous const std::string *gatewayField = nullptr; 1142*4a0cb85cSEd Tanous if (gatewayFieldIt != thisJson.end()) 1143*4a0cb85cSEd Tanous { 1144*4a0cb85cSEd Tanous const std::string *gatewayField = 1145*4a0cb85cSEd Tanous gatewayFieldIt->get_ptr<const std::string *>(); 1146*4a0cb85cSEd Tanous if (gatewayField == nullptr || 1147*4a0cb85cSEd Tanous !ipv4VerifyIpAndGetBitcount(*gatewayField)) 1148*4a0cb85cSEd Tanous { 1149*4a0cb85cSEd Tanous messages::addMessageToJson( 1150*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1151*4a0cb85cSEd Tanous messages::propertyValueFormatError(*gatewayField, 1152*4a0cb85cSEd Tanous "Gateway"), 1153*4a0cb85cSEd Tanous pathString + "/Gateway"); 1154*4a0cb85cSEd Tanous continue; 1155*4a0cb85cSEd Tanous } 1156*4a0cb85cSEd Tanous } 1157*4a0cb85cSEd Tanous 1158*4a0cb85cSEd Tanous // if a vlan already exists, modify the existing 1159*4a0cb85cSEd Tanous if (thisData != ipv4Data.end()) 1160*4a0cb85cSEd Tanous { 11611abe55efSEd Tanous // Existing object that should be modified/deleted/remain 11621abe55efSEd Tanous // unchanged 1163*4a0cb85cSEd Tanous if (thisJson.is_null()) 11641abe55efSEd Tanous { 1165*4a0cb85cSEd Tanous auto callback = [entryIdx{std::to_string(entryIdx)}, 1166*4a0cb85cSEd Tanous asyncResp]( 1167*4a0cb85cSEd Tanous const boost::system::error_code ec) { 1168*4a0cb85cSEd Tanous if (ec) 1169*4a0cb85cSEd Tanous { 1170*4a0cb85cSEd Tanous messages::addMessageToJson( 1171*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1172*4a0cb85cSEd Tanous messages::internalError(), 1173*4a0cb85cSEd Tanous "/IPv4Addresses/" + entryIdx + "/"); 1174*4a0cb85cSEd Tanous return; 11751abe55efSEd Tanous } 1176*4a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = 1177*4a0cb85cSEd Tanous nullptr; 1178*4a0cb85cSEd Tanous }; 1179*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 1180*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1181*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + 1182*4a0cb85cSEd Tanous thisData->id, 1183*4a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 1184179db1d7SKowalski, Kamil } 1185*4a0cb85cSEd Tanous else if (thisJson.is_object()) 1186*4a0cb85cSEd Tanous { 1187179db1d7SKowalski, Kamil // Apply changes 1188*4a0cb85cSEd Tanous if (addressField != nullptr) 11891abe55efSEd Tanous { 1190*4a0cb85cSEd Tanous auto callback = 1191*4a0cb85cSEd Tanous [asyncResp, entryIdx, 1192*4a0cb85cSEd Tanous addressField{std::string(*addressField)}]( 1193*4a0cb85cSEd Tanous const boost::system::error_code ec) { 1194*4a0cb85cSEd Tanous if (ec) 11951abe55efSEd Tanous { 1196*4a0cb85cSEd Tanous messages::addMessageToJson( 1197*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1198*4a0cb85cSEd Tanous messages::internalError(), 1199*4a0cb85cSEd Tanous "/IPv4Addresses/" + 1200*4a0cb85cSEd Tanous std::to_string(entryIdx) + 1201*4a0cb85cSEd Tanous "/Address"); 1202*4a0cb85cSEd Tanous return; 1203*4a0cb85cSEd Tanous } 1204*4a0cb85cSEd Tanous asyncResp->res 1205*4a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 1206*4a0cb85cSEd Tanous entryIdx)]["Address"] = addressField; 1207*4a0cb85cSEd Tanous }; 1208*4a0cb85cSEd Tanous 1209*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 1210*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1211*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 1212*4a0cb85cSEd Tanous "/ipv4/" + thisData->id, 1213*4a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 1214*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Address", 1215*4a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 1216*4a0cb85cSEd Tanous *addressField)); 1217179db1d7SKowalski, Kamil } 1218179db1d7SKowalski, Kamil 1219*4a0cb85cSEd Tanous if (prefixLength && subnetField != nullptr) 12201abe55efSEd Tanous { 1221*4a0cb85cSEd Tanous changeIPv4SubnetMaskProperty(ifaceId, entryIdx, 1222*4a0cb85cSEd Tanous thisData->id, *subnetField, 1223*4a0cb85cSEd Tanous *prefixLength, asyncResp); 1224179db1d7SKowalski, Kamil } 1225179db1d7SKowalski, Kamil 1226*4a0cb85cSEd Tanous if (!addressOriginInDBusFormat.empty() && 1227*4a0cb85cSEd Tanous addressOriginField != nullptr) 12281abe55efSEd Tanous { 1229*4a0cb85cSEd Tanous changeIPv4Origin(ifaceId, entryIdx, thisData->id, 1230*4a0cb85cSEd Tanous *addressOriginField, 1231*4a0cb85cSEd Tanous addressOriginInDBusFormat, asyncResp); 1232179db1d7SKowalski, Kamil } 1233179db1d7SKowalski, Kamil 1234*4a0cb85cSEd Tanous if (gatewayField != nullptr) 12351abe55efSEd Tanous { 1236*4a0cb85cSEd Tanous auto callback = 1237*4a0cb85cSEd Tanous [asyncResp, entryIdx, 1238*4a0cb85cSEd Tanous gatewayField{std::string(*gatewayField)}]( 1239*4a0cb85cSEd Tanous const boost::system::error_code ec) { 1240*4a0cb85cSEd Tanous if (ec) 12411abe55efSEd Tanous { 1242*4a0cb85cSEd Tanous messages::addMessageToJson( 1243*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1244*4a0cb85cSEd Tanous messages::internalError(), 1245*4a0cb85cSEd Tanous "/IPv4Addresses/" + 1246*4a0cb85cSEd Tanous std::to_string(entryIdx) + 1247*4a0cb85cSEd Tanous "/Gateway"); 1248*4a0cb85cSEd Tanous return; 1249*4a0cb85cSEd Tanous } 1250*4a0cb85cSEd Tanous asyncResp->res 1251*4a0cb85cSEd Tanous .jsonValue["IPv4Addresses"][std::to_string( 1252*4a0cb85cSEd Tanous entryIdx)]["Gateway"] = 1253*4a0cb85cSEd Tanous std::move(gatewayField); 1254*4a0cb85cSEd Tanous }; 1255*4a0cb85cSEd Tanous 1256*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 1257*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1258*4a0cb85cSEd Tanous "/xyz/openbmc_project/network/" + ifaceId + 1259*4a0cb85cSEd Tanous "/ipv4/" + thisData->id, 1260*4a0cb85cSEd Tanous "org.freedesktop.DBus.Properties", "Set", 1261*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.IP", "Gateway", 1262*4a0cb85cSEd Tanous sdbusplus::message::variant<std::string>( 1263*4a0cb85cSEd Tanous *gatewayField)); 1264*4a0cb85cSEd Tanous } 1265*4a0cb85cSEd Tanous } 1266*4a0cb85cSEd Tanous thisData++; 12671abe55efSEd Tanous } 12681abe55efSEd Tanous else 12691abe55efSEd Tanous { 1270*4a0cb85cSEd Tanous // Create IPv4 with provided data 1271*4a0cb85cSEd Tanous if (gatewayField == nullptr) 12721abe55efSEd Tanous { 1273*4a0cb85cSEd Tanous messages::addMessageToJson( 1274*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1275*4a0cb85cSEd Tanous messages::propertyMissing("Gateway"), 1276*4a0cb85cSEd Tanous pathString + "/Gateway"); 1277*4a0cb85cSEd Tanous continue; 1278*4a0cb85cSEd Tanous } 1279*4a0cb85cSEd Tanous 1280*4a0cb85cSEd Tanous if (addressField == nullptr) 12811abe55efSEd Tanous { 1282*4a0cb85cSEd Tanous messages::addMessageToJson( 1283*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1284*4a0cb85cSEd Tanous messages::propertyMissing("Address"), 1285*4a0cb85cSEd Tanous pathString + "/Address"); 1286*4a0cb85cSEd Tanous continue; 1287*4a0cb85cSEd Tanous } 1288*4a0cb85cSEd Tanous 1289*4a0cb85cSEd Tanous if (!prefixLength) 12901abe55efSEd Tanous { 1291*4a0cb85cSEd Tanous messages::addMessageToJson( 1292*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1293*4a0cb85cSEd Tanous messages::propertyMissing("SubnetMask"), 1294*4a0cb85cSEd Tanous pathString + "/SubnetMask"); 1295*4a0cb85cSEd Tanous continue; 1296588c3f0dSKowalski, Kamil } 1297588c3f0dSKowalski, Kamil 1298*4a0cb85cSEd Tanous createIPv4(ifaceId, entryIdx, *prefixLength, *gatewayField, 1299*4a0cb85cSEd Tanous *addressField, asyncResp); 1300*4a0cb85cSEd Tanous asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = thisJson; 1301*4a0cb85cSEd Tanous } 1302*4a0cb85cSEd Tanous entryIdx++; 1303*4a0cb85cSEd Tanous } 1304*4a0cb85cSEd Tanous } 1305*4a0cb85cSEd Tanous 1306*4a0cb85cSEd Tanous nlohmann::json parseInterfaceData( 1307*4a0cb85cSEd Tanous const std::string &iface_id, const EthernetInterfaceData ðData, 1308*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 1309*4a0cb85cSEd Tanous { 1310*4a0cb85cSEd Tanous // Copy JSON object to avoid race condition 1311*4a0cb85cSEd Tanous nlohmann::json json_response(Node::json); 1312*4a0cb85cSEd Tanous 1313*4a0cb85cSEd Tanous json_response["Id"] = iface_id; 1314*4a0cb85cSEd Tanous json_response["@odata.id"] = 1315*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + iface_id; 1316*4a0cb85cSEd Tanous 1317*4a0cb85cSEd Tanous json_response["SpeedMbps"] = ethData.speed; 1318*4a0cb85cSEd Tanous json_response["MACAddress"] = ethData.mac_address; 1319*4a0cb85cSEd Tanous if (!ethData.hostname.empty()) 1320*4a0cb85cSEd Tanous { 1321*4a0cb85cSEd Tanous json_response["HostName"] = ethData.hostname; 1322*4a0cb85cSEd Tanous } 1323*4a0cb85cSEd Tanous 1324*4a0cb85cSEd Tanous nlohmann::json &vlanObj = json_response["VLAN"]; 1325*4a0cb85cSEd Tanous if (ethData.vlan_id) 1326*4a0cb85cSEd Tanous { 1327*4a0cb85cSEd Tanous vlanObj["VLANEnable"] = true; 1328*4a0cb85cSEd Tanous vlanObj["VLANId"] = *ethData.vlan_id; 1329*4a0cb85cSEd Tanous } 1330*4a0cb85cSEd Tanous else 1331*4a0cb85cSEd Tanous { 1332*4a0cb85cSEd Tanous vlanObj["VLANEnable"] = false; 1333*4a0cb85cSEd Tanous vlanObj["VLANId"] = 0; 1334*4a0cb85cSEd Tanous } 1335*4a0cb85cSEd Tanous 1336*4a0cb85cSEd Tanous if (ipv4Data.size() > 0) 1337*4a0cb85cSEd Tanous { 1338*4a0cb85cSEd Tanous nlohmann::json &ipv4_array = json_response["IPv4Addresses"]; 1339*4a0cb85cSEd Tanous ipv4_array = nlohmann::json::array(); 1340*4a0cb85cSEd Tanous for (auto &ipv4_config : ipv4Data) 1341*4a0cb85cSEd Tanous { 1342*4a0cb85cSEd Tanous if (!ipv4_config.address.empty()) 1343*4a0cb85cSEd Tanous { 1344*4a0cb85cSEd Tanous ipv4_array.push_back({{"AddressOrigin", ipv4_config.origin}, 1345*4a0cb85cSEd Tanous {"SubnetMask", ipv4_config.netmask}, 1346*4a0cb85cSEd Tanous {"Address", ipv4_config.address}}); 1347*4a0cb85cSEd Tanous 1348*4a0cb85cSEd Tanous if (!ipv4_config.gateway.empty()) 1349*4a0cb85cSEd Tanous { 1350*4a0cb85cSEd Tanous ipv4_array.back()["Gateway"] = ipv4_config.gateway; 1351*4a0cb85cSEd Tanous } 1352*4a0cb85cSEd Tanous } 1353*4a0cb85cSEd Tanous } 1354*4a0cb85cSEd Tanous } 1355*4a0cb85cSEd Tanous 1356*4a0cb85cSEd Tanous return json_response; 1357588c3f0dSKowalski, Kamil } 1358588c3f0dSKowalski, Kamil 13599391bb9cSRapkiewicz, Pawel /** 13609391bb9cSRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 13619391bb9cSRapkiewicz, Pawel */ 136255c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 13631abe55efSEd Tanous const std::vector<std::string> ¶ms) override 13641abe55efSEd Tanous { 1365*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13661abe55efSEd Tanous if (params.size() != 1) 13671abe55efSEd Tanous { 1368*4a0cb85cSEd Tanous asyncResp->res.result( 1369*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 13709391bb9cSRapkiewicz, Pawel return; 13719391bb9cSRapkiewicz, Pawel } 13729391bb9cSRapkiewicz, Pawel 1373*4a0cb85cSEd Tanous getEthernetIfaceData( 1374*4a0cb85cSEd Tanous params[0], 1375*4a0cb85cSEd Tanous [this, asyncResp, iface_id{std::string(params[0])}]( 1376*4a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 1377*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 1378*4a0cb85cSEd Tanous if (!success) 13791abe55efSEd Tanous { 13801abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 13811abe55efSEd Tanous // object, and other errors 1382e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1383*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1384*4a0cb85cSEd Tanous messages::resourceNotFound("EthernetInterface", 1385*4a0cb85cSEd Tanous iface_id)); 1386*4a0cb85cSEd Tanous asyncResp->res.result( 1387*4a0cb85cSEd Tanous boost::beast::http::status::not_found); 1388*4a0cb85cSEd Tanous return; 13899391bb9cSRapkiewicz, Pawel } 1390*4a0cb85cSEd Tanous asyncResp->res.jsonValue = 1391*4a0cb85cSEd Tanous parseInterfaceData(iface_id, ethData, 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 { 1398*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 13991abe55efSEd Tanous if (params.size() != 1) 14001abe55efSEd Tanous { 1401588c3f0dSKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1402588c3f0dSKowalski, Kamil return; 1403588c3f0dSKowalski, Kamil } 1404588c3f0dSKowalski, Kamil 1405*4a0cb85cSEd Tanous const std::string &iface_id = params[0]; 1406588c3f0dSKowalski, Kamil 1407179db1d7SKowalski, Kamil nlohmann::json patchReq; 14081abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 14091abe55efSEd Tanous { 1410588c3f0dSKowalski, Kamil return; 1411588c3f0dSKowalski, Kamil } 1412588c3f0dSKowalski, Kamil 1413*4a0cb85cSEd Tanous // Get single eth interface data, and call the below callback for JSON 1414588c3f0dSKowalski, Kamil // preparation 1415*4a0cb85cSEd Tanous getEthernetIfaceData( 1416*4a0cb85cSEd Tanous iface_id, 1417*4a0cb85cSEd Tanous [this, asyncResp, iface_id, patchReq = std::move(patchReq)]( 1418*4a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 1419*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 14201abe55efSEd Tanous if (!success) 14211abe55efSEd Tanous { 1422588c3f0dSKowalski, Kamil // ... otherwise return error 14231abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 14241abe55efSEd Tanous // object, and other errors 1425927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1426*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1427*4a0cb85cSEd Tanous messages::resourceNotFound("VLAN Network Interface", 1428*4a0cb85cSEd Tanous iface_id)); 1429*4a0cb85cSEd Tanous asyncResp->res.result( 1430*4a0cb85cSEd Tanous boost::beast::http::status::not_found); 1431*4a0cb85cSEd Tanous asyncResp->res.end(); 1432588c3f0dSKowalski, Kamil 1433588c3f0dSKowalski, Kamil return; 1434588c3f0dSKowalski, Kamil } 1435588c3f0dSKowalski, Kamil 1436*4a0cb85cSEd Tanous asyncResp->res.jsonValue = 1437*4a0cb85cSEd Tanous parseInterfaceData(iface_id, ethData, ipv4Data); 1438588c3f0dSKowalski, Kamil 1439*4a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 14401abe55efSEd Tanous { 14411abe55efSEd Tanous if (propertyIt.key() == "VLAN") 14421abe55efSEd Tanous { 1443*4a0cb85cSEd Tanous handleVlanPatch(iface_id, propertyIt.value(), ethData, 1444*4a0cb85cSEd Tanous asyncResp); 14451abe55efSEd Tanous } 14461abe55efSEd Tanous else if (propertyIt.key() == "HostName") 14471abe55efSEd Tanous { 1448*4a0cb85cSEd Tanous handleHostnamePatch(propertyIt.value(), asyncResp); 14491abe55efSEd Tanous } 14501abe55efSEd Tanous else if (propertyIt.key() == "IPv4Addresses") 14511abe55efSEd Tanous { 1452*4a0cb85cSEd Tanous handleIPv4Patch(iface_id, propertyIt.value(), ipv4Data, 1453179db1d7SKowalski, Kamil asyncResp); 14541abe55efSEd Tanous } 14551abe55efSEd Tanous else if (propertyIt.key() == "IPv6Addresses") 14561abe55efSEd Tanous { 1457179db1d7SKowalski, Kamil // TODO(kkowalsk) IPv6 Not supported on D-Bus yet 1458179db1d7SKowalski, Kamil messages::addMessageToJsonRoot( 1459*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1460179db1d7SKowalski, Kamil messages::propertyNotWritable(propertyIt.key())); 14611abe55efSEd Tanous } 14621abe55efSEd Tanous else 14631abe55efSEd Tanous { 14641abe55efSEd Tanous auto fieldInJsonIt = 1465*4a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 1466588c3f0dSKowalski, Kamil 1467*4a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 14681abe55efSEd Tanous { 1469588c3f0dSKowalski, Kamil // Field not in scope of defined fields 1470588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1471*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 14721abe55efSEd Tanous messages::propertyUnknown(propertyIt.key())); 14731abe55efSEd Tanous } 1474*4a0cb85cSEd Tanous else 14751abe55efSEd Tanous { 1476588c3f0dSKowalski, Kamil // User attempted to modify non-writable field 1477588c3f0dSKowalski, Kamil messages::addMessageToJsonRoot( 1478*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1479*4a0cb85cSEd Tanous messages::propertyNotWritable( 14801abe55efSEd Tanous propertyIt.key())); 1481588c3f0dSKowalski, Kamil } 1482588c3f0dSKowalski, Kamil } 1483588c3f0dSKowalski, Kamil } 1484588c3f0dSKowalski, Kamil }); 1485588c3f0dSKowalski, Kamil } 14869391bb9cSRapkiewicz, Pawel }; 14879391bb9cSRapkiewicz, Pawel 1488e439f0f8SKowalski, Kamil /** 1489*4a0cb85cSEd Tanous * VlanNetworkInterface derived class for delivering VLANNetworkInterface 1490*4a0cb85cSEd Tanous * Schema 1491e439f0f8SKowalski, Kamil */ 14921abe55efSEd Tanous class VlanNetworkInterface : public Node 14931abe55efSEd Tanous { 1494e439f0f8SKowalski, Kamil public: 1495e439f0f8SKowalski, Kamil /* 1496e439f0f8SKowalski, Kamil * Default Constructor 1497e439f0f8SKowalski, Kamil */ 1498e439f0f8SKowalski, Kamil template <typename CrowApp> 14991abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 1500*4a0cb85cSEd Tanous // one manager called openbmc. This shall be generic, but requires to 1501*4a0cb85cSEd Tanous // update GetSubroutes method 15021abe55efSEd Tanous VlanNetworkInterface(CrowApp &app) : 1503*4a0cb85cSEd Tanous Node(app, 1504*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>>/VLANs/" 1505*4a0cb85cSEd Tanous "<str>", 15061abe55efSEd Tanous std::string(), std::string()) 15071abe55efSEd Tanous { 1508e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1509e439f0f8SKowalski, Kamil "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; 1510e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1511e439f0f8SKowalski, Kamil "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface"; 1512e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface"; 1513e439f0f8SKowalski, Kamil 1514e439f0f8SKowalski, Kamil entityPrivileges = { 1515e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1516e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1517e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1518e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1519e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1520e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1521e439f0f8SKowalski, Kamil } 1522e439f0f8SKowalski, Kamil 1523e439f0f8SKowalski, Kamil private: 1524*4a0cb85cSEd Tanous nlohmann::json parseInterfaceData( 1525*4a0cb85cSEd Tanous const std::string &parent_iface_id, const std::string &iface_id, 1526*4a0cb85cSEd Tanous const EthernetInterfaceData ðData, 1527*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) 15281abe55efSEd Tanous { 1529e439f0f8SKowalski, Kamil // Copy JSON object to avoid race condition 1530*4a0cb85cSEd Tanous nlohmann::json json_response(Node::json); 1531e439f0f8SKowalski, Kamil 1532e439f0f8SKowalski, Kamil // Fill out obvious data... 1533*4a0cb85cSEd Tanous json_response["Id"] = iface_id; 1534*4a0cb85cSEd Tanous json_response["@odata.id"] = 1535*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parent_iface_id + 1536*4a0cb85cSEd Tanous "/VLANs/" + iface_id; 1537e439f0f8SKowalski, Kamil 1538*4a0cb85cSEd Tanous json_response["VLANEnable"] = true; 1539*4a0cb85cSEd Tanous if (ethData.vlan_id) 1540*4a0cb85cSEd Tanous { 1541*4a0cb85cSEd Tanous json_response["VLANId"] = *ethData.vlan_id; 1542*4a0cb85cSEd Tanous } 1543*4a0cb85cSEd Tanous return json_response; 1544e439f0f8SKowalski, Kamil } 1545e439f0f8SKowalski, Kamil 154655c7b7a2SEd Tanous bool verifyNames(crow::Response &res, const std::string &parent, 15471abe55efSEd Tanous const std::string &iface) 15481abe55efSEd Tanous { 15491abe55efSEd Tanous if (!boost::starts_with(iface, parent + "_")) 15501abe55efSEd Tanous { 1551927a505aSKowalski, Kamil messages::addMessageToErrorJson( 155255c7b7a2SEd Tanous res.jsonValue, 1553927a505aSKowalski, Kamil messages::resourceNotFound("VLAN Network Interface", iface)); 1554927a505aSKowalski, Kamil res.result(boost::beast::http::status::not_found); 1555927a505aSKowalski, Kamil res.end(); 1556927a505aSKowalski, Kamil 1557927a505aSKowalski, Kamil return false; 15581abe55efSEd Tanous } 15591abe55efSEd Tanous else 15601abe55efSEd Tanous { 1561927a505aSKowalski, Kamil return true; 1562927a505aSKowalski, Kamil } 1563927a505aSKowalski, Kamil } 1564927a505aSKowalski, Kamil 1565e439f0f8SKowalski, Kamil /** 1566e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1567e439f0f8SKowalski, Kamil */ 156855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 15691abe55efSEd Tanous const std::vector<std::string> ¶ms) override 15701abe55efSEd Tanous { 1571*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1572*4a0cb85cSEd Tanous // TODO(Pawel) this shall be parameterized call (two params) to get 1573e439f0f8SKowalski, Kamil // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. 1574e439f0f8SKowalski, Kamil // Check if there is required param, truly entering this shall be 1575e439f0f8SKowalski, Kamil // impossible. 15761abe55efSEd Tanous if (params.size() != 2) 15771abe55efSEd Tanous { 1578e439f0f8SKowalski, Kamil res.result(boost::beast::http::status::internal_server_error); 1579e439f0f8SKowalski, Kamil res.end(); 1580e439f0f8SKowalski, Kamil return; 1581e439f0f8SKowalski, Kamil } 1582e439f0f8SKowalski, Kamil 1583*4a0cb85cSEd Tanous const std::string &parent_iface_id = params[0]; 1584*4a0cb85cSEd Tanous const std::string &iface_id = params[1]; 1585e439f0f8SKowalski, Kamil 1586*4a0cb85cSEd Tanous if (!verifyNames(res, parent_iface_id, iface_id)) 15871abe55efSEd Tanous { 1588a434f2bdSEd Tanous return; 1589a434f2bdSEd Tanous } 1590a434f2bdSEd Tanous 1591e439f0f8SKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1592e439f0f8SKowalski, Kamil // preparation 1593*4a0cb85cSEd Tanous getEthernetIfaceData( 1594*4a0cb85cSEd Tanous iface_id, 1595*4a0cb85cSEd Tanous [this, asyncResp, parent_iface_id, iface_id]( 1596*4a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 1597*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 1598*4a0cb85cSEd Tanous if (success && ethData.vlan_id) 15991abe55efSEd Tanous { 1600*4a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 1601*4a0cb85cSEd Tanous parent_iface_id, iface_id, ethData, ipv4Data); 16021abe55efSEd Tanous } 16031abe55efSEd Tanous else 16041abe55efSEd Tanous { 1605e439f0f8SKowalski, Kamil // ... otherwise return error 16061abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 16071abe55efSEd Tanous // object, and other errors 1608927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1609*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1610*4a0cb85cSEd Tanous messages::resourceNotFound("VLAN Network Interface", 1611*4a0cb85cSEd Tanous iface_id)); 1612*4a0cb85cSEd Tanous asyncResp->res.result( 1613*4a0cb85cSEd Tanous boost::beast::http::status::not_found); 1614e439f0f8SKowalski, Kamil } 1615e439f0f8SKowalski, Kamil }); 1616e439f0f8SKowalski, Kamil } 1617e439f0f8SKowalski, Kamil 161855c7b7a2SEd Tanous void doPatch(crow::Response &res, const crow::Request &req, 16191abe55efSEd Tanous const std::vector<std::string> ¶ms) override 16201abe55efSEd Tanous { 1621*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16221abe55efSEd Tanous if (params.size() != 2) 16231abe55efSEd Tanous { 1624*4a0cb85cSEd Tanous asyncResp->res.result( 1625*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1626e439f0f8SKowalski, Kamil return; 1627e439f0f8SKowalski, Kamil } 1628e439f0f8SKowalski, Kamil 1629d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 163055c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1631927a505aSKowalski, Kamil 16321abe55efSEd Tanous if (!verifyNames(res, parentIfaceId, ifaceId)) 16331abe55efSEd Tanous { 1634927a505aSKowalski, Kamil return; 1635927a505aSKowalski, Kamil } 1636927a505aSKowalski, Kamil 1637927a505aSKowalski, Kamil nlohmann::json patchReq; 16381abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, patchReq)) 16391abe55efSEd Tanous { 1640927a505aSKowalski, Kamil return; 1641927a505aSKowalski, Kamil } 1642927a505aSKowalski, Kamil 1643927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1644927a505aSKowalski, Kamil // preparation 1645*4a0cb85cSEd Tanous getEthernetIfaceData( 16461abe55efSEd Tanous ifaceId, 1647*4a0cb85cSEd Tanous [this, asyncResp, parentIfaceId, ifaceId, 1648*4a0cb85cSEd Tanous patchReq{std::move(patchReq)}]( 1649*4a0cb85cSEd Tanous const bool &success, const EthernetInterfaceData ðData, 1650*4a0cb85cSEd Tanous const boost::container::flat_set<IPv4AddressData> &ipv4Data) { 16511abe55efSEd Tanous if (!success) 16521abe55efSEd Tanous { 16531abe55efSEd Tanous // TODO(Pawel)consider distinguish between non existing 16541abe55efSEd Tanous // object, and other errors 1655927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1656*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1657*4a0cb85cSEd Tanous messages::resourceNotFound("VLAN Network Interface", 1658*4a0cb85cSEd Tanous ifaceId)); 1659*4a0cb85cSEd Tanous asyncResp->res.result( 1660*4a0cb85cSEd Tanous boost::beast::http::status::not_found); 1661*4a0cb85cSEd Tanous asyncResp->res.end(); 1662927a505aSKowalski, Kamil 1663927a505aSKowalski, Kamil return; 1664927a505aSKowalski, Kamil } 1665927a505aSKowalski, Kamil 1666*4a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 1667*4a0cb85cSEd Tanous parentIfaceId, ifaceId, ethData, ipv4Data); 1668927a505aSKowalski, Kamil 1669*4a0cb85cSEd Tanous for (auto propertyIt : patchReq.items()) 16701abe55efSEd Tanous { 1671927a505aSKowalski, Kamil if (propertyIt.key() != "VLANEnable" && 16721abe55efSEd Tanous propertyIt.key() != "VLANId") 16731abe55efSEd Tanous { 16741abe55efSEd Tanous auto fieldInJsonIt = 1675*4a0cb85cSEd Tanous asyncResp->res.jsonValue.find(propertyIt.key()); 1676*4a0cb85cSEd Tanous if (fieldInJsonIt == asyncResp->res.jsonValue.end()) 16771abe55efSEd Tanous { 1678927a505aSKowalski, Kamil // Field not in scope of defined fields 1679927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1680*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 16811abe55efSEd Tanous messages::propertyUnknown(propertyIt.key())); 16821abe55efSEd Tanous } 1683*4a0cb85cSEd Tanous else 16841abe55efSEd Tanous { 1685927a505aSKowalski, Kamil // User attempted to modify non-writable field 1686927a505aSKowalski, Kamil messages::addMessageToJsonRoot( 1687*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1688*4a0cb85cSEd Tanous messages::propertyNotWritable( 16891abe55efSEd Tanous propertyIt.key())); 1690927a505aSKowalski, Kamil } 1691927a505aSKowalski, Kamil } 1692927a505aSKowalski, Kamil } 1693927a505aSKowalski, Kamil 1694*4a0cb85cSEd Tanous EthernetInterface::handleVlanPatch(ifaceId, patchReq, ethData, 1695*4a0cb85cSEd Tanous asyncResp); 1696927a505aSKowalski, Kamil }); 1697e439f0f8SKowalski, Kamil } 1698e439f0f8SKowalski, Kamil 169955c7b7a2SEd Tanous void doDelete(crow::Response &res, const crow::Request &req, 17001abe55efSEd Tanous const std::vector<std::string> ¶ms) override 17011abe55efSEd Tanous { 1702*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17031abe55efSEd Tanous if (params.size() != 2) 17041abe55efSEd Tanous { 1705*4a0cb85cSEd Tanous asyncResp->res.result( 1706*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1707e439f0f8SKowalski, Kamil return; 1708e439f0f8SKowalski, Kamil } 1709e439f0f8SKowalski, Kamil 1710d76323e5SEd Tanous const std::string &parentIfaceId = params[0]; 171155c7b7a2SEd Tanous const std::string &ifaceId = params[1]; 1712927a505aSKowalski, Kamil 1713*4a0cb85cSEd Tanous if (!verifyNames(asyncResp->res, parentIfaceId, ifaceId)) 17141abe55efSEd Tanous { 1715927a505aSKowalski, Kamil return; 1716927a505aSKowalski, Kamil } 1717927a505aSKowalski, Kamil 1718927a505aSKowalski, Kamil // Get single eth interface data, and call the below callback for JSON 1719927a505aSKowalski, Kamil // preparation 1720*4a0cb85cSEd Tanous getEthernetIfaceData(ifaceId, [this, asyncResp, 1721*4a0cb85cSEd Tanous parentIfaceId{ 1722*4a0cb85cSEd Tanous std::string(parentIfaceId)}, 1723*4a0cb85cSEd Tanous ifaceId{std::string(ifaceId)}]( 1724*4a0cb85cSEd Tanous const bool &success, 1725*4a0cb85cSEd Tanous const EthernetInterfaceData ðData, 1726*4a0cb85cSEd Tanous const boost::container::flat_set< 1727*4a0cb85cSEd Tanous IPv4AddressData> &ipv4Data) { 1728*4a0cb85cSEd Tanous if (success && ethData.vlan_id) 17291abe55efSEd Tanous { 1730*4a0cb85cSEd Tanous asyncResp->res.jsonValue = parseInterfaceData( 1731*4a0cb85cSEd Tanous parentIfaceId, ifaceId, ethData, ipv4Data); 1732927a505aSKowalski, Kamil 1733*4a0cb85cSEd Tanous auto callback = [asyncResp]( 1734*4a0cb85cSEd Tanous const boost::system::error_code ec) { 17351abe55efSEd Tanous if (ec) 17361abe55efSEd Tanous { 17371abe55efSEd Tanous messages::addMessageToErrorJson( 1738*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1739*4a0cb85cSEd Tanous messages::internalError()); 1740*4a0cb85cSEd Tanous asyncResp->res.result( 1741*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1742927a505aSKowalski, Kamil } 1743*4a0cb85cSEd Tanous }; 1744*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 1745*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1746*4a0cb85cSEd Tanous std::string("/xyz/openbmc_project/network/") + ifaceId, 1747*4a0cb85cSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 17481abe55efSEd Tanous } 17491abe55efSEd Tanous else 17501abe55efSEd Tanous { 1751927a505aSKowalski, Kamil // ... otherwise return error 1752*4a0cb85cSEd Tanous // TODO(Pawel)consider distinguish between non existing object, 1753*4a0cb85cSEd Tanous // and 1754*4a0cb85cSEd Tanous // other errors 1755927a505aSKowalski, Kamil messages::addMessageToErrorJson( 1756*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1757*4a0cb85cSEd Tanous messages::resourceNotFound("VLAN Network Interface", 1758*4a0cb85cSEd Tanous ifaceId)); 1759*4a0cb85cSEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 1760*4a0cb85cSEd Tanous asyncResp->res.end(); 1761927a505aSKowalski, Kamil } 1762927a505aSKowalski, Kamil }); 1763e439f0f8SKowalski, Kamil } 1764e439f0f8SKowalski, Kamil }; 1765e439f0f8SKowalski, Kamil 1766e439f0f8SKowalski, Kamil /** 1767e439f0f8SKowalski, Kamil * VlanNetworkInterfaceCollection derived class for delivering 1768e439f0f8SKowalski, Kamil * VLANNetworkInterface Collection Schema 1769e439f0f8SKowalski, Kamil */ 17701abe55efSEd Tanous class VlanNetworkInterfaceCollection : public Node 17711abe55efSEd Tanous { 1772e439f0f8SKowalski, Kamil public: 1773e439f0f8SKowalski, Kamil template <typename CrowApp> 17741abe55efSEd Tanous // TODO(Pawel) Remove line from below, where we assume that there is only 1775*4a0cb85cSEd Tanous // one manager called openbmc. This shall be generic, but requires to 1776*4a0cb85cSEd Tanous // update GetSubroutes method 17771abe55efSEd Tanous VlanNetworkInterfaceCollection(CrowApp &app) : 1778*4a0cb85cSEd Tanous Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", 1779*4a0cb85cSEd Tanous std::string()) 17801abe55efSEd Tanous { 1781e439f0f8SKowalski, Kamil Node::json["@odata.type"] = 1782e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1783e439f0f8SKowalski, Kamil Node::json["@odata.context"] = 1784e439f0f8SKowalski, Kamil "/redfish/v1/$metadata" 1785e439f0f8SKowalski, Kamil "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection"; 1786e439f0f8SKowalski, Kamil Node::json["Name"] = "VLAN Network Interface Collection"; 1787e439f0f8SKowalski, Kamil 1788e439f0f8SKowalski, Kamil entityPrivileges = { 1789e439f0f8SKowalski, Kamil {boost::beast::http::verb::get, {{"Login"}}}, 1790e439f0f8SKowalski, Kamil {boost::beast::http::verb::head, {{"Login"}}}, 1791e439f0f8SKowalski, Kamil {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1792e439f0f8SKowalski, Kamil {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1793e439f0f8SKowalski, Kamil {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1794e439f0f8SKowalski, Kamil {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1795e439f0f8SKowalski, Kamil } 1796e439f0f8SKowalski, Kamil 1797e439f0f8SKowalski, Kamil private: 1798e439f0f8SKowalski, Kamil /** 1799e439f0f8SKowalski, Kamil * Functions triggers appropriate requests on DBus 1800e439f0f8SKowalski, Kamil */ 180155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 18021abe55efSEd Tanous const std::vector<std::string> ¶ms) override 18031abe55efSEd Tanous { 1804*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 18051abe55efSEd Tanous if (params.size() != 1) 18061abe55efSEd Tanous { 1807e439f0f8SKowalski, Kamil // This means there is a problem with the router 1808*4a0cb85cSEd Tanous asyncResp->res.result( 1809*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1810e439f0f8SKowalski, Kamil return; 1811e439f0f8SKowalski, Kamil } 1812e439f0f8SKowalski, Kamil 1813*4a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1814e439f0f8SKowalski, Kamil 1815*4a0cb85cSEd Tanous // Get eth interface list, and call the below callback for JSON 18161abe55efSEd Tanous // preparation 1817*4a0cb85cSEd Tanous getEthernetIfaceList([this, asyncResp, 1818*4a0cb85cSEd Tanous rootInterfaceName{ 1819*4a0cb85cSEd Tanous std::string(rootInterfaceName)}]( 18201abe55efSEd Tanous const bool &success, 18211abe55efSEd Tanous const std::vector<std::string> &iface_list) { 1822*4a0cb85cSEd Tanous if (!success) 18231abe55efSEd Tanous { 1824*4a0cb85cSEd Tanous asyncResp->res.result( 1825*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1826*4a0cb85cSEd Tanous return; 18271abe55efSEd Tanous } 1828*4a0cb85cSEd Tanous asyncResp->res.jsonValue = Node::json; 1829*4a0cb85cSEd Tanous 1830*4a0cb85cSEd Tanous nlohmann::json iface_array = nlohmann::json::array(); 1831*4a0cb85cSEd Tanous 1832*4a0cb85cSEd Tanous for (const std::string &iface_item : iface_list) 18331abe55efSEd Tanous { 1834*4a0cb85cSEd Tanous if (boost::starts_with(iface_item, rootInterfaceName + "_")) 1835*4a0cb85cSEd Tanous { 1836*4a0cb85cSEd Tanous iface_array.push_back( 1837*4a0cb85cSEd Tanous {{"@odata.id", 1838*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 1839*4a0cb85cSEd Tanous rootInterfaceName + "/VLANs/" + iface_item}}); 1840e439f0f8SKowalski, Kamil } 1841e439f0f8SKowalski, Kamil } 1842e439f0f8SKowalski, Kamil 1843*4a0cb85cSEd Tanous if (iface_array.empty()) 18441abe55efSEd Tanous { 1845e439f0f8SKowalski, Kamil messages::addMessageToErrorJson( 1846*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 18471abe55efSEd Tanous messages::resourceNotFound("EthernetInterface", 1848e439f0f8SKowalski, Kamil rootInterfaceName)); 1849*4a0cb85cSEd Tanous asyncResp->res.result(boost::beast::http::status::not_found); 1850*4a0cb85cSEd Tanous return; 1851e439f0f8SKowalski, Kamil } 1852*4a0cb85cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 1853*4a0cb85cSEd Tanous iface_array.size(); 1854*4a0cb85cSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(iface_array); 1855*4a0cb85cSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 1856*4a0cb85cSEd Tanous "/redfish/v1/Managers/bmc/EthernetInterfaces/" + 1857*4a0cb85cSEd Tanous rootInterfaceName + "/VLANs"; 1858e439f0f8SKowalski, Kamil }); 1859e439f0f8SKowalski, Kamil } 1860e439f0f8SKowalski, Kamil 186155c7b7a2SEd Tanous void doPost(crow::Response &res, const crow::Request &req, 18621abe55efSEd Tanous const std::vector<std::string> ¶ms) override 18631abe55efSEd Tanous { 1864*4a0cb85cSEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 18651abe55efSEd Tanous if (params.size() != 1) 18661abe55efSEd Tanous { 1867*4a0cb85cSEd Tanous asyncResp->res.result( 1868*4a0cb85cSEd Tanous boost::beast::http::status::internal_server_error); 1869e439f0f8SKowalski, Kamil return; 1870e439f0f8SKowalski, Kamil } 1871e439f0f8SKowalski, Kamil 1872e439f0f8SKowalski, Kamil nlohmann::json postReq; 18731abe55efSEd Tanous if (!json_util::processJsonFromRequest(res, req, postReq)) 18741abe55efSEd Tanous { 1875e439f0f8SKowalski, Kamil return; 1876e439f0f8SKowalski, Kamil } 1877e439f0f8SKowalski, Kamil 1878*4a0cb85cSEd Tanous auto vlanIdJson = json.find("VLANId"); 1879*4a0cb85cSEd Tanous if (vlanIdJson == json.end()) 18801abe55efSEd Tanous { 1881*4a0cb85cSEd Tanous messages::addMessageToJson(asyncResp->res.jsonValue, 1882*4a0cb85cSEd Tanous messages::propertyMissing("VLANId"), 1883*4a0cb85cSEd Tanous "/VLANId"); 1884e439f0f8SKowalski, Kamil return; 1885e439f0f8SKowalski, Kamil } 1886e439f0f8SKowalski, Kamil 1887*4a0cb85cSEd Tanous const uint64_t *vlanId = vlanIdJson->get_ptr<const uint64_t *>(); 1888*4a0cb85cSEd Tanous if (vlanId == nullptr) 18891abe55efSEd Tanous { 1890*4a0cb85cSEd Tanous messages::addMessageToJson( 1891*4a0cb85cSEd Tanous asyncResp->res.jsonValue, 1892*4a0cb85cSEd Tanous messages::propertyValueTypeError(vlanIdJson->dump(), "VLANId"), 1893*4a0cb85cSEd Tanous "/VLANId"); 1894*4a0cb85cSEd Tanous return; 1895e439f0f8SKowalski, Kamil } 1896*4a0cb85cSEd Tanous const std::string &rootInterfaceName = params[0]; 1897e439f0f8SKowalski, Kamil 1898*4a0cb85cSEd Tanous auto callback = [asyncResp](const boost::system::error_code ec) { 18991abe55efSEd Tanous if (ec) 19001abe55efSEd Tanous { 1901*4a0cb85cSEd Tanous // TODO(ed) make more consistent error messages based on 1902*4a0cb85cSEd Tanous // phosphor-network responses 1903*4a0cb85cSEd Tanous messages::addMessageToErrorJson(asyncResp->res.jsonValue, 19048ceb2ecaSEd Tanous messages::internalError()); 1905*4a0cb85cSEd Tanous return; 19061abe55efSEd Tanous } 1907*4a0cb85cSEd Tanous asyncResp->res.result(boost::beast::http::status::created); 1908*4a0cb85cSEd Tanous messages::addMessageToErrorJson(asyncResp->res.jsonValue, 1909*4a0cb85cSEd Tanous messages::created()); 1910e439f0f8SKowalski, Kamil }; 1911*4a0cb85cSEd Tanous crow::connections::systemBus->async_method_call( 1912*4a0cb85cSEd Tanous std::move(callback), "xyz.openbmc_project.Network", 1913*4a0cb85cSEd Tanous "/xyz/openbmc_project/network", 1914*4a0cb85cSEd Tanous "xyz.openbmc_project.Network.VLAN.Create", "VLAN", 1915*4a0cb85cSEd Tanous rootInterfaceName, static_cast<uint32_t>(*vlanId)); 1916*4a0cb85cSEd Tanous } 1917*4a0cb85cSEd Tanous }; 19189391bb9cSRapkiewicz, Pawel } // namespace redfish 1919