blob: ccd9ca4fc83eacc442f3c03d1393af36c74b6831 [file] [log] [blame] [edit]
#pragma once
#include "constants.hpp"
#include "types.hpp"
#include <nlohmann/json.hpp>
#include <mutex>
#include <optional>
#include <semaphore>
#include <tuple>
namespace vpd
{
/**
* @brief A class to process and publish VPD data.
*
* The class works on VPD and is mainly responsible for following tasks:
* 1) Select appropriate device tree and JSON. Reboot if required.
* 2) Get desired parser using parser factory.
* 3) Calling respective parser class to get parsed VPD.
* 4) Arranging VPD data under required interfaces.
* 5) Calling PIM to publish VPD.
*
* The class may also implement helper functions required for VPD handling.
*/
class Worker
{
public:
/**
* List of deleted functions.
*/
Worker(const Worker&);
Worker& operator=(const Worker&);
Worker(Worker&&) = delete;
/**
* @brief Constructor.
*
* In case the processing is not JSON based, no argument needs to be passed.
* Constructor will also, based on symlink pick the correct JSON and
* initialize the parsed JSON variable.
*
* @param[in] pathToConfigJSON - Path to the config JSON, if applicable.
* @param[in] i_maxThreadCount - Maximum thread while collecting FRUs VPD.
*
* Note: Throws std::exception in case of construction failure. Caller needs
* to handle to detect successful object creation.
*/
Worker(std::string pathToConfigJson = std::string(),
uint8_t i_maxThreadCount = constants::MAX_THREADS);
/**
* @brief Destructor
*/
~Worker() = default;
#ifdef IBM_SYSTEM
/**
* @brief API to perform initial setup before manager claims Bus name.
*
* Before BUS name for VPD-Manager is claimed, fitconfig whould be set for
* corret device tree, inventory JSON w.r.t system should be linked and
* system VPD should be on DBus.
*/
void performInitialSetup();
#endif
/**
* @brief An API to check if system VPD is already published.
*
* @return Status, true if system is already collected else false.
*/
bool isSystemVPDOnDBus() const;
/**
* @brief API to process all FRUs presnt in config JSON file.
*
* This API based on config JSON passed/selected for the system, will
* trigger parser for all the FRUs and publish it on DBus.
*
* Note: Config JSON file path should be passed to worker class constructor
* to make use of this API.
*
*/
void collectFrusFromJson();
/**
* @brief API to parse VPD data
*
* @param[in] i_vpdFilePath - Path to the VPD file.
*/
types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath);
/**
* @brief An API to populate DBus interfaces for a FRU.
*
* Note: Call this API to populate D-Bus. Also caller should handle empty
* objectInterfaceMap.
*
* @param[in] parsedVpdMap - Parsed VPD as a map.
* @param[out] objectInterfaceMap - Object and its interfaces map.
* @param[in] vpdFilePath - EEPROM path of FRU.
*/
void populateDbus(const types::VPDMapVariant& parsedVpdMap,
types::ObjectMap& objectInterfaceMap,
const std::string& vpdFilePath);
/**
* @brief An API to delete FRU VPD over DBus.
*
* @param[in] i_dbusObjPath - Dbus object path of the FRU.
*
* @throw std::runtime_error if given input path is empty.
*/
void deleteFruVpd(const std::string& i_dbusObjPath);
/**
* @brief API to get status of VPD collection process.
*
* @return - True when done, false otherwise.
*/
inline bool isAllFruCollectionDone() const
{
return m_isAllFruCollected;
}
/**
* @brief API to get system config JSON object
*
* @return System config JSON object.
*/
inline nlohmann::json getSysCfgJsonObj() const
{
return m_parsedJson;
}
/**
* @brief API to get active thread count.
*
* Each FRU is collected in a separate thread. This API gives the active
* thread collecting FRU's VPD at any given time.
*
* @return Count of active threads.
*/
size_t getActiveThreadCount() const
{
return m_activeCollectionThreadCount;
}
/**
* @brief API to get list of EEPROMs for which thread creation failed.
*
* This API returns reference to list of EEPROM paths for which VPD
* collection thread creation has failed. Manager needs to process this list
* of EEPROMs and take appropriate action.
*
* @return reference to list of EEPROM paths for which VPD collection thread
* creation has failed
*/
inline std::forward_list<std::string>& getFailedEepromPaths() noexcept
{
return m_failedEepromPaths;
}
private:
/**
* @brief An API to parse and publish a FRU VPD over D-Bus.
*
* Note: This API will handle all the exceptions internally and will only
* return status of parsing and publishing of VPD over D-Bus.
*
* @param[in] i_vpdFilePath - Path of file containing VPD.
* @return Tuple of status and file path. Status, true if successfull else
* false.
*/
std::tuple<bool, std::string> parseAndPublishVPD(
const std::string& i_vpdFilePath);
/**
* @brief An API to set appropriate device tree and JSON.
*
* This API based on system chooses corresponding device tree and JSON.
* If device tree change is required, it updates the "fitconfig" and reboots
* the system. Else it is NOOP.
*
* @throw std::exception
*/
void setDeviceTreeAndJson();
/**
* @brief API to select system specific JSON.
*
* The API based on the IM value of VPD, will select appropriate JSON for
* the system. In case no system is found corresponding to the extracted IM
* value, error will be logged.
*
* @param[out] systemJson - System JSON name.
* @param[in] parsedVpdMap - Parsed VPD map.
*/
void getSystemJson(std::string& systemJson,
const types::VPDMapVariant& parsedVpdMap);
/**
* @brief An API to read IM value from VPD.
*
* Note: Throws exception in case of error. Caller need to handle.
*
* @param[in] parsedVpd - Parsed VPD.
*/
std::string getIMValue(const types::IPZVpdMap& parsedVpd) const;
/**
* @brief An API to read HW version from VPD.
*
* Note: Throws exception in case of error. Caller need to handle.
*
* @param[in] parsedVpd - Parsed VPD.
*/
std::string getHWVersion(const types::IPZVpdMap& parsedVpd) const;
/**
* @brief An API to parse given VPD file path.
*
* @throw std::exception
*
* @param[in] vpdFilePath - EEPROM file path.
* @param[out] parsedVpd - Parsed VPD as a map.
*/
void fillVPDMap(const std::string& vpdFilePath,
types::VPDMapVariant& parsedVpd);
/**
* @brief An API to parse and publish system VPD on D-Bus.
*
* Note: Throws exception in case of invalid VPD format.
*
* @param[in] parsedVpdMap - Parsed VPD as a map.
*/
void publishSystemVPD(const types::VPDMapVariant& parsedVpdMap);
/**
* @brief An API to process extrainterfaces w.r.t a FRU.
*
* @param[in] singleFru - JSON block for a single FRU.
* @param[out] interfaces - Map to hold interface along with its properties.
* @param[in] parsedVpdMap - Parsed VPD as a map.
*/
void processExtraInterfaces(const nlohmann::json& singleFru,
types::InterfaceMap& interfaces,
const types::VPDMapVariant& parsedVpdMap);
/**
* @brief An API to process embedded and synthesized FRUs.
*
* @param[in] singleFru - FRU to be processed.
* @param[out] interfaces - Map to hold interface along with its properties.
*/
void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
types::InterfaceMap& interfaces);
/**
* @brief An API to read process FRU based in CCIN.
*
* For some FRUs VPD can be processed only if the FRU has some specific
* value for CCIN. In case the value is not from that set, VPD for those
* FRUs can't be processed.
*
* @param[in] singleFru - Fru whose CCIN value needs to be matched.
* @param[in] parsedVpdMap - Parsed VPD map.
*/
bool processFruWithCCIN(const nlohmann::json& singleFru,
const types::VPDMapVariant& parsedVpdMap);
/**
* @brief API to process json's inherit flag.
*
* Inherit flag denotes that some property in the child FRU needs to be
* inherited from parent FRU.
*
* @param[in] parsedVpdMap - Parsed VPD as a map.
* @param[out] interfaces - Map to hold interface along with its properties.
*/
void processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
types::InterfaceMap& interfaces);
/**
* @brief API to process json's "copyRecord" flag.
*
* copyRecord flag denotes if some record data needs to be copies in the
* given FRU.
*
* @param[in] singleFru - FRU being processed.
* @param[in] parsedVpdMap - Parsed VPD as a map.
* @param[out] interfaces - Map to hold interface along with its properties.
*/
void processCopyRecordFlag(const nlohmann::json& singleFru,
const types::VPDMapVariant& parsedVpdMap,
types::InterfaceMap& interfaces);
/**
* @brief An API to populate IPZ VPD property map.
*
* @param[out] interfacePropMap - Map of interface and properties under it.
* @param[in] keyordValueMap - Keyword value map of IPZ VPD.
* @param[in] interfaceName - Name of the interface.
*/
void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap,
const types::IPZKwdValueMap& keyordValueMap,
const std::string& interfaceName);
/**
* @brief An API to populate Kwd VPD property map.
*
* @param[in] keyordValueMap - Keyword value map of Kwd VPD.
* @param[out] interfaceMap - interface and property,value under it.
*/
void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap,
types::InterfaceMap& interfaceMap);
/**
* @brief API to populate all required interface for a FRU.
*
* @param[in] interfaceJson - JSON containing interfaces to be populated.
* @param[out] interfaceMap - Map to hold populated interfaces.
* @param[in] parsedVpdMap - Parsed VPD as a map.
*/
void populateInterfaces(const nlohmann::json& interfaceJson,
types::InterfaceMap& interfaceMap,
const types::VPDMapVariant& parsedVpdMap);
/**
* @brief Check if the given CPU is an IO only chip.
*
* The CPU is termed as IO, whose all of the cores are bad and can never be
* used. Those CPU chips can be used for IO purpose like connecting PCIe
* devices etc., The CPU whose every cores are bad, can be identified from
* the CP00 record's PG keyword, only if all of the 8 EQs' value equals
* 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.)
*
* @param [in] pgKeyword - PG Keyword of CPU.
* @return true if the given cpu is an IO, false otherwise.
*/
bool isCPUIOGoodOnly(const std::string& pgKeyword);
/**
* @brief API to prime inventory Objects.
*
* @param[in] i_vpdFilePath - EEPROM file path.
* @return true if the prime inventory is success, false otherwise.
*/
bool primeInventory(const std::string& i_vpdFilePath);
/**
* @brief API to process preAction(base_action) defined in config JSON.
*
* @note sequence of tags under any given flag of preAction is EXTREMELY
* important to ensure proper processing. The API will process all the
* nested items under the base action sequentially. Also if any of the tag
* processing fails, the code will not process remaining tags under the
* flag.
* ******** sample format **************
* fru EEPROM path: {
* base_action: {
* flag1: {
* tag1: {
* },
* tag2: {
* }
* }
* flag2: {
* tags: {
* }
* }
* }
* }
* *************************************
*
* @param[in] i_vpdFilePath - Path to the EEPROM file.
* @param[in] i_flagToProcess - To identify which flag(s) needs to be
* processed under PreAction tag of config JSON.
* @return Execution status.
*/
bool processPreAction(const std::string& i_vpdFilePath,
const std::string& i_flagToProcess);
/**
* @brief API to process postAction(base_action) defined in config JSON.
*
* @note Sequence of tags under any given flag of postAction is EXTREMELY
* important to ensure proper processing. The API will process all the
* nested items under the base action sequentially. Also if any of the tag
* processing fails, the code will not process remaining tags under the
* flag.
* ******** sample format **************
* fru EEPROM path: {
* base_action: {
* flag1: {
* tag1: {
* },
* tag2: {
* }
* }
* flag2: {
* tags: {
* }
* }
* }
* }
* *************************************
* Also, if post action is required to be processed only for FRUs with
* certain CCIN then CCIN list can be provided under flag.
*
* @param[in] i_vpdFruPath - Path to the EEPROM file.
* @param[in] i_flagToProcess - To identify which flag(s) needs to be
* processed under postAction tag of config JSON.
* @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is
* required.
* @return Execution status.
*/
bool processPostAction(
const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt);
/**
* @brief Function to enable and bring MUX out of idle state.
*
* This finds all the MUX defined in the system json and enables them by
* setting the holdidle parameter to 0.
*
* @throw std::runtime_error
*/
void enableMuxChips();
/**
* @brief An API to perform backup or restore of VPD.
*
* @param[in,out] io_srcVpdMap - Source VPD map.
*/
void performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap);
/**
* @brief API to update "Functional" property.
*
* The API sets the default value for "Functional" property once if the
* property is not yet populated over DBus. As the property value is not
* controlled by the VPD-Collection process, if it is found already
* populated, the functions skips re-populating the property so that already
* existing value can be retained.
*
* @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
* @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
*/
void processFunctionalProperty(const std::string& i_inventoryObjPath,
types::InterfaceMap& io_interfaces);
/**
* @brief API to update "enabled" property.
*
* The API sets the default value for "enabled" property once if the
* property is not yet populated over DBus. As the property value is not
* controlled by the VPD-Collection process, if it is found already
* populated, the functions skips re-populating the property so that already
* existing value can be retained.
*
* @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
* @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
*/
void processEnabledProperty(const std::string& i_inventoryObjPath,
types::InterfaceMap& io_interfaces);
/**
* @brief API to form asset tag string for the system.
*
* @param[in] i_parsedVpdMap - Parsed VPD map.
*
* @throw std::runtime_error
*
* @return - Formed asset tag string.
*/
std::string createAssetTagString(
const types::VPDMapVariant& i_parsedVpdMap);
/**
* @brief API to prime system blueprint.
*
* The API will traverse the system config JSON and will prime all the FRU
* paths which qualifies for priming.
*/
void primeSystemBlueprint();
/**
* @brief API to set symbolic link for system config JSON.
*
* Once correct device tree is set, symbolic link to the correct sytsem
* config JSON is set to be used in subsequent BMC boot.
*
* @param[in] i_systemJson - system config JSON.
*/
void setJsonSymbolicLink(const std::string& i_systemJson);
/**
* @brief API to set present property.
*
* This API updates the present property of the given FRU with the given
* value. Note: It is the responsibility of the caller to determine whether
* the present property for the FRU should be updated or not.
*
* @param[in] i_vpdPath - EEPROM or inventory path.
* @param[in] i_value - value to be set.
*/
void setPresentProperty(const std::string& i_fruPath, const bool& i_value);
/**
* @brief API to check if the path needs to be skipped for collection.
*
* Some FRUs, under some given scenarios should not be collected and
* skipped.
*
* @param[in] i_vpdFilePath - EEPROM path.
*
* @return True - if path is empty or should be skipped, false otherwise.
*/
bool skipPathForCollection(const std::string& i_vpdFilePath);
/**
* @brief API to check if present property should be handled for given FRU.
*
* vpd-manager should update present property for a FRU if and only if it's
* not synthesized and vpd-manager handles present property for the FRU.
* This API assumes "handlePresence" tag is a subset of "synthesized" tag.
*
* @param[in] i_fru - JSON block for a single FRU.
*
* @return true if present property should be handled, false otherwise.
*/
inline bool isPresentPropertyHandlingRequired(
const nlohmann::json& i_fru) const noexcept
{
// TODO: revisit this to see if this logic can be optimized.
return !i_fru.value("synthesized", false) &&
i_fru.value("handlePresence", true);
}
// Parsed JSON file.
nlohmann::json m_parsedJson{};
// Hold if symlink is present or not.
bool m_isSymlinkPresent = false;
// Path to config JSON if applicable.
std::string& m_configJsonPath;
// Keeps track of active thread(s) doing VPD collection.
size_t m_activeCollectionThreadCount = 0;
// Holds status, if VPD collection has been done or not.
// Note: This variable does not give information about successfull or failed
// collection. It just states, if the VPD collection process is over or not.
bool m_isAllFruCollected = false;
// To distinguish the factory reset path.
bool m_isFactoryResetDone = false;
// Mutex to guard critical resource m_activeCollectionThreadCount.
std::mutex m_mutex;
// Counting semaphore to limit the number of threads.
std::counting_semaphore<constants::MAX_THREADS> m_semaphore;
// List of EEPROM paths for which VPD collection thread creation has failed.
std::forward_list<std::string> m_failedEepromPaths;
};
} // namespace vpd