From ab6554f1d8197753cfb430a72798dde6f4461552 Mon Sep 17 00:00:00 2001 From: Joshi-Mansi Date: Tue, 10 Mar 2020 18:33:36 +0530 Subject: [Redfish-Ethernet Inf] Enable Read/Write for FQDN Enabling read/write requirement of FQDN in Ethernet Interface Schema to make it OCP compliant. Tested: 1. Tested using PATCH: - https://bmc-ip/redfish/v1/Managers/bmc/EthernetInterfaces/eth-id {"FQDN": "hostname.domainname"} GET Response- "FQDN": "hostname.domainname" //Success - When given invalid hostname/domainname Error Message "propertyValueFormatError" 2. Ran the Redfish validator and no new issues found. Signed-off-by: Joshi-Mansi Change-Id: Ief2e94f8b499be59196b0e7073ceffe8d49268ca --- redfish-core/lib/ethernet.hpp | 116 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 10 deletions(-) (limited to 'redfish-core') diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp index 0a2a1858b7..56e1a1508b 100644 --- a/redfish-core/lib/ethernet.hpp +++ b/redfish-core/lib/ethernet.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1084,7 +1085,13 @@ class EthernetInterface : public Node void handleHostnamePatch(const std::string &hostname, const std::shared_ptr asyncResp) { - asyncResp->res.jsonValue["HostName"] = hostname; + // 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) @@ -1099,6 +1106,84 @@ class EthernetInterface : public Node std::variant(hostname)); } + void handleDomainnamePatch(const std::string &ifaceId, + const std::string &domainname, + const std::shared_ptr asyncResp) + { + std::vector 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>(vectorDomainname)); + } + + void handleFqdnPatch(const std::string &ifaceId, const std::string &fqdn, + const std::shared_ptr 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); + } + + 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)) + { + 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,}$"); + + return std::regex_match(domainname, pattern); + } + void handleMACAddressPatch(const std::string &ifaceId, const std::string &macAddress, const std::shared_ptr &asyncResp) @@ -1705,11 +1790,16 @@ class EthernetInterface : public Node if (!ethData.hostname.empty()) { json_response["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 = std::move(ethData.hostname); if (!ethData.domainnames.empty()) { - json_response["FQDN"] = - ethData.hostname + "." + ethData.domainnames[0]; + FQDN += "." + ethData.domainnames[0]; } + json_response["FQDN"] = FQDN; } json_response["VLANs"] = { @@ -1828,6 +1918,7 @@ class EthernetInterface : public Node const std::string &iface_id = params[0]; std::optional hostname; + std::optional fqdn; std::optional macAddress; std::optional ipv6DefaultGateway; std::optional ipv4StaticAddresses; @@ -1840,12 +1931,12 @@ class EthernetInterface : public Node DHCPParameters v6dhcpParms; if (!json_util::readJson( - req, res, "HostName", hostname, "IPv4StaticAddresses", - ipv4StaticAddresses, "MACAddress", macAddress, - "StaticNameServers", staticNameServers, "IPv6DefaultGateway", - ipv6DefaultGateway, "IPv6StaticAddresses", ipv6StaticAddresses, - "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, "InterfaceEnabled", - interfaceEnabled)) + req, res, "HostName", hostname, "FQDN", fqdn, + "IPv4StaticAddresses", ipv4StaticAddresses, "MACAddress", + macAddress, "StaticNameServers", staticNameServers, + "IPv6DefaultGateway", ipv6DefaultGateway, "IPv6StaticAddresses", + ipv6StaticAddresses, "DHCPv4", dhcpv4, "DHCPv6", dhcpv6, + "InterfaceEnabled", interfaceEnabled)) { return; } @@ -1879,7 +1970,7 @@ class EthernetInterface : public Node getEthernetIfaceData( iface_id, [this, asyncResp, iface_id, hostname = std::move(hostname), - macAddress = std::move(macAddress), + fqdn = std::move(fqdn), macAddress = std::move(macAddress), ipv4StaticAddresses = std::move(ipv4StaticAddresses), ipv6DefaultGateway = std::move(ipv6DefaultGateway), ipv6StaticAddresses = std::move(ipv6StaticAddresses), @@ -1912,6 +2003,11 @@ class EthernetInterface : public Node handleHostnamePatch(*hostname, asyncResp); } + if (fqdn) + { + handleFqdnPatch(iface_id, *fqdn, asyncResp); + } + if (macAddress) { handleMACAddressPatch(iface_id, *macAddress, asyncResp); -- cgit v1.2.3