From dcb106713ca9dd63db9f88c4fe92d543e927388d Mon Sep 17 00:00:00 2001 From: Ratan Gupta Date: Mon, 10 Jul 2017 10:33:50 +0530 Subject: Make changes as per the new settings infrastructure Host network config will be referring to xyz settings namespace. Resolves openbmc/openbmc#1678 Resolves openbmc/openbmc#556 Change-Id: I77e4b015595990b3f44733ff4977b462ddf9a70a Signed-off-by: Ratan Gupta --- chassishandler.cpp | 634 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 383 insertions(+), 251 deletions(-) (limited to 'chassishandler.cpp') diff --git a/chassishandler.cpp b/chassishandler.cpp index 903926e..0b991fd 100644 --- a/chassishandler.cpp +++ b/chassishandler.cpp @@ -1,5 +1,7 @@ #include "chassishandler.h" #include "host-ipmid/ipmid-api.h" +#include "types.hpp" + #include #include #include @@ -13,8 +15,16 @@ #include #include #include +#include + #include +#include #include +#include "xyz/openbmc_project/Common/error.hpp" + +#include +#include + #include "config.h" //Defines @@ -46,8 +56,6 @@ static constexpr size_t IPADDR_OFFSET = 17; static constexpr size_t PREFIX_OFFSET = 21; static constexpr size_t GATEWAY_OFFSET = 22; -using namespace phosphor::logging; - void register_netfn_chassis_functions() __attribute__((constructor)); @@ -57,6 +65,22 @@ const char *settings_object_name = "/org/openbmc/settings/host0"; const char *settings_intf_name = "org.freedesktop.DBus.Properties"; const char *host_intf_name = "org.openbmc.settings.Host"; + +constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper"; +constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper"; +constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper"; + +constexpr auto SETTINGS_ROOT = "/"; +constexpr auto SETTINGS_MATCH = "host0"; +constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties"; + +constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; +constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; + +constexpr auto METHOD_GET = "Get"; +constexpr auto METHOD_GET_ALL = "GetAll"; +constexpr auto METHOD_SET = "Set"; + typedef struct { uint8_t cap_flags; @@ -80,6 +104,208 @@ namespace State = sdbusplus::xyz::openbmc_project::State::server; namespace fs = std::experimental::filesystem; +using namespace phosphor::logging; +using namespace sdbusplus::xyz::openbmc_project::Common::Error; + +/** @brief Gets the dbus object info implementing the given interface + * from the given subtree. + * @param[in] interface - Dbus interface. + * @param[in] serviceRoot - subtree from where the search should start. + * @param[in] match - identifier for object. + * @return On success returns the object having objectpath and servicename. + */ + +//TODO There may be cases where an interface is implemented by multiple +// objects,to handle such cases we are interested on that object +// which are on interested busname. +// Currently mapper doesn't give the readable busname(gives busid) so we can't +// use busname to find the object,will do later once the support is there. + +ipmi::DbusObjectInfo getDbusObject(const std::string& interface, + const std::string& serviceRoot = SETTINGS_ROOT, + const std::string& match = "") +{ + std::vectorinterfaces; + interfaces.emplace_back(interface); + + auto bus = sdbusplus::bus::new_default(); + auto depth = 0; + + auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME, + MAPPER_OBJ, + MAPPER_INTF, + "GetSubTree"); + + mapperCall.append(serviceRoot); + mapperCall.append(depth); + mapperCall.append(interfaces); + + auto mapperReply = bus.call(mapperCall); + if (mapperReply.is_method_error()) + { + log("Error in mapper call"); + elog(); + } + + ipmi::ObjectTree objectTree; + mapperReply.read(objectTree); + + if (objectTree.empty()) + { + log("No Object have impelmented the interface", + entry("INTERFACE=%s", interface.c_str())); + elog(); + } + + ipmi::DbusObjectInfo objectInfo; + + // if match is empty then return the first object + if(match == "") + { + objectInfo = make_pair(objectTree.begin()->first, + objectTree.begin()->second.begin()->first); + return objectInfo; + } + + // else search the match string in the object path + auto objectFound = false; + for (auto& object : objectTree) + { + if(object.first.find(match)!= std::string::npos) + { + objectFound = true; + objectInfo = make_pair(object.first, object.second.begin()->first); + break; + } + } + + if(!objectFound) + { + log("Failed to find object which matches", + entry("MATCH=%s",match.c_str())); + elog(); + } + return objectInfo; + +} + +/** @brief Gets the value associated with the given object + * and the interface. + * @param[in] service - Dbus service name. + * @param[in] objPath - Dbus object path. + * @param[in] interface - Dbus interface. + * @param[in] property - name of the property. + * @return On success returns the value of the property. + */ +std::string getDbusProperty(const std::string& service, + const std::string& objPath, + const std::string& interface, + const std::string& property) +{ + + sdbusplus::message::variant name; + + auto bus = sdbusplus::bus::new_default(); + + auto method = bus.new_method_call( + service.c_str(), + objPath.c_str(), + PROP_INTF, + METHOD_GET); + + method.append(interface, property); + + auto reply = bus.call(method); + + if (reply.is_method_error()) + { + log("Failed to get property", + entry("PROPERTY=%s", property.c_str()), + entry("PATH=%s", objPath.c_str()), + entry("INTERFACE=%s", interface.c_str())); + elog(); + } + + reply.read(name); + + return name.get(); +} + +/** @brief Gets all the properties associated with the given object + * and the interface. + * @param[in] service - Dbus service name. + * @param[in] objPath - Dbus object path. + * @param[in] interface - Dbus interface. + * @return On success returns the map of name value pair. + */ +ipmi::PropertyMap getAllDbusProperties(const std::string& service, + const std::string& objPath, + const std::string& interface) +{ + ipmi::PropertyMap properties; + auto bus = sdbusplus::bus::new_default(); + + auto method = bus.new_method_call( + service.c_str(), + objPath.c_str(), + PROP_INTF, + METHOD_GET_ALL); + + method.append(interface); + + auto reply = bus.call(method); + + if (reply.is_method_error()) + { + log("Failed to get all properties", + entry("PATH=%s", objPath.c_str()), + entry("INTERFACE=%s", interface.c_str())); + elog(); + } + + reply.read(properties); + return properties; +} + +/** @brief Sets the property value of the given object. + * @param[in] service - Dbus service name. + * @param[in] objPath - Dbus object path. + * @param[in] interface - Dbus interface. + * @param[in] property - name of the property. + * @param[in] value - value which needs to be set. + */ +void setDbusProperty(const std::string& service, + const std::string& objPath, + const std::string& interface, + const std::string& property, + const ipmi::Value& value) +{ + auto bus = sdbusplus::bus::new_default(); + + auto method = bus.new_method_call( + service.c_str(), + objPath.c_str(), + PROP_INTF, + METHOD_SET); + + method.append(interface); + method.append(property, value); + + if (!bus.call(method)) + { + log("Failed to set property", + entry("PROPERTY=%s", property.c_str()), + entry("PATH=%s",objPath.c_str()), + entry("INTERFACE=%s",interface.c_str())); + elog(); + } + +} + +//TODO : Can remove the below function as we have +// new functions which uses sdbusplus. +// +// openbmc/openbmc#1489 int dbus_get_property(const char *name, char **buf) { sd_bus_error error = SD_BUS_ERROR_NULL; @@ -147,6 +373,11 @@ finish: return r; } +//TODO : Can remove the below function as we have +// new functions which uses sdbusplus. +// +// openbmc/openbmc#1489 + int dbus_set_property(const char * name, const char *value) { sd_bus_error error = SD_BUS_ERROR_NULL; @@ -216,305 +447,206 @@ struct set_sys_boot_options_t { uint8_t data[SIZE_BOOT_OPTION]; } __attribute__ ((packed)); -struct host_network_config_t { - std::string ipaddress; - std::string prefix; - std::string gateway; - std::string macaddress; - std::string addrType; - - host_network_config_t()=default; -}; -void fillNetworkConfig( host_network_config_t & host_config , - const std::string& conf_str ) { +int getHostNetworkData(get_sys_boot_options_response_t* respptr) +{ + ipmi::PropertyMap properties; + int rc = 0; - constexpr auto COMMA_DELIMITER = ","; - constexpr auto EQUAL_DELIMITER = "="; - size_t commaDelimtrPos = 0; - size_t equalDelimtrPos = 0,commaDelimtrPrevPos = 0; - std::string value; - while ( commaDelimtrPos < conf_str.length() ) { + try + { + //TODO There may be cases where an interface is implemented by multiple + // objects,to handle such cases we are interested on that object + // which are on interested busname. + // Currenlty mapper doesn't give the readable busname(gives busid) + // so we can't match with bus name so giving some object specific info + // as SETTINGS_MATCH. + // Later SETTINGS_MATCH will be replaced with busname. - commaDelimtrPos = conf_str.find(COMMA_DELIMITER,commaDelimtrPos); - //This condition is to extract the last - //Substring as we will not be having the delimeter - //at end. std::string::npos is -1 + auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT, + SETTINGS_MATCH); + auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT, + SETTINGS_MATCH); - if ( commaDelimtrPos == std::string::npos ) { - commaDelimtrPos = conf_str.length(); - } + properties = getAllDbusProperties(ipObjectInfo.second, + ipObjectInfo.first, IP_INTERFACE); + auto MACAddress = + getDbusProperty(macObjectInfo.second, macObjectInfo.first, + MAC_INTERFACE, "MACAddress"); - equalDelimtrPos = conf_str.find (EQUAL_DELIMITER,commaDelimtrPrevPos); + sscanf(MACAddress.c_str(), MAC_ADDRESS_FORMAT, + (respptr->data + MAC_OFFSET), + (respptr->data + MAC_OFFSET + 1), + (respptr->data + MAC_OFFSET + 2), + (respptr->data + MAC_OFFSET + 3), + (respptr->data + MAC_OFFSET + 4), + (respptr->data + MAC_OFFSET + 5)); - //foo,ipaddress=1234 - if ( equalDelimtrPos == std::string::npos ) { - commaDelimtrPos++; - commaDelimtrPrevPos= commaDelimtrPos; - continue; - } + respptr->data[MAC_OFFSET + 6] = 0x00; - value = conf_str.substr((equalDelimtrPos+1), - commaDelimtrPos-(equalDelimtrPos+1)); + uint8_t addrType = (properties["Origin"].get() == + "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ? 1 : 0; -#ifdef _IPMI_DEBUG_ - printf ("Name=[%s],Value=[%s],commaDelimtrPos=[%d],\ - commaDelimtrPrevPos=[%d],equalDelimtrPos=[%d]\n", - name.c_str(),value.c_str(),commaDelimtrPos, - commaDelimtrPrevPos,equalDelimtrPos); -#endif + memcpy(respptr->data + ADDRTYPE_OFFSET, &addrType, sizeof(addrType)); - if ( 0 == conf_str.compare(commaDelimtrPrevPos, - equalDelimtrPos-commaDelimtrPrevPos, - "ipaddress" )) { - host_config.ipaddress = std::move(value); - } - else if ( 0 == conf_str.compare(commaDelimtrPrevPos, - equalDelimtrPos-commaDelimtrPrevPos, - "prefix" )) { - host_config.prefix = std::move(value); - } - else if ( 0 == conf_str.compare(commaDelimtrPrevPos, - equalDelimtrPos-commaDelimtrPrevPos, - "gateway" )) { - host_config.gateway = std::move(value); - } - else if ( 0 == conf_str.compare(commaDelimtrPrevPos, - equalDelimtrPos-commaDelimtrPrevPos, - "mac" )) { - host_config.macaddress = std::move(value); - } - else if ( 0 == conf_str.compare(commaDelimtrPrevPos, - equalDelimtrPos-commaDelimtrPrevPos, - "addr_type" )) { - host_config.addrType = std::move(value); - } + // ipaddress and gateway would be in IPv4 format - commaDelimtrPos++; - commaDelimtrPrevPos= commaDelimtrPos; - } -} + inet_pton(AF_INET, properties["Address"].get().c_str(), + (respptr->data + IPADDR_OFFSET)); -int getHostNetworkData(get_sys_boot_options_response_t* respptr) -{ + uint8_t prefix = properties["PrefixLength"].get(); + memcpy(respptr->data + PREFIX_OFFSET, &prefix, sizeof(prefix)); - char *prop = nullptr; - int rc = dbus_get_property("network_config",&prop); + inet_pton(AF_INET, properties["Gateway"].get().c_str(), + (respptr->data + GATEWAY_OFFSET)); - if ( rc < 0 ) { - fprintf(stderr, "Dbus get property(boot_flags) failed\ - for get_sys_boot_options.\n"); - return rc; } - - std::string conf_str(prop); - - if ( prop ) { - - free(prop); - prop = nullptr; + catch (InternalFailure& e) + { + commit(); + memset(respptr->data, 0, SIZE_BOOT_OPTION); + rc = -1; + return rc; } - /* network_config property Value would be in the form of - * ipaddress=1.1.1.1,prefix=16,gateway=2.2.2.2,mac=11:22:33:44:55:66,dhcp=0 - */ - - /* Parsing the string and fill the hostconfig structure with the - * values */ - - printf ("Configuration String[%s]\n ",conf_str.c_str()); - - host_network_config_t host_config; - - // Fill the host_config from the configuration string - fillNetworkConfig(host_config,conf_str); - - //Assigning the index as intialByteLength as it is fixed and prefilled. - printf ("host_config.macaddress.c_str()=[%s]\n",host_config.macaddress.c_str()); - do{ - - rc = sscanf(host_config.macaddress.c_str(),MAC_ADDRESS_FORMAT, - (respptr->data+MAC_OFFSET), (respptr->data+MAC_OFFSET+1), - (respptr->data+MAC_OFFSET+2),(respptr->data+MAC_OFFSET+3), - (respptr->data+MAC_OFFSET+4), (respptr->data+MAC_OFFSET+5)); - - - if ( rc < 6 ){ - fprintf(stderr, "sscanf Failed in extracting mac address.\n"); - rc = -1; - break; - } - - //Conevrt the dhcp,ipaddress,mask and gateway as hex number - respptr->data[MAC_OFFSET+6]=0x00; - - rc = sscanf(host_config.addrType.c_str(),ADDR_TYPE_FORMAT, - (respptr->data+ADDRTYPE_OFFSET)); - - if ( rc <= 0 ) { - fprintf(stderr, "sscanf Failed in extracting address type.\n"); - rc = -1; - break; - } - - //ipaddress and gateway would be in IPv4 format - rc = inet_pton(AF_INET,host_config.ipaddress.c_str(), - (respptr->data+IPADDR_OFFSET)); - - if ( rc <= 0 ) { - fprintf(stderr, "inet_pton failed during ipaddress coneversion\n"); - rc = -1; - break; - } - - rc = sscanf(host_config.prefix.c_str(),PREFIX_FORMAT, - (respptr->data+PREFIX_OFFSET)); - - if ( rc <= 0 ) { - fprintf(stderr, "sscanf failed during prefix extraction.\n"); - rc = -1; - break; - } - - rc = inet_pton(AF_INET,host_config.gateway.c_str(), - (respptr->data+GATEWAY_OFFSET)); - - if ( rc <= 0 ) { - fprintf(stderr, "inet_pton failed during gateway conversion.\n"); - rc = -1; - break; - } - - }while (0); + //PetiBoot-Specific + //If sucess then copy the first 9 bytes to the data + //else set the respptr to 0 - if ( rc ) { - - //PetiBoot-Specific - //If sucess then copy the first 9 bytes to the data - //else set the respptr to 0 - - memcpy(respptr->data,net_conf_initial_bytes, - sizeof(net_conf_initial_bytes)); + memcpy(respptr->data, net_conf_initial_bytes, + sizeof(net_conf_initial_bytes)); #ifdef _IPMI_DEBUG_ - printf ("\n===Printing the IPMI Formatted Data========\n"); + printf("\n===Printing the IPMI Formatted Data========\n"); - for ( uint8_t pos = 0; posdata[pos]); + for (uint8_t pos = 0; pos < index; pos++) + { + printf("%02x ", respptr->data[pos]); + } #endif - }else { - - memset(respptr->data,0,SIZE_BOOT_OPTION); - } return rc; } -int setHostNetworkData(set_sys_boot_options_t * reqptr) +int setHostNetworkData(set_sys_boot_options_t* reqptr) { + using namespace std::string_literals; std::string host_network_config; char mac[SIZE_MAC] = {0}; char ipAddress[INET_ADDRSTRLEN] = {0}; char gateway[INET_ADDRSTRLEN] = {0}; - char dhcp[SIZE_PREFIX] = {0}; - char prefix[SIZE_PREFIX] = {0}; - int rc = 0; - uint32_t zeroCookie=0; + char dhcp {0}; + std::string addressOrigin = + "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; + uint8_t prefix {0}; + uint32_t zeroCookie = 0; //cookie starts from second byte // version starts from sixth byte - do { - - // cookie == 0x21 0x70 0x62 0x21 - if ( memcmp(&(reqptr->data[COOKIE_OFFSET]), - (net_conf_initial_bytes+COOKIE_OFFSET), - SIZE_COOKIE) != 0 ) { - //cookie == 0 - if ( memcmp(&(reqptr->data[COOKIE_OFFSET]), - &zeroCookie, - SIZE_COOKIE) == 0 ) { - rc = 0; - break; + try + { + do + { + // cookie == 0x21 0x70 0x62 0x21 + if (memcmp(&(reqptr->data[COOKIE_OFFSET]), + (net_conf_initial_bytes + COOKIE_OFFSET), + SIZE_COOKIE) != 0) + { + //cookie == 0 + if (memcmp(&(reqptr->data[COOKIE_OFFSET]), + &zeroCookie, + SIZE_COOKIE) == 0) + { + // need to zero out the network settings. + break; + } + + log("Invalid Cookie"); + elog(); } - //Invalid cookie - fprintf(stderr, "Invalid Cookie\n"); - rc = -1; - break; - } - // vesion == 0x00 0x01 - if ( memcmp(&(reqptr->data[VERSION_OFFSET]), - (net_conf_initial_bytes+VERSION_OFFSET), - SIZE_VERSION) != 0 ) { - - fprintf(stderr, "Invalid Version\n"); - rc = -1; - break; - } - - snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT, - reqptr->data[MAC_OFFSET], - reqptr->data[MAC_OFFSET+1], - reqptr->data[MAC_OFFSET+2], - reqptr->data[MAC_OFFSET+3], - reqptr->data[MAC_OFFSET+4], - reqptr->data[MAC_OFFSET+5]); - snprintf(dhcp,SIZE_PREFIX, ADDR_TYPE_FORMAT, reqptr->data[ADDRTYPE_OFFSET]); - //Validating the address type which could be - //either static or dynamic - if( *(reqptr->data+ADDRTYPE_OFFSET) > 1 ) { - - fprintf(stderr, "Invalid Address Type\n"); - rc = -1; - break; + // vesion == 0x00 0x01 + if (memcmp(&(reqptr->data[VERSION_OFFSET]), + (net_conf_initial_bytes + VERSION_OFFSET), + SIZE_VERSION) != 0) + { - } + log("Invalid Version"); + elog(); + } - snprintf(ipAddress, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT, - reqptr->data[IPADDR_OFFSET], reqptr->data[IPADDR_OFFSET+1], - reqptr->data[IPADDR_OFFSET+2], reqptr->data[IPADDR_OFFSET+3]); + snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT, + reqptr->data[MAC_OFFSET], + reqptr->data[MAC_OFFSET + 1], + reqptr->data[MAC_OFFSET + 2], + reqptr->data[MAC_OFFSET + 3], + reqptr->data[MAC_OFFSET + 4], + reqptr->data[MAC_OFFSET + 5]); - //validating prefix - if ( *(reqptr->data+PREFIX_OFFSET) > (uint8_t)MAX_PREFIX_VALUE ) { + memcpy(&dhcp, &(reqptr->data[ADDRTYPE_OFFSET]), + sizeof(decltype(dhcp))); - fprintf(stderr, "Invalid Prefix\n"); - rc = -1; - break; - } + if (dhcp) + { + addressOrigin = + "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; + } - snprintf(prefix,SIZE_PREFIX,PREFIX_FORMAT, reqptr->data[PREFIX_OFFSET]); + snprintf(ipAddress, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT, + reqptr->data[IPADDR_OFFSET], + reqptr->data[IPADDR_OFFSET + 1], + reqptr->data[IPADDR_OFFSET + 2], + reqptr->data[IPADDR_OFFSET + 3]); - snprintf(gateway, INET_ADDRSTRLEN,IP_ADDRESS_FORMAT, - reqptr->data[GATEWAY_OFFSET], - reqptr->data[GATEWAY_OFFSET+1], - reqptr->data[GATEWAY_OFFSET+2], - reqptr->data[GATEWAY_OFFSET+3]); + memcpy(&prefix, &(reqptr->data[PREFIX_OFFSET]), + sizeof(decltype(prefix))); - }while(0); + snprintf(gateway, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT, + reqptr->data[GATEWAY_OFFSET], + reqptr->data[GATEWAY_OFFSET + 1], + reqptr->data[GATEWAY_OFFSET + 2], + reqptr->data[GATEWAY_OFFSET + 3]); + } while(0); - if( !rc ) - { //Cookie == 0 or it is a valid cookie - host_network_config += "ipaddress="+std::string(ipAddress)+",prefix="+ - std::string(prefix)+",gateway="+std::string(gateway)+ - ",mac="+std::string(mac)+",addr_type="+std::string(dhcp); - - printf ("Network configuration changed: %s\n",host_network_config.c_str()); - - rc = dbus_set_property("network_config",host_network_config.c_str()); - - if ( rc < 0 ) { - fprintf(stderr, "Dbus set property(network_config)\ - failed for set_sys_boot_options.\n"); - rc = -1; - } + host_network_config += "ipaddress="s + ipAddress + + ",prefix="s + std::to_string(prefix) + ",gateway="s + gateway + + ",mac="s + mac + ",addressOrigin="s + addressOrigin; + + log("Network configuration changed", + entry("NETWORKCONFIG=%s", host_network_config.c_str())); + + auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT, + SETTINGS_MATCH); + auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT, + SETTINGS_MATCH); + // set the dbus property + setDbusProperty(ipObjectInfo.second, ipObjectInfo.first, + IP_INTERFACE, "Address", std::string(ipAddress)); + setDbusProperty(ipObjectInfo.second, ipObjectInfo.first, + IP_INTERFACE, "PrefixLength", prefix); + setDbusProperty(ipObjectInfo.second, ipObjectInfo.first, + IP_INTERFACE, "Origin", addressOrigin); + setDbusProperty(ipObjectInfo.second, ipObjectInfo.first, + IP_INTERFACE, "Gateway", std::string(gateway)); + setDbusProperty(ipObjectInfo.second, ipObjectInfo.first, + IP_INTERFACE, "Type", + std::string("xyz.openbmc_project.Network.IP.Protocol.IPv4")); + setDbusProperty(macObjectInfo.second, macObjectInfo.first, + MAC_INTERFACE,"MACAddress", std::string(mac)); } - return rc; + catch (InternalFailure& e) + { + commit(); + return -1; + } + + return 0; } ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, -- cgit v1.2.1