diff options
-rw-r--r-- | redfish-core/include/redfish.hpp | 6 | ||||
-rw-r--r-- | redfish-core/lib/ethernet.hpp | 2298 | ||||
-rw-r--r-- | redfish-core/lib/hypervisor_system.hpp | 15 |
3 files changed, 1086 insertions, 1233 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index 6dff5fddbe..0f43a36c35 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -69,8 +69,7 @@ class RedfishService requestRoutesServiceRoot(app); requestRoutesNetworkProtocol(app); requestRoutesSession(app); - nodes.emplace_back(std::make_unique<EthernetCollection>(app)); - nodes.emplace_back(std::make_unique<EthernetInterface>(app)); + requestEthernetInterfacesRoutes(app); requestRoutesThermal(app); requestRoutesManagerCollection(app); requestRoutesManager(app); @@ -91,9 +90,6 @@ class RedfishService #endif requestRoutesSoftwareInventoryCollection(app); requestRoutesSoftwareInventory(app); - nodes.emplace_back( - std::make_unique<VlanNetworkInterfaceCollection>(app)); - nodes.emplace_back(std::make_unique<VlanNetworkInterface>(app)); requestRoutesSystemLogServiceCollection(app); requestRoutesEventLogService(app); diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp index 99f452d727..d78cb58703 100644 --- a/redfish-core/lib/ethernet.hpp +++ b/redfish-core/lib/ethernet.hpp @@ -1024,1360 +1024,1233 @@ void getEthernetIfaceList(CallbackFunc&& callback) "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); } -/** - * EthernetCollection derived class for delivering Ethernet Collection Schema - */ -class EthernetCollection : public Node +void handleHostnamePatch(const std::string& hostname, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - public: - EthernetCollection(App& app) : - Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") - { - entityPrivileges = { - {boost::beast::http::verb::get, {{"Login"}}}, - {boost::beast::http::verb::head, {{"Login"}}}, - {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; - } - - private: - /** - * Functions triggers appropriate requests on DBus - */ - void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request&, const std::vector<std::string>&) override + // SHOULD handle host names of up to 255 characters(RFC 1123) + if (hostname.length() > 255) { - asyncResp->res.jsonValue["@odata.type"] = - "#EthernetInterfaceCollection.EthernetInterfaceCollection"; - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/Managers/bmc/EthernetInterfaces"; - asyncResp->res.jsonValue["Name"] = - "Ethernet Network Interface Collection"; - asyncResp->res.jsonValue["Description"] = - "Collection of EthernetInterfaces for this Manager"; - - // Get eth interface list, and call the below callback for JSON - // preparation - getEthernetIfaceList( - [asyncResp]( - const bool& success, - const boost::container::flat_set<std::string>& ifaceList) { - if (!success) - { - messages::internalError(asyncResp->res); - return; - } - - nlohmann::json& ifaceArray = - asyncResp->res.jsonValue["Members"]; - ifaceArray = nlohmann::json::array(); - std::string tag = "_"; - for (const std::string& ifaceItem : ifaceList) - { - std::size_t found = ifaceItem.find(tag); - if (found == std::string::npos) - { - ifaceArray.push_back( - {{"@odata.id", - "/redfish/v1/Managers/bmc/EthernetInterfaces/" + - ifaceItem}}); - } - } - - asyncResp->res.jsonValue["Members@odata.count"] = - ifaceArray.size(); - asyncResp->res.jsonValue["@odata.id"] = - "/redfish/v1/Managers/bmc/EthernetInterfaces"; - }); + messages::propertyValueFormatError(asyncResp->res, hostname, + "HostName"); + return; } -}; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + } + }, + "xyz.openbmc_project.Network", "/xyz/openbmc_project/network/config", + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.SystemConfiguration", "HostName", + std::variant<std::string>(hostname)); +} -/** - * EthernetInterface derived class for delivering Ethernet Schema - */ -class EthernetInterface : public Node +void handleDomainnamePatch(const std::string& ifaceId, + const std::string& domainname, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { - public: - /* - * Default Constructor - */ - EthernetInterface(App& app) : - Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/", - std::string()) - { - entityPrivileges = { - {boost::beast::http::verb::get, {{"Login"}}}, - {boost::beast::http::verb::head, {{"Login"}}}, - {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; - } - - private: - void - handleHostnamePatch(const std::string& hostname, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) - { - // SHOULD handle host names of up to 255 characters(RFC 1123) - if (hostname.length() > 255) - { - messages::propertyValueFormatError(asyncResp->res, hostname, - "HostName"); - return; - } - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - messages::internalError(asyncResp->res); - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/config", - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.SystemConfiguration", "HostName", - std::variant<std::string>(hostname)); - } - - void handleDomainnamePatch( - const std::string& ifaceId, const std::string& domainname, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) - { - std::vector<std::string> vectorDomainname = {domainname}; - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - messages::internalError(asyncResp->res); - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.EthernetInterface", "DomainName", - std::variant<std::vector<std::string>>(vectorDomainname)); - } - - void handleFqdnPatch(const std::string& ifaceId, const std::string& fqdn, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) - { - // Total length of FQDN must not exceed 255 characters(RFC 1035) - if (fqdn.length() > 255) - { - messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); - return; - } - - size_t pos = fqdn.find('.'); - if (pos == std::string::npos) - { - messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); - return; - } - - std::string hostname; - std::string domainname; - domainname = (fqdn).substr(pos + 1); - hostname = (fqdn).substr(0, pos); - - if (!isHostnameValid(hostname) || !isDomainnameValid(domainname)) - { - messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); - return; - } - - handleHostnamePatch(hostname, asyncResp); - handleDomainnamePatch(ifaceId, domainname, asyncResp); - } + std::vector<std::string> vectorDomainname = {domainname}; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + } + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.EthernetInterface", "DomainName", + std::variant<std::vector<std::string>>(vectorDomainname)); +} - bool isHostnameValid(const std::string& hostname) +bool isHostnameValid(const std::string& hostname) +{ + // A valid host name can never have the dotted-decimal form (RFC 1123) + if (std::all_of(hostname.begin(), hostname.end(), ::isdigit)) { - // A valid host name can never have the dotted-decimal form (RFC 1123) - if (std::all_of(hostname.begin(), hostname.end(), ::isdigit)) - { - return false; - } - // Each label(hostname/subdomains) within a valid FQDN - // MUST handle host names of up to 63 characters (RFC 1123) - // labels cannot start or end with hyphens (RFC 952) - // labels can start with numbers (RFC 1123) - const std::regex pattern( - "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); - - return std::regex_match(hostname, pattern); + return false; } + // Each label(hostname/subdomains) within a valid FQDN + // MUST handle host names of up to 63 characters (RFC 1123) + // labels cannot start or end with hyphens (RFC 952) + // labels can start with numbers (RFC 1123) + const std::regex pattern( + "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); + + return std::regex_match(hostname, pattern); +} - bool isDomainnameValid(const std::string& domainname) - { - // Can have multiple subdomains - // Top Level Domain's min length is 2 character - const std::regex pattern("^([A-Za-z0-9][a-zA-Z0-9\\-]{1,61}|[a-zA-Z0-9]" - "{1,30}\\.)*[a-zA-Z]{2,}$"); +bool isDomainnameValid(const std::string& domainname) +{ + // Can have multiple subdomains + // Top Level Domain's min length is 2 character + const std::regex pattern("^([A-Za-z0-9][a-zA-Z0-9\\-]{1,61}|[a-zA-Z0-9]" + "{1,30}\\.)*[a-zA-Z]{2,}$"); - return std::regex_match(domainname, pattern); - } + return std::regex_match(domainname, pattern); +} - void handleMACAddressPatch( - const std::string& ifaceId, const std::string& macAddress, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +void handleFqdnPatch(const std::string& ifaceId, const std::string& fqdn, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + // Total length of FQDN must not exceed 255 characters(RFC 1035) + if (fqdn.length() > 255) { - crow::connections::systemBus->async_method_call( - [asyncResp, macAddress](const boost::system::error_code ec) { - if (ec) - { - messages::internalError(asyncResp->res); - return; - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.MACAddress", "MACAddress", - std::variant<std::string>(macAddress)); + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; } - void setDHCPEnabled(const std::string& ifaceId, - const std::string& propertyName, const bool v4Value, - const bool v6Value, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) + size_t pos = fqdn.find('.'); + if (pos == std::string::npos) { - const std::string dhcp = getDhcpEnabledEnumeration(v4Value, v6Value); - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; - messages::internalError(asyncResp->res); - return; - } - messages::success(asyncResp->res); - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.EthernetInterface", propertyName, - std::variant<std::string>{dhcp}); + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; } - void setEthernetInterfaceBoolProperty( - const std::string& ifaceId, const std::string& propertyName, - const bool& value, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) - { - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; - messages::internalError(asyncResp->res); - return; - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.EthernetInterface", propertyName, - std::variant<bool>{value}); - } + std::string hostname; + std::string domainname; + domainname = (fqdn).substr(pos + 1); + hostname = (fqdn).substr(0, pos); - void setDHCPv4Config(const std::string& propertyName, const bool& value, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) + if (!isHostnameValid(hostname) || !isDomainnameValid(domainname)) { - BMCWEB_LOG_DEBUG << propertyName << " = " << value; - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; - messages::internalError(asyncResp->res); - return; - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/config/dhcp", - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.DHCPConfiguration", propertyName, - std::variant<bool>{value}); + messages::propertyValueFormatError(asyncResp->res, fqdn, "FQDN"); + return; } - void handleDHCPPatch(const std::string& ifaceId, - const EthernetInterfaceData& ethData, - const DHCPParameters& v4dhcpParms, - const DHCPParameters& v6dhcpParms, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) - { - bool ipv4Active = translateDHCPEnabledToBool(ethData.DHCPEnabled, true); - bool ipv6Active = - translateDHCPEnabledToBool(ethData.DHCPEnabled, false); - - bool nextv4DHCPState = - v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active; + handleHostnamePatch(hostname, asyncResp); + handleDomainnamePatch(ifaceId, domainname, asyncResp); +} - bool nextv6DHCPState{}; - if (v6dhcpParms.dhcpv6OperatingMode) - { - if ((*v6dhcpParms.dhcpv6OperatingMode != "Stateful") && - (*v6dhcpParms.dhcpv6OperatingMode != "Stateless") && - (*v6dhcpParms.dhcpv6OperatingMode != "Disabled")) +void handleMACAddressPatch(const std::string& ifaceId, + const std::string& macAddress, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + crow::connections::systemBus->async_method_call( + [asyncResp, macAddress](const boost::system::error_code ec) { + if (ec) { - messages::propertyValueFormatError( - asyncResp->res, *v6dhcpParms.dhcpv6OperatingMode, - "OperatingMode"); + messages::internalError(asyncResp->res); return; } - nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Stateful"); - } - else - { - nextv6DHCPState = ipv6Active; - } + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.MACAddress", "MACAddress", + std::variant<std::string>(macAddress)); +} - bool nextDNS{}; - if (v4dhcpParms.useDNSServers && v6dhcpParms.useDNSServers) - { - if (*v4dhcpParms.useDNSServers != *v6dhcpParms.useDNSServers) +void setDHCPEnabled(const std::string& ifaceId, const std::string& propertyName, + const bool v4Value, const bool v6Value, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + const std::string dhcp = getDhcpEnabledEnumeration(v4Value, v6Value); + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) { - messages::generalError(asyncResp->res); + BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; + messages::internalError(asyncResp->res); return; } - nextDNS = *v4dhcpParms.useDNSServers; - } - else if (v4dhcpParms.useDNSServers) - { - nextDNS = *v4dhcpParms.useDNSServers; - } - else if (v6dhcpParms.useDNSServers) - { - nextDNS = *v6dhcpParms.useDNSServers; - } - else - { - nextDNS = ethData.DNSEnabled; - } + messages::success(asyncResp->res); + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.EthernetInterface", propertyName, + std::variant<std::string>{dhcp}); +} - bool nextNTP{}; - if (v4dhcpParms.useNTPServers && v6dhcpParms.useNTPServers) - { - if (*v4dhcpParms.useNTPServers != *v6dhcpParms.useNTPServers) +void setEthernetInterfaceBoolProperty( + const std::string& ifaceId, const std::string& propertyName, + const bool& value, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) { - messages::generalError(asyncResp->res); + BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; + messages::internalError(asyncResp->res); return; } - nextNTP = *v4dhcpParms.useNTPServers; - } - else if (v4dhcpParms.useNTPServers) - { - nextNTP = *v4dhcpParms.useNTPServers; - } - else if (v6dhcpParms.useNTPServers) - { - nextNTP = *v6dhcpParms.useNTPServers; - } - else - { - nextNTP = ethData.NTPEnabled; - } + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.EthernetInterface", propertyName, + std::variant<bool>{value}); +} - bool nextUseDomain{}; - if (v4dhcpParms.useUseDomainName && v6dhcpParms.useUseDomainName) - { - if (*v4dhcpParms.useUseDomainName != *v6dhcpParms.useUseDomainName) +void setDHCPv4Config(const std::string& propertyName, const bool& value, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + BMCWEB_LOG_DEBUG << propertyName << " = " << value; + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) { - messages::generalError(asyncResp->res); + BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; + messages::internalError(asyncResp->res); return; } - nextUseDomain = *v4dhcpParms.useUseDomainName; - } - else if (v4dhcpParms.useUseDomainName) + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/config/dhcp", + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.DHCPConfiguration", propertyName, + std::variant<bool>{value}); +} + +void handleDHCPPatch(const std::string& ifaceId, + const EthernetInterfaceData& ethData, + const DHCPParameters& v4dhcpParms, + const DHCPParameters& v6dhcpParms, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + bool ipv4Active = translateDHCPEnabledToBool(ethData.DHCPEnabled, true); + bool ipv6Active = translateDHCPEnabledToBool(ethData.DHCPEnabled, false); + + bool nextv4DHCPState = + v4dhcpParms.dhcpv4Enabled ? *v4dhcpParms.dhcpv4Enabled : ipv4Active; + + bool nextv6DHCPState{}; + if (v6dhcpParms.dhcpv6OperatingMode) + { + if ((*v6dhcpParms.dhcpv6OperatingMode != "Stateful") && + (*v6dhcpParms.dhcpv6OperatingMode != "Stateless") && + (*v6dhcpParms.dhcpv6OperatingMode != "Disabled")) { - nextUseDomain = *v4dhcpParms.useUseDomainName; + messages::propertyValueFormatError(asyncResp->res, + *v6dhcpParms.dhcpv6OperatingMode, + "OperatingMode"); + return; } - else if (v6dhcpParms.useUseDomainName) + nextv6DHCPState = (*v6dhcpParms.dhcpv6OperatingMode == "Stateful"); + } + else + { + nextv6DHCPState = ipv6Active; + } + + bool nextDNS{}; + if (v4dhcpParms.useDNSServers && v6dhcpParms.useDNSServers) + { + if (*v4dhcpParms.useDNSServers != *v6dhcpParms.useDNSServers) { - nextUseDomain = *v6dhcpParms.useUseDomainName; + messages::generalError(asyncResp->res); + return; } - else + nextDNS = *v4dhcpParms.useDNSServers; + } + else if (v4dhcpParms.useDNSServers) + { + nextDNS = *v4dhcpParms.useDNSServers; + } + else if (v6dhcpParms.useDNSServers) + { + nextDNS = *v6dhcpParms.useDNSServers; + } + else + { + nextDNS = ethData.DNSEnabled; + } + + bool nextNTP{}; + if (v4dhcpParms.useNTPServers && v6dhcpParms.useNTPServers) + { + if (*v4dhcpParms.useNTPServers != *v6dhcpParms.useNTPServers) { - nextUseDomain = ethData.HostNameEnabled; + messages::generalError(asyncResp->res); + return; } - - BMCWEB_LOG_DEBUG << "set DHCPEnabled..."; - setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState, - asyncResp); - BMCWEB_LOG_DEBUG << "set DNSEnabled..."; - setDHCPv4Config("DNSEnabled", nextDNS, asyncResp); - BMCWEB_LOG_DEBUG << "set NTPEnabled..."; - setDHCPv4Config("NTPEnabled", nextNTP, asyncResp); - BMCWEB_LOG_DEBUG << "set HostNameEnabled..."; - setDHCPv4Config("HostNameEnabled", nextUseDomain, asyncResp); + nextNTP = *v4dhcpParms.useNTPServers; } - - boost::container::flat_set<IPv4AddressData>::const_iterator - getNextStaticIpEntry( - const boost::container::flat_set<IPv4AddressData>::const_iterator& - head, - const boost::container::flat_set<IPv4AddressData>::const_iterator& - end) + else if (v4dhcpParms.useNTPServers) { - return std::find_if(head, end, [](const IPv4AddressData& value) { - return value.origin == "Static"; - }); + nextNTP = *v4dhcpParms.useNTPServers; } - - boost::container::flat_set<IPv6AddressData>::const_iterator - getNextStaticIpEntry( - const boost::container::flat_set<IPv6AddressData>::const_iterator& - head, - const boost::container::flat_set<IPv6AddressData>::const_iterator& - end) + else if (v6dhcpParms.useNTPServers) { - return std::find_if(head, end, [](const IPv6AddressData& value) { - return value.origin == "Static"; - }); + nextNTP = *v6dhcpParms.useNTPServers; + } + else + { + nextNTP = ethData.NTPEnabled; } - void handleIPv4StaticPatch( - const std::string& ifaceId, nlohmann::json& input, - const boost::container::flat_set<IPv4AddressData>& ipv4Data, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) + bool nextUseDomain{}; + if (v4dhcpParms.useUseDomainName && v6dhcpParms.useUseDomainName) { - if ((!input.is_array()) || input.empty()) + if (*v4dhcpParms.useUseDomainName != *v6dhcpParms.useUseDomainName) { - messages::propertyValueTypeError( - asyncResp->res, - input.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - "IPv4StaticAddresses"); + messages::generalError(asyncResp->res); return; } + nextUseDomain = *v4dhcpParms.useUseDomainName; + } + else if (v4dhcpParms.useUseDomainName) + { + nextUseDomain = *v4dhcpParms.useUseDomainName; + } + else if (v6dhcpParms.useUseDomainName) + { + nextUseDomain = *v6dhcpParms.useUseDomainName; + } + else + { + nextUseDomain = ethData.HostNameEnabled; + } - unsigned entryIdx = 1; - // Find the first static IP address currently active on the NIC and - // match it to the first JSON element in the IPv4StaticAddresses array. - // Match each subsequent JSON element to the next static IP programmed - // into the NIC. - boost::container::flat_set<IPv4AddressData>::const_iterator niciPentry = - getNextStaticIpEntry(ipv4Data.cbegin(), ipv4Data.cend()); + BMCWEB_LOG_DEBUG << "set DHCPEnabled..."; + setDHCPEnabled(ifaceId, "DHCPEnabled", nextv4DHCPState, nextv6DHCPState, + asyncResp); + BMCWEB_LOG_DEBUG << "set DNSEnabled..."; + setDHCPv4Config("DNSEnabled", nextDNS, asyncResp); + BMCWEB_LOG_DEBUG << "set NTPEnabled..."; + setDHCPv4Config("NTPEnabled", nextNTP, asyncResp); + BMCWEB_LOG_DEBUG << "set HostNameEnabled..."; + setDHCPv4Config("HostNameEnabled", nextUseDomain, asyncResp); +} + +boost::container::flat_set<IPv4AddressData>::const_iterator + getNextStaticIpEntry( + const boost::container::flat_set<IPv4AddressData>::const_iterator& head, + const boost::container::flat_set<IPv4AddressData>::const_iterator& end) +{ + return std::find_if(head, end, [](const IPv4AddressData& value) { + return value.origin == "Static"; + }); +} + +boost::container::flat_set<IPv6AddressData>::const_iterator + getNextStaticIpEntry( + const boost::container::flat_set<IPv6AddressData>::const_iterator& head, + const boost::container::flat_set<IPv6AddressData>::const_iterator& end) +{ + return std::find_if(head, end, [](const IPv6AddressData& value) { + return value.origin == "Static"; + }); +} + +void handleIPv4StaticPatch( + const std::string& ifaceId, nlohmann::json& input, + const boost::container::flat_set<IPv4AddressData>& ipv4Data, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + if ((!input.is_array()) || input.empty()) + { + messages::propertyValueTypeError( + asyncResp->res, + input.dump(2, ' ', true, nlohmann::json::error_handler_t::replace), + "IPv4StaticAddresses"); + return; + } - for (nlohmann::json& thisJson : input) + unsigned entryIdx = 1; + // Find the first static IP address currently active on the NIC and + // match it to the first JSON element in the IPv4StaticAddresses array. + // Match each subsequent JSON element to the next static IP programmed + // into the NIC. + boost::container::flat_set<IPv4AddressData>::const_iterator niciPentry = + getNextStaticIpEntry(ipv4Data.cbegin(), ipv4Data.cend()); + + for (nlohmann::json& thisJson : input) + { + std::string pathString = + "IPv4StaticAddresses/" + std::to_string(entryIdx); + + if (!thisJson.is_null() && !thisJson.empty()) { - std::string pathString = - "IPv4StaticAddresses/" + std::to_string(entryIdx); + std::optional<std::string> address; + std::optional<std::string> subnetMask; + std::optional<std::string> gateway; - if (!thisJson.is_null() && !thisJson.empty()) + if (!json_util::readJson(thisJson, asyncResp->res, "Address", + address, "SubnetMask", subnetMask, + "Gateway", gateway)) { - std::optional<std::string> address; - std::optional<std::string> subnetMask; - std::optional<std::string> gateway; - - if (!json_util::readJson(thisJson, asyncResp->res, "Address", - address, "SubnetMask", subnetMask, - "Gateway", gateway)) - { - messages::propertyValueFormatError( - asyncResp->res, - thisJson.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - pathString); - return; - } + messages::propertyValueFormatError( + asyncResp->res, + thisJson.dump(2, ' ', true, + nlohmann::json::error_handler_t::replace), + pathString); + return; + } - // Find the address/subnet/gateway values. Any values that are - // not explicitly provided are assumed to be unmodified from the - // current state of the interface. Merge existing state into the - // current request. - const std::string* addr = nullptr; - const std::string* gw = nullptr; - uint8_t prefixLength = 0; - bool errorInEntry = false; - if (address) - { - if (ipv4VerifyIpAndGetBitcount(*address)) - { - addr = &(*address); - } - else - { - messages::propertyValueFormatError( - asyncResp->res, *address, pathString + "/Address"); - errorInEntry = true; - } - } - else if (niciPentry != ipv4Data.cend()) + // Find the address/subnet/gateway values. Any values that are + // not explicitly provided are assumed to be unmodified from the + // current state of the interface. Merge existing state into the + // current request. + const std::string* addr = nullptr; + const std::string* gw = nullptr; + uint8_t prefixLength = 0; + bool errorInEntry = false; + if (address) + { + if (ipv4VerifyIpAndGetBitcount(*address)) { - addr = &(niciPentry->address); + addr = &(*address); } else { - messages::propertyMissing(asyncResp->res, - pathString + "/Address"); + messages::propertyValueFormatError(asyncResp->res, *address, + pathString + "/Address"); errorInEntry = true; } + } + else if (niciPentry != ipv4Data.cend()) + { + addr = &(niciPentry->address); + } + else + { + messages::propertyMissing(asyncResp->res, + pathString + "/Address"); + errorInEntry = true; + } - if (subnetMask) - { - if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) - { - messages::propertyValueFormatError( - asyncResp->res, *subnetMask, - pathString + "/SubnetMask"); - errorInEntry = true; - } - } - else if (niciPentry != ipv4Data.cend()) + if (subnetMask) + { + if (!ipv4VerifyIpAndGetBitcount(*subnetMask, &prefixLength)) { - if (!ipv4VerifyIpAndGetBitcount(niciPentry->netmask, - &prefixLength)) - { - messages::propertyValueFormatError( - asyncResp->res, niciPentry->netmask, - pathString + "/SubnetMask"); - errorInEntry = true; - } + messages::propertyValueFormatError( + asyncResp->res, *subnetMask, + pathString + "/SubnetMask"); + errorInEntry = true; } - else + } + else if (niciPentry != ipv4Data.cend()) + { + if (!ipv4VerifyIpAndGetBitcount(niciPentry->netmask, + &prefixLength)) { - messages::propertyMissing(asyncResp->res, - pathString + "/SubnetMask"); + messages::propertyValueFormatError( + asyncResp->res, niciPentry->netmask, + pathString + "/SubnetMask"); errorInEntry = true; } + } + else + { + messages::propertyMissing(asyncResp->res, + pathString + "/SubnetMask"); + errorInEntry = true; + } - if (gateway) - { - if (ipv4VerifyIpAndGetBitcount(*gateway)) - { - gw = &(*gateway); - } - else - { - messages::propertyValueFormatError( - asyncResp->res, *gateway, pathString + "/Gateway"); - errorInEntry = true; - } - } - else if (niciPentry != ipv4Data.cend()) + if (gateway) + { + if (ipv4VerifyIpAndGetBitcount(*gateway)) { - gw = &niciPentry->gateway; + gw = &(*gateway); } else { - messages::propertyMissing(asyncResp->res, - pathString + "/Gateway"); + messages::propertyValueFormatError(asyncResp->res, *gateway, + pathString + "/Gateway"); errorInEntry = true; } + } + else if (niciPentry != ipv4Data.cend()) + { + gw = &niciPentry->gateway; + } + else + { + messages::propertyMissing(asyncResp->res, + pathString + "/Gateway"); + errorInEntry = true; + } - if (errorInEntry) - { - return; - } + if (errorInEntry) + { + return; + } - if (niciPentry != ipv4Data.cend()) - { - deleteAndCreateIPv4(ifaceId, niciPentry->id, prefixLength, - *gw, *addr, asyncResp); - niciPentry = - getNextStaticIpEntry(++niciPentry, ipv4Data.cend()); - } - else - { - createIPv4(ifaceId, prefixLength, *gateway, *address, - asyncResp); - } - entryIdx++; + if (niciPentry != ipv4Data.cend()) + { + deleteAndCreateIPv4(ifaceId, niciPentry->id, prefixLength, *gw, + *addr, asyncResp); + niciPentry = + getNextStaticIpEntry(++niciPentry, ipv4Data.cend()); } else { - if (niciPentry == ipv4Data.cend()) + createIPv4(ifaceId, prefixLength, *gateway, *address, + asyncResp); + } + entryIdx++; + } + else + { + if (niciPentry == ipv4Data.cend()) + { + // Requesting a DELETE/DO NOT MODIFY action for an item + // that isn't present on the eth(n) interface. Input JSON is + // in error, so bail out. + if (thisJson.is_null()) { - // Requesting a DELETE/DO NOT MODIFY action for an item - // that isn't present on the eth(n) interface. Input JSON is - // in error, so bail out. - if (thisJson.is_null()) - { - messages::resourceCannotBeDeleted(asyncResp->res); - return; - } - messages::propertyValueFormatError( - asyncResp->res, - thisJson.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - pathString); + messages::resourceCannotBeDeleted(asyncResp->res); return; } + messages::propertyValueFormatError( + asyncResp->res, + thisJson.dump(2, ' ', true, + nlohmann::json::error_handler_t::replace), + pathString); + return; + } - if (thisJson.is_null()) - { - deleteIPv4(ifaceId, niciPentry->id, asyncResp); - } - if (niciPentry != ipv4Data.cend()) - { - niciPentry = - getNextStaticIpEntry(++niciPentry, ipv4Data.cend()); - } - entryIdx++; + if (thisJson.is_null()) + { + deleteIPv4(ifaceId, niciPentry->id, asyncResp); + } + if (niciPentry != ipv4Data.cend()) + { + niciPentry = + getNextStaticIpEntry(++niciPentry, ipv4Data.cend()); } + entryIdx++; } } +} - void handleStaticNameServersPatch( - const std::string& ifaceId, - const std::vector<std::string>& updatedStaticNameServers, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +void handleStaticNameServersPatch( + const std::string& ifaceId, + const std::vector<std::string>& updatedStaticNameServers, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + return; + } + }, + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.EthernetInterface", "StaticNameServers", + std::variant<std::vector<std::string>>{updatedStaticNameServers}); +} + +void handleIPv6StaticAddressesPatch( + const std::string& ifaceId, const nlohmann::json& input, + const boost::container::flat_set<IPv6AddressData>& ipv6Data, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + if (!input.is_array() || input.empty()) { - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - messages::internalError(asyncResp->res); - return; - } - }, - "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.EthernetInterface", - "StaticNameServers", - std::variant<std::vector<std::string>>{updatedStaticNameServers}); + messages::propertyValueTypeError( + asyncResp->res, + input.dump(2, ' ', true, nlohmann::json::error_handler_t::replace), + "IPv6StaticAddresses"); + return; } - - void handleIPv6StaticAddressesPatch( - const std::string& ifaceId, const nlohmann::json& input, - const boost::container::flat_set<IPv6AddressData>& ipv6Data, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) + size_t entryIdx = 1; + boost::container::flat_set<IPv6AddressData>::const_iterator niciPentry = + getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend()); + for (const nlohmann::json& thisJson : input) { - if (!input.is_array() || input.empty()) - { - messages::propertyValueTypeError( - asyncResp->res, - input.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - "IPv6StaticAddresses"); - return; - } - size_t entryIdx = 1; - boost::container::flat_set<IPv6AddressData>::const_iterator niciPentry = - getNextStaticIpEntry(ipv6Data.cbegin(), ipv6Data.cend()); - for (const nlohmann::json& thisJson : input) - { - std::string pathString = - "IPv6StaticAddresses/" + std::to_string(entryIdx); + std::string pathString = + "IPv6StaticAddresses/" + std::to_string(entryIdx); - if (!thisJson.is_null() && !thisJson.empty()) + if (!thisJson.is_null() && !thisJson.empty()) + { + std::optional<std::string> address; + std::optional<uint8_t> prefixLength; + nlohmann::json thisJsonCopy = thisJson; + if (!json_util::readJson(thisJsonCopy, asyncResp->res, "Address", + address, "PrefixLength", prefixLength)) { - std::optional<std::string> address; - std::optional<uint8_t> prefixLength; - nlohmann::json thisJsonCopy = thisJson; - if (!json_util::readJson(thisJsonCopy, asyncResp->res, - "Address", address, "PrefixLength", - prefixLength)) - { - messages::propertyValueFormatError( - asyncResp->res, - thisJson.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - pathString); - return; - } - - const std::string* addr; - uint8_t prefix; + messages::propertyValueFormatError( + asyncResp->res, + thisJson.dump(2, ' ', true, + nlohmann::json::error_handler_t::replace), + pathString); + return; + } - // Find the address and prefixLength values. Any values that are - // not explicitly provided are assumed to be unmodified from the - // current state of the interface. Merge existing state into the - // current request. - if (address) - { - addr = &(*address); - } - else if (niciPentry != ipv6Data.end()) - { - addr = &(niciPentry->address); - } - else - { - messages::propertyMissing(asyncResp->res, - pathString + "/Address"); - return; - } + const std::string* addr; + uint8_t prefix; - if (prefixLength) - { - prefix = *prefixLength; - } - else if (niciPentry != ipv6Data.end()) - { - prefix = niciPentry->prefixLength; - } - else - { - messages::propertyMissing(asyncResp->res, - pathString + "/PrefixLength"); - return; - } + // Find the address and prefixLength values. Any values that are + // not explicitly provided are assumed to be unmodified from the + // current state of the interface. Merge existing state into the + // current request. + if (address) + { + addr = &(*address); + } + else if (niciPentry != ipv6Data.end()) + { + addr = &(niciPentry->address); + } + else + { + messages::propertyMissing(asyncResp->res, + pathString + "/Address"); + return; + } - if (niciPentry != ipv6Data.end()) - { - deleteAndCreateIPv6(ifaceId, niciPentry->id, prefix, *addr, - asyncResp); - niciPentry = - getNextStaticIpEntry(++niciPentry, ipv6Data.cend()); - } - else - { - createIPv6(ifaceId, *prefixLength, *addr, asyncResp); - } - entryIdx++; + if (prefixLength) + { + prefix = *prefixLength; + } + else if (niciPentry != ipv6Data.end()) + { + prefix = niciPentry->prefixLength; } else { - if (niciPentry == ipv6Data.end()) - { - // Requesting a DELETE/DO NOT MODIFY action for an item - // that isn't present on the eth(n) interface. Input JSON is - // in error, so bail out. - if (thisJson.is_null()) - { - messages::resourceCannotBeDeleted(asyncResp->res); - return; - } - messages::propertyValueFormatError( - asyncResp->res, - thisJson.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace), - pathString); - return; - } + messages::propertyMissing(asyncResp->res, + pathString + "/PrefixLength"); + return; + } - if (thisJson.is_null()) - { - deleteIPv6(ifaceId, niciPentry->id, asyncResp); - } - if (niciPentry != ipv6Data.cend()) - { - niciPentry = - getNextStaticIpEntry(++niciPentry, ipv6Data.cend()); - } - entryIdx++; + if (niciPentry != ipv6Data.end()) + { + deleteAndCreateIPv6(ifaceId, niciPentry->id, prefix, *addr, + asyncResp); + niciPentry = + getNextStaticIpEntry(++niciPentry, ipv6Data.cend()); + } + else + { + createIPv6(ifaceId, *prefixLength, *addr, asyncResp); } + entryIdx++; } - } - - void parseInterfaceData( - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const std::string& ifaceId, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>& ipv4Data, - const boost::container::flat_set<IPv6AddressData>& ipv6Data) - { - constexpr const std::array<const char*, 1> inventoryForEthernet = { - "xyz.openbmc_project.Inventory.Item.Ethernet"}; - - nlohmann::json& jsonResponse = asyncResp->res.jsonValue; - jsonResponse["Id"] = ifaceId; - jsonResponse["@odata.id"] = - "/redfish/v1/Managers/bmc/EthernetInterfaces/" + ifaceId; - jsonResponse["InterfaceEnabled"] = ethData.nicEnabled; - - auto health = std::make_shared<HealthPopulate>(asyncResp); - - crow::connections::systemBus->async_method_call( - [health](const boost::system::error_code ec, - std::vector<std::string>& resp) { - if (ec) + else + { + if (niciPentry == ipv6Data.end()) + { + // Requesting a DELETE/DO NOT MODIFY action for an item + // that isn't present on the eth(n) interface. Input JSON is + // in error, so bail out. + if (thisJson.is_null()) { + messages::resourceCannotBeDeleted(asyncResp->res); return; } + messages::propertyValueFormatError( + asyncResp->res, + thisJson.dump(2, ' ', true, + nlohmann::json::error_handler_t::replace), + pathString); + return; + } - health->inventory = std::move(resp); - }, - "xyz.openbmc_project.ObjectMapper", - "/xyz/openbmc_project/object_mapper", - "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", - int32_t(0), inventoryForEthernet); - - health->populate(); - - if (ethData.nicEnabled) - { - jsonResponse["LinkStatus"] = "LinkUp"; - jsonResponse["Status"]["State"] = "Enabled"; - } - else - { - jsonResponse["LinkStatus"] = "NoLink"; - jsonResponse["Status"]["State"] = "Disabled"; - } - - jsonResponse["LinkStatus"] = ethData.linkUp ? "LinkUp" : "LinkDown"; - jsonResponse["SpeedMbps"] = ethData.speed; - jsonResponse["MACAddress"] = ethData.mac_address; - jsonResponse["DHCPv4"]["DHCPEnabled"] = - translateDHCPEnabledToBool(ethData.DHCPEnabled, true); - jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.NTPEnabled; - jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.DNSEnabled; - jsonResponse["DHCPv4"]["UseDomainName"] = ethData.HostNameEnabled; - - jsonResponse["DHCPv6"]["OperatingMode"] = - translateDHCPEnabledToBool(ethData.DHCPEnabled, false) ? "Stateful" - : "Disabled"; - jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.NTPEnabled; - jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.DNSEnabled; - jsonResponse["DHCPv6"]["UseDomainName"] = ethData.HostNameEnabled; - - if (!ethData.hostname.empty()) - { - jsonResponse["HostName"] = ethData.hostname; - - // When domain name is empty then it means, that it is a network - // without domain names, and the host name itself must be treated as - // FQDN - std::string fqdn = ethData.hostname; - if (!ethData.domainnames.empty()) + if (thisJson.is_null()) + { + deleteIPv6(ifaceId, niciPentry->id, asyncResp); + } + if (niciPentry != ipv6Data.cend()) { - fqdn += "." + ethData.domainnames[0]; + niciPentry = + getNextStaticIpEntry(++niciPentry, ipv6Data.cend()); } - jsonResponse["FQDN"] = fqdn; + entryIdx++; } + } +} - jsonResponse["VLANs"] = { - {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces/" + - ifaceId + "/VLANs"}}; - - jsonResponse["NameServers"] = ethData.nameServers; - jsonResponse["StaticNameServers"] = ethData.staticNameServers; +void parseInterfaceData( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& ifaceId, const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>& ipv4Data, + const boost::container::flat_set<IPv6AddressData>& ipv6Data) +{ + constexpr const std::array<const char*, 1> inventoryForEthernet = { + "xyz.openbmc_project.Inventory.Item.Ethernet"}; - nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"]; - nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"]; - ipv4Array = nlohmann::json::array(); - ipv4StaticArray = nlohmann::json::array(); - for (auto& ipv4Config : ipv4Data) - { + nlohmann::json& jsonResponse = asyncResp->res.jsonValue; + jsonResponse["Id"] = ifaceId; + jsonResponse["@odata.id"] = + "/redfish/v1/Managers/bmc/EthernetInterfaces/" + ifaceId; + jsonResponse["InterfaceEnabled"] = ethData.nicEnabled; - std::string gatewayStr = ipv4Config.gateway; - if (gatewayStr.empty()) - { - gatewayStr = "0.0.0.0"; - } + auto health = std::make_shared<HealthPopulate>(asyncResp); - ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin}, - {"SubnetMask", ipv4Config.netmask}, - {"Address", ipv4Config.address}, - {"Gateway", gatewayStr}}); - if (ipv4Config.origin == "Static") + crow::connections::systemBus->async_method_call( + [health](const boost::system::error_code ec, + std::vector<std::string>& resp) { + if (ec) { - ipv4StaticArray.push_back({{"AddressOrigin", ipv4Config.origin}, - {"SubnetMask", ipv4Config.netmask}, - {"Address", ipv4Config.address}, - {"Gateway", gatewayStr}}); + return; } - } - std::string ipv6GatewayStr = ethData.ipv6_default_gateway; - if (ipv6GatewayStr.empty()) - { - ipv6GatewayStr = "0:0:0:0:0:0:0:0"; - } + health->inventory = std::move(resp); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", int32_t(0), + inventoryForEthernet); - jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr; + health->populate(); - nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"]; - nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"]; - ipv6Array = nlohmann::json::array(); - ipv6StaticArray = nlohmann::json::array(); - nlohmann::json& ipv6AddrPolicyTable = - jsonResponse["IPv6AddressPolicyTable"]; - ipv6AddrPolicyTable = nlohmann::json::array(); - for (auto& ipv6Config : ipv6Data) - { - ipv6Array.push_back({{"Address", ipv6Config.address}, - {"PrefixLength", ipv6Config.prefixLength}, - {"AddressOrigin", ipv6Config.origin}, - {"AddressState", nullptr}}); - if (ipv6Config.origin == "Static") - { - ipv6StaticArray.push_back( - {{"Address", ipv6Config.address}, - {"PrefixLength", ipv6Config.prefixLength}, - {"AddressOrigin", ipv6Config.origin}, - {"AddressState", nullptr}}); - } - } + if (ethData.nicEnabled) + { + jsonResponse["LinkStatus"] = "LinkUp"; + jsonResponse["Status"]["State"] = "Enabled"; + } + else + { + jsonResponse["LinkStatus"] = "NoLink"; + jsonResponse["Status"]["State"] = "Disabled"; } - /** - * Functions triggers appropriate requests on DBus - */ - void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request&, - const std::vector<std::string>& params) override + jsonResponse["LinkStatus"] = ethData.linkUp ? "LinkUp" : "LinkDown"; + jsonResponse["SpeedMbps"] = ethData.speed; + jsonResponse["MACAddress"] = ethData.mac_address; + jsonResponse["DHCPv4"]["DHCPEnabled"] = + translateDHCPEnabledToBool(ethData.DHCPEnabled, true); + jsonResponse["DHCPv4"]["UseNTPServers"] = ethData.NTPEnabled; + jsonResponse["DHCPv4"]["UseDNSServers"] = ethData.DNSEnabled; + jsonResponse["DHCPv4"]["UseDomainName"] = ethData.HostNameEnabled; + + jsonResponse["DHCPv6"]["OperatingMode"] = + translateDHCPEnabledToBool(ethData.DHCPEnabled, false) ? "Stateful" + : "Disabled"; + jsonResponse["DHCPv6"]["UseNTPServers"] = ethData.NTPEnabled; + jsonResponse["DHCPv6"]["UseDNSServers"] = ethData.DNSEnabled; + jsonResponse["DHCPv6"]["UseDomainName"] = ethData.HostNameEnabled; + + if (!ethData.hostname.empty()) { - if (params.size() != 1) + jsonResponse["HostName"] = ethData.hostname; + + // When domain name is empty then it means, that it is a network + // without domain names, and the host name itself must be treated as + // FQDN + std::string fqdn = ethData.hostname; + if (!ethData.domainnames.empty()) { - messages::internalError(asyncResp->res); - return; + fqdn += "." + ethData.domainnames[0]; } + jsonResponse["FQDN"] = fqdn; + } - getEthernetIfaceData( - params[0], - [this, asyncResp, ifaceId{std::string(params[0])}]( - const bool& success, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>& ipv4Data, - const boost::container::flat_set<IPv6AddressData>& ipv6Data) { - if (!success) - { - // TODO(Pawel)consider distinguish between non existing - // object, and other errors - messages::resourceNotFound(asyncResp->res, - "EthernetInterface", ifaceId); - return; - } - - asyncResp->res.jsonValue["@odata.type"] = - "#EthernetInterface.v1_4_1.EthernetInterface"; - asyncResp->res.jsonValue["Name"] = "Manager Ethernet Interface"; - asyncResp->res.jsonValue["Description"] = - "Management Network Interface"; + jsonResponse["VLANs"] = { + {"@odata.id", + "/redfish/v1/Managers/bmc/EthernetInterfaces/" + ifaceId + "/VLANs"}}; - parseInterfaceData(asyncResp, ifaceId, ethData, ipv4Data, - ipv6Data); - }); - } + jsonResponse["NameServers"] = ethData.nameServers; + jsonResponse["StaticNameServers"] = ethData.staticNameServers; - void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request& req, - const std::vector<std::string>& params) override + nlohmann::json& ipv4Array = jsonResponse["IPv4Addresses"]; + nlohmann::json& ipv4StaticArray = jsonResponse["IPv4StaticAddresses"]; + ipv4Array = nlohmann::json::array(); + ipv4StaticArray = nlohmann::json::array(); + for (auto& ipv4Config : ipv4Data) { - if (params.size() != 1) + std::string gatewayStr = ipv4Config.gateway; + if (gatewayStr.empty()) { - messages::internalError(asyncResp->res); - return; + gatewayStr = "0.0.0.0"; } - const std::string& ifaceId = params[0]; - - std::optional<std::string> hostname; - std::optional<std::string> fqdn; - std::optional<std::string> macAddress; - std::optional<std::string> ipv6DefaultGateway; - std::optional<nlohmann::json> ipv4StaticAddresses; - std::optional<nlohmann::json> ipv6StaticAddresses; - std::optional<std::vector<std::string>> staticNameServers; - std::optional<nlohmann::json> dhcpv4; - std::optional<nlohmann::json> dhcpv6; - std::optional<bool> interfaceEnabled; - DHCPParameters v4dhcpParms; - DHCPParameters v6dhcpParms; - - if (!json_util::readJson( - req, asyncResp->res, "HostName", hostname, "FQDN", fqdn, - "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress", - macAddress, "StaticNameServers", staticNameServers, - "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses", - ipv6StaticAddresses, "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, - "InterfaceEnabled", interfaceEnabled)) + ipv4Array.push_back({{"AddressOrigin", ipv4Config.origin}, + {"SubnetMask", ipv4Config.netmask}, + {"Address", ipv4Config.address}, + {"Gateway", gatewayStr}}); + if (ipv4Config.origin == "Static") { - return; - } - if (dhcpv4) - { - if (!json_util::readJson(*dhcpv4, asyncResp->res, "DHCPEnabled", - v4dhcpParms.dhcpv4Enabled, "UseDNSServers", - v4dhcpParms.useDNSServers, "UseNTPServers", - v4dhcpParms.useNTPServers, "UseDomainName", - v4dhcpParms.useUseDomainName)) - { - return; - } + ipv4StaticArray.push_back({{"AddressOrigin", ipv4Config.origin}, + {"SubnetMask", ipv4Config.netmask}, + {"Address", ipv4Config.address}, + {"Gateway", gatewayStr}}); } + } + + std::string ipv6GatewayStr = ethData.ipv6_default_gateway; + if (ipv6GatewayStr.empty()) + { + ipv6GatewayStr = "0:0:0:0:0:0:0:0"; + } + + jsonResponse["IPv6DefaultGateway"] = ipv6GatewayStr; - if (dhcpv6) + nlohmann::json& ipv6Array = jsonResponse["IPv6Addresses"]; + nlohmann::json& ipv6StaticArray = jsonResponse["IPv6StaticAddresses"]; + ipv6Array = nlohmann::json::array(); + ipv6StaticArray = nlohmann::json::array(); + nlohmann::json& ipv6AddrPolicyTable = + jsonResponse["IPv6AddressPolicyTable"]; + ipv6AddrPolicyTable = nlohmann::json::array(); + for (auto& ipv6Config : ipv6Data) + { + ipv6Array.push_back({{"Address", ipv6Config.address}, + {"PrefixLength", ipv6Config.prefixLength}, + {"AddressOrigin", ipv6Config.origin}, + {"AddressState", nullptr}}); + if (ipv6Config.origin == "Static") { - if (!json_util::readJson(*dhcpv6, asyncResp->res, "OperatingMode", - v6dhcpParms.dhcpv6OperatingMode, - "UseDNSServers", v6dhcpParms.useDNSServers, - "UseNTPServers", v6dhcpParms.useNTPServers, - "UseDomainName", - v6dhcpParms.useUseDomainName)) - { - return; - } + ipv6StaticArray.push_back( + {{"Address", ipv6Config.address}, + {"PrefixLength", ipv6Config.prefixLength}, + {"AddressOrigin", ipv6Config.origin}, + {"AddressState", nullptr}}); } + } +} + +void parseInterfaceData(nlohmann::json& jsonResponse, + const std::string& parentIfaceId, + const std::string& ifaceId, + const EthernetInterfaceData& ethData) +{ + // Fill out obvious data... + jsonResponse["Id"] = ifaceId; + jsonResponse["@odata.id"] = "/redfish/v1/Managers/bmc/EthernetInterfaces/" + + parentIfaceId + "/VLANs/" + ifaceId; + + jsonResponse["VLANEnable"] = true; + if (!ethData.vlan_id.empty()) + { + jsonResponse["VLANId"] = ethData.vlan_id.back(); + } +} + +bool verifyNames(const std::string& parent, const std::string& iface) +{ + if (!boost::starts_with(iface, parent + "_")) + { + return false; + } + return true; +} - // Get single eth interface data, and call the below callback for - // JSON preparation - getEthernetIfaceData( - ifaceId, - [this, asyncResp, ifaceId, hostname = std::move(hostname), - fqdn = std::move(fqdn), macAddress = std::move(macAddress), - ipv4StaticAddresses = std::move(ipv4StaticAddresses), - ipv6DefaultGateway = std::move(ipv6DefaultGateway), - ipv6StaticAddresses = std::move(ipv6StaticAddresses), - staticNameServers = std::move(staticNameServers), - dhcpv4 = std::move(dhcpv4), dhcpv6 = std::move(dhcpv6), - v4dhcpParms = std::move(v4dhcpParms), - v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled]( - const bool& success, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>& ipv4Data, - const boost::container::flat_set<IPv6AddressData>& ipv6Data) { +inline void requestEthernetInterfacesRoutes(App& app) +{ + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/") + .privileges({"Login"}) + .methods( + boost::beast::http::verb:: + get)([](const crow::Request&, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { + asyncResp->res.jsonValue["@odata.type"] = + "#EthernetInterfaceCollection.EthernetInterfaceCollection"; + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Managers/bmc/EthernetInterfaces"; + asyncResp->res.jsonValue["Name"] = + "Ethernet Network Interface Collection"; + asyncResp->res.jsonValue["Description"] = + "Collection of EthernetInterfaces for this Manager"; + + // Get eth interface list, and call the below callback for JSON + // preparation + getEthernetIfaceList([asyncResp](const bool& success, + const boost::container::flat_set< + std::string>& ifaceList) { if (!success) { - // ... otherwise return error - // TODO(Pawel)consider distinguish between non existing - // object, and other errors - messages::resourceNotFound(asyncResp->res, - "Ethernet Interface", ifaceId); + messages::internalError(asyncResp->res); return; } - if (dhcpv4 || dhcpv6) - { - handleDHCPPatch(ifaceId, ethData, v4dhcpParms, v6dhcpParms, - asyncResp); - } - - if (hostname) + nlohmann::json& ifaceArray = + asyncResp->res.jsonValue["Members"]; + ifaceArray = nlohmann::json::array(); + std::string tag = "_"; + for (const std::string& ifaceItem : ifaceList) { - handleHostnamePatch(*hostname, asyncResp); + std::size_t found = ifaceItem.find(tag); + if (found == std::string::npos) + { + ifaceArray.push_back( + {{"@odata.id", + "/redfish/v1/Managers/bmc/EthernetInterfaces/" + + ifaceItem}}); + } } - if (fqdn) - { - handleFqdnPatch(ifaceId, *fqdn, asyncResp); - } + asyncResp->res.jsonValue["Members@odata.count"] = + ifaceArray.size(); + asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/Managers/bmc/EthernetInterfaces"; + }); + }); - if (macAddress) - { - handleMACAddressPatch(ifaceId, *macAddress, asyncResp); - } + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/") + .privileges({"Login"}) + .methods(boost::beast::http::verb::get)( + [](const crow::Request&, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& ifaceId) { + getEthernetIfaceData( + ifaceId, + [asyncResp, + ifaceId](const bool& success, + const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>& + ipv4Data, + const boost::container::flat_set<IPv6AddressData>& + ipv6Data) { + if (!success) + { + // TODO(Pawel)consider distinguish between non + // existing object, and other errors + messages::resourceNotFound( + asyncResp->res, "EthernetInterface", ifaceId); + return; + } - if (ipv4StaticAddresses) - { - // TODO(ed) for some reason the capture of ipv4Addresses - // above is returning a const value, not a non-const - // value. This doesn't really work for us, as we need to - // be able to efficiently move out the intermedia - // nlohmann::json objects. This makes a copy of the - // structure, and operates on that, but could be done - // more efficiently - nlohmann::json ipv4Static = *ipv4StaticAddresses; - handleIPv4StaticPatch(ifaceId, ipv4Static, ipv4Data, - asyncResp); - } + asyncResp->res.jsonValue["@odata.type"] = + "#EthernetInterface.v1_4_1.EthernetInterface"; + asyncResp->res.jsonValue["Name"] = + "Manager Ethernet Interface"; + asyncResp->res.jsonValue["Description"] = + "Management Network Interface"; - if (staticNameServers) - { - handleStaticNameServersPatch(ifaceId, *staticNameServers, - asyncResp); - } + parseInterfaceData(asyncResp, ifaceId, ethData, + ipv4Data, ipv6Data); + }); + }); - if (ipv6DefaultGateway) + BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/") + .privileges({"ConfigureComponents"}) + .methods(boost::beast::http::verb::patch)( + [](const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& ifaceId) { + std::optional<std::string> hostname; + std::optional<std::string> fqdn; + std::optional<std::string> macAddress; + std::optional<std::string> ipv6DefaultGateway; + std::optional<nlohmann::json> ipv4StaticAddresses; + std::optional<nlohmann::json> ipv6StaticAddresses; + std::optional<std::vector<std::string>> staticNameServers; + std::optional<nlohmann::json> dhcpv4; + std::optional<nlohmann::json> dhcpv6; + std::optional<bool> interfaceEnabled; + DHCPParameters v4dhcpParms; + DHCPParameters v6dhcpParms; + + if (!json_util::readJson( + req, asyncResp->res, "HostName", hostname, "FQDN", fqdn, + "IPv4StaticAddresses", ipv4StaticAddresses, + "MACAddress", macAddress, "StaticNameServers", + staticNameServers, "IPv6DefaultGateway", + ipv6DefaultGateway, "IPv6StaticAddresses", + ipv6StaticAddresses, "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, + "InterfaceEnabled", interfaceEnabled)) { - messages::propertyNotWritable(asyncResp->res, - "IPv6DefaultGateway"); + return; } - - if (ipv6StaticAddresses) + if (dhcpv4) { - nlohmann::json ipv6Static = *ipv6StaticAddresses; - handleIPv6StaticAddressesPatch(ifaceId, ipv6Static, - ipv6Data, asyncResp); + if (!json_util::readJson( + *dhcpv4, asyncResp->res, "DHCPEnabled", + v4dhcpParms.dhcpv4Enabled, "UseDNSServers", + v4dhcpParms.useDNSServers, "UseNTPServers", + v4dhcpParms.useNTPServers, "UseDomainName", + v4dhcpParms.useUseDomainName)) + { + return; + } } - if (interfaceEnabled) + if (dhcpv6) { - setEthernetInterfaceBoolProperty( - ifaceId, "NICEnabled", *interfaceEnabled, asyncResp); + if (!json_util::readJson( + *dhcpv6, asyncResp->res, "OperatingMode", + v6dhcpParms.dhcpv6OperatingMode, "UseDNSServers", + v6dhcpParms.useDNSServers, "UseNTPServers", + v6dhcpParms.useNTPServers, "UseDomainName", + v6dhcpParms.useUseDomainName)) + { + return; + } } - }); - } -}; -/** - * VlanNetworkInterface derived class for delivering VLANNetworkInterface - * Schema - */ -class VlanNetworkInterface : public Node -{ - public: - /* - * Default Constructor - */ - VlanNetworkInterface(App& app) : - Node(app, - "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/", - std::string(), std::string()) - { - entityPrivileges = { - {boost::beast::http::verb::get, {{"Login"}}}, - {boost::beast::http::verb::head, {{"Login"}}}, - {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; - } - - private: - void parseInterfaceData(nlohmann::json& jsonResponse, - const std::string& parentIfaceId, - const std::string& ifaceId, - const EthernetInterfaceData& ethData) - { - // Fill out obvious data... - jsonResponse["Id"] = ifaceId; - jsonResponse["@odata.id"] = - "/redfish/v1/Managers/bmc/EthernetInterfaces/" + parentIfaceId + - "/VLANs/" + ifaceId; - - jsonResponse["VLANEnable"] = true; - if (!ethData.vlan_id.empty()) - { - jsonResponse["VLANId"] = ethData.vlan_id.back(); - } - } - - bool verifyNames(const std::string& parent, const std::string& iface) - { - if (!boost::starts_with(iface, parent + "_")) - { - return false; - } - return true; - } + // Get single eth interface data, and call the below callback + // for JSON preparation + getEthernetIfaceData( + ifaceId, + [asyncResp, ifaceId, hostname = std::move(hostname), + fqdn = std::move(fqdn), macAddress = std::move(macAddress), + ipv4StaticAddresses = std::move(ipv4StaticAddresses), + ipv6DefaultGateway = std::move(ipv6DefaultGateway), + ipv6StaticAddresses = std::move(ipv6StaticAddresses), + staticNameServers = std::move(staticNameServers), + dhcpv4 = std::move(dhcpv4), dhcpv6 = std::move(dhcpv6), + v4dhcpParms = std::move(v4dhcpParms), + v6dhcpParms = std::move(v6dhcpParms), interfaceEnabled]( + const bool& success, + const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>& + ipv4Data, + const boost::container::flat_set<IPv6AddressData>& + ipv6Data) { + if (!success) + { + // ... otherwise return error + // TODO(Pawel)consider distinguish between non + // existing object, and other errors + messages::resourceNotFound( + asyncResp->res, "Ethernet Interface", ifaceId); + return; + } - /** - * Functions triggers appropriate requests on DBus - */ - void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request&, - const std::vector<std::string>& params) override - { - // TODO(Pawel) this shall be parameterized call (two params) to get - // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'. - // Check if there is required param, truly entering this shall be - // impossible. - if (params.size() != 2) - { - messages::internalError(asyncResp->res); - return; - } + if (dhcpv4 || dhcpv6) + { + handleDHCPPatch(ifaceId, ethData, v4dhcpParms, + v6dhcpParms, asyncResp); + } - const std::string& parentIfaceId = params[0]; - const std::string& ifaceId = params[1]; - asyncResp->res.jsonValue["@odata.type"] = - "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; - asyncResp->res.jsonValue["Name"] = "VLAN Network Interface"; + if (hostname) + { + handleHostnamePatch(*hostname, asyncResp); + } - if (!verifyNames(parentIfaceId, ifaceId)) - { - return; - } + if (fqdn) + { + handleFqdnPatch(ifaceId, *fqdn, asyncResp); + } - // Get single eth interface data, and call the below callback for - // JSON preparation - getEthernetIfaceData( - params[1], - [this, asyncResp, parentIfaceId{std::string(params[0])}, - ifaceId{std::string(params[1])}]( - const bool& success, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>&, - const boost::container::flat_set<IPv6AddressData>&) { - if (success && ethData.vlan_id.size() != 0) - { - parseInterfaceData(asyncResp->res.jsonValue, parentIfaceId, - ifaceId, ethData); - } - else - { - // ... otherwise return error - // TODO(Pawel)consider distinguish between non existing - // object, and other errors - messages::resourceNotFound( - asyncResp->res, "VLAN Network Interface", ifaceId); - } - }); - } + if (macAddress) + { + handleMACAddressPatch(ifaceId, *macAddress, + asyncResp); + } - void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request& req, - const std::vector<std::string>& params) override - { + if (ipv4StaticAddresses) + { + // TODO(ed) for some reason the capture of + // ipv4Addresses above is returning a const value, + // not a non-const value. This doesn't really work + // for us, as we need to be able to efficiently move + // out the intermedia nlohmann::json objects. This + // makes a copy of the structure, and operates on + // that, but could be done more efficiently + nlohmann::json ipv4Static = *ipv4StaticAddresses; + handleIPv4StaticPatch(ifaceId, ipv4Static, ipv4Data, + asyncResp); + } - if (params.size() != 2) - { - messages::internalError(asyncResp->res); - return; - } + if (staticNameServers) + { + handleStaticNameServersPatch( + ifaceId, *staticNameServers, asyncResp); + } - const std::string& parentIfaceId = params[0]; - const std::string& ifaceId = params[1]; + if (ipv6DefaultGateway) + { + messages::propertyNotWritable(asyncResp->res, + "IPv6DefaultGateway"); + } - if (!verifyNames(parentIfaceId, ifaceId)) - { - messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", - ifaceId); - return; - } + if (ipv6StaticAddresses) + { + nlohmann::json ipv6Static = *ipv6StaticAddresses; + handleIPv6StaticAddressesPatch(ifaceId, ipv6Static, + ipv6Data, asyncResp); + } - bool vlanEnable = false; - uint32_t vlanId = 0; + if (interfaceEnabled) + { + setEthernetInterfaceBoolProperty( + ifaceId, "NICEnabled", *interfaceEnabled, + asyncResp); + } + }); + }); - if (!json_util::readJson(req, asyncResp->res, "VLANEnable", vlanEnable, - "VLANId", vlanId)) - { - return; - } + BMCWEB_ROUTE( + app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/") + .privileges({"Login"}) + .methods(boost::beast::http::verb::get)( + [](const crow::Request& /* req */, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& parentIfaceId, const std::string& ifaceId) { + asyncResp->res.jsonValue["@odata.type"] = + "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface"; + asyncResp->res.jsonValue["Name"] = "VLAN Network Interface"; - // Get single eth interface data, and call the below callback for - // JSON preparation - getEthernetIfaceData( - params[1], - [asyncResp, parentIfaceId{std::string(params[0])}, - ifaceId{std::string(params[1])}, &vlanEnable, - &vlanId](const bool& success, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>&, - const boost::container::flat_set<IPv6AddressData>&) { - if (success && !ethData.vlan_id.empty()) + if (!verifyNames(parentIfaceId, ifaceId)) { - auto callback = - [asyncResp](const boost::system::error_code ec) { - if (ec) - { - messages::internalError(asyncResp->res); - } - }; - - if (vlanEnable == true) - { - crow::connections::systemBus->async_method_call( - std::move(callback), "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network/" + ifaceId, - "org.freedesktop.DBus.Properties", "Set", - "xyz.openbmc_project.Network.VLAN", "Id", - std::variant<uint32_t>(vlanId)); - } - else - { - BMCWEB_LOG_DEBUG << "vlanEnable is false. Deleting the " - "vlan interface"; - crow::connections::systemBus->async_method_call( - std::move(callback), "xyz.openbmc_project.Network", - std::string("/xyz/openbmc_project/network/") + - ifaceId, - "xyz.openbmc_project.Object.Delete", "Delete"); - } + return; } - else + + // Get single eth interface data, and call the below callback + // for JSON preparation + getEthernetIfaceData( + ifaceId, + [asyncResp, parentIfaceId, ifaceId]( + const bool& success, + const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>&, + const boost::container::flat_set<IPv6AddressData>&) { + if (success && ethData.vlan_id.size() != 0) + { + parseInterfaceData(asyncResp->res.jsonValue, + parentIfaceId, ifaceId, ethData); + } + else + { + // ... otherwise return error + // TODO(Pawel)consider distinguish between non + // existing object, and other errors + messages::resourceNotFound(asyncResp->res, + "VLAN Network Interface", + ifaceId); + } + }); + }); + + BMCWEB_ROUTE( + app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/") + .privileges({"ConfigureComponents"}) + .methods(boost::beast::http::verb::patch)( + [](const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& parentIfaceId, const std::string& ifaceId) { + if (!verifyNames(parentIfaceId, ifaceId)) { - // TODO(Pawel)consider distinguish between non existing - // object, and other errors messages::resourceNotFound( asyncResp->res, "VLAN Network Interface", ifaceId); return; } - }); - } - - void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request&, - const std::vector<std::string>& params) override - { - if (params.size() != 2) - { - messages::internalError(asyncResp->res); - return; - } - const std::string& parentIfaceId = params[0]; - const std::string& ifaceId = params[1]; + bool vlanEnable = false; + uint32_t vlanId = 0; - if (!verifyNames(parentIfaceId, ifaceId)) - { - messages::resourceNotFound(asyncResp->res, "VLAN Network Interface", - ifaceId); - return; - } - - // Get single eth interface data, and call the below callback for - // JSON preparation - getEthernetIfaceData( - params[1], - [asyncResp, parentIfaceId{std::string(params[0])}, - ifaceId{std::string(params[1])}]( - const bool& success, const EthernetInterfaceData& ethData, - const boost::container::flat_set<IPv4AddressData>&, - const boost::container::flat_set<IPv6AddressData>&) { - if (success && !ethData.vlan_id.empty()) + if (!json_util::readJson(req, asyncResp->res, "VLANEnable", + vlanEnable, "VLANId", vlanId)) { - auto callback = - [asyncResp](const boost::system::error_code ec) { - if (ec) + return; + } + + // Get single eth interface data, and call the below callback + // for JSON preparation + getEthernetIfaceData( + ifaceId, + [asyncResp, parentIfaceId, ifaceId, &vlanEnable, &vlanId]( + const bool& success, + const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>&, + const boost::container::flat_set<IPv6AddressData>&) { + if (success && !ethData.vlan_id.empty()) + { + auto callback = + [asyncResp]( + const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + } + }; + + if (vlanEnable == true) { - messages::internalError(asyncResp->res); + crow::connections::systemBus->async_method_call( + std::move(callback), + "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network/" + ifaceId, + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Network.VLAN", "Id", + std::variant<uint32_t>(vlanId)); } - }; - crow::connections::systemBus->async_method_call( - std::move(callback), "xyz.openbmc_project.Network", - std::string("/xyz/openbmc_project/network/") + ifaceId, - "xyz.openbmc_project.Object.Delete", "Delete"); - } - else + else + { + BMCWEB_LOG_DEBUG + << "vlanEnable is false. Deleting the " + "vlan interface"; + crow::connections::systemBus->async_method_call( + std::move(callback), + "xyz.openbmc_project.Network", + std::string( + "/xyz/openbmc_project/network/") + + ifaceId, + "xyz.openbmc_project.Object.Delete", + "Delete"); + } + } + else + { + // TODO(Pawel)consider distinguish between non + // existing object, and other errors + messages::resourceNotFound(asyncResp->res, + "VLAN Network Interface", + ifaceId); + return; + } + }); + }); + + BMCWEB_ROUTE( + app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/<str>/") + .privileges({"ConfigureComponents"}) + .methods(boost::beast::http::verb::delete_)( + [](const crow::Request& /* req */, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& parentIfaceId, const std::string& ifaceId) { + if (!verifyNames(parentIfaceId, ifaceId)) { - // ... otherwise return error - // TODO(Pawel)consider distinguish between non existing - // object, and other errors messages::resourceNotFound( asyncResp->res, "VLAN Network Interface", ifaceId); + return; } - }); - } -}; - -/** - * VlanNetworkInterfaceCollection derived class for delivering - * VLANNetworkInterface Collection Schema - */ -class VlanNetworkInterfaceCollection : public Node -{ - public: - VlanNetworkInterfaceCollection(App& app) : - Node(app, "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/", - std::string()) - { - entityPrivileges = { - {boost::beast::http::verb::get, {{"Login"}}}, - {boost::beast::http::verb::head, {{"Login"}}}, - {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, - {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; - } - - private: - /** - * Functions triggers appropriate requests on DBus - */ - void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request&, - const std::vector<std::string>& params) override - { - if (params.size() != 1) - { - // This means there is a problem with the router - messages::internalError(asyncResp->res); - return; - } - const std::string& rootInterfaceName = params[0]; + // Get single eth interface data, and call the below callback + // for JSON preparation + getEthernetIfaceData( + ifaceId, + [asyncResp, parentIfaceId, ifaceId]( + const bool& success, + const EthernetInterfaceData& ethData, + const boost::container::flat_set<IPv4AddressData>&, + const boost::container::flat_set<IPv6AddressData>&) { + if (success && !ethData.vlan_id.empty()) + { + auto callback = + [asyncResp]( + const boost::system::error_code ec) { + if (ec) + { + messages::internalError(asyncResp->res); + } + }; + crow::connections::systemBus->async_method_call( + std::move(callback), + "xyz.openbmc_project.Network", + std::string("/xyz/openbmc_project/network/") + + ifaceId, + "xyz.openbmc_project.Object.Delete", "Delete"); + } + else + { + // ... otherwise return error + // TODO(Pawel)consider distinguish between non + // existing object, and other errors + messages::resourceNotFound(asyncResp->res, + "VLAN Network Interface", + ifaceId); + } + }); + }); - // Get eth interface list, and call the below callback for JSON - // preparation - getEthernetIfaceList( - [asyncResp, rootInterfaceName{std::string(rootInterfaceName)}]( - const bool& success, - const boost::container::flat_set<std::string>& ifaceList) { + BMCWEB_ROUTE(app, + "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/") + .privileges({"Login"}) + .methods( + boost::beast::http::verb:: + get)([](const crow::Request& /* req */, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& rootInterfaceName) { + // Get eth interface list, and call the below callback for JSON + // preparation + getEthernetIfaceList([asyncResp, rootInterfaceName]( + const bool& success, + const boost::container::flat_set< + std::string>& ifaceList) { if (!success) { messages::internalError(asyncResp->res); @@ -2420,54 +2293,53 @@ class VlanNetworkInterfaceCollection : public Node "/redfish/v1/Managers/bmc/EthernetInterfaces/" + rootInterfaceName + "/VLANs"; }); - } + }); - void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const crow::Request& req, - const std::vector<std::string>& params) override - { - if (params.size() != 1) - { - messages::internalError(asyncResp->res); - return; - } - bool vlanEnable = false; - uint32_t vlanId = 0; - if (!json_util::readJson(req, asyncResp->res, "VLANId", vlanId, - "VLANEnable", vlanEnable)) - { - return; - } - // Need both vlanId and vlanEnable to service this request - if (!vlanId) - { - messages::propertyMissing(asyncResp->res, "VLANId"); - } - if (!vlanEnable) - { - messages::propertyMissing(asyncResp->res, "VLANEnable"); - } - if (static_cast<bool>(vlanId) ^ vlanEnable) - { - return; - } + BMCWEB_ROUTE(app, + "/redfish/v1/Managers/bmc/EthernetInterfaces/<str>/VLANs/") + .privileges({"ConfigureComponents"}) + .methods(boost::beast::http::verb::post)( + [](const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& rootInterfaceName) { + bool vlanEnable = false; + uint32_t vlanId = 0; + if (!json_util::readJson(req, asyncResp->res, "VLANId", vlanId, + "VLANEnable", vlanEnable)) + { + return; + } + // Need both vlanId and vlanEnable to service this request + if (!vlanId) + { + messages::propertyMissing(asyncResp->res, "VLANId"); + } + if (!vlanEnable) + { + messages::propertyMissing(asyncResp->res, "VLANEnable"); + } + if (static_cast<bool>(vlanId) ^ vlanEnable) + { + return; + } + + auto callback = + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + // TODO(ed) make more consistent error messages + // based on phosphor-network responses + messages::internalError(asyncResp->res); + return; + } + messages::created(asyncResp->res); + }; + crow::connections::systemBus->async_method_call( + std::move(callback), "xyz.openbmc_project.Network", + "/xyz/openbmc_project/network", + "xyz.openbmc_project.Network.VLAN.Create", "VLAN", + rootInterfaceName, vlanId); + }); +} - const std::string& rootInterfaceName = params[0]; - auto callback = [asyncResp](const boost::system::error_code ec) { - if (ec) - { - // TODO(ed) make more consistent error messages based on - // phosphor-network responses - messages::internalError(asyncResp->res); - return; - } - messages::created(asyncResp->res); - }; - crow::connections::systemBus->async_method_call( - std::move(callback), "xyz.openbmc_project.Network", - "/xyz/openbmc_project/network", - "xyz.openbmc_project.Network.VLAN.Create", "VLAN", - rootInterfaceName, vlanId); - } -}; } // namespace redfish diff --git a/redfish-core/lib/hypervisor_system.hpp b/redfish-core/lib/hypervisor_system.hpp index db6c0c2d7a..0e0629d153 100644 --- a/redfish-core/lib/hypervisor_system.hpp +++ b/redfish-core/lib/hypervisor_system.hpp @@ -673,21 +673,6 @@ inline void handleHypervisorIPv4StaticPatch( } } -inline bool isHostnameValid(const std::string& hostName) -{ - // As per RFC 1123 - // Allow up to 255 characters - if (hostName.length() > 255) - { - return false; - } - // Validate the regex - const std::regex pattern( - "^[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]$"); - - return std::regex_match(hostName, pattern); -} - inline void handleHostnamePatch(const std::string& hostName, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |