Revamped code for VPD parser

The commit removes all the pre-existing code from the branch
and pushes the revamped code.

Major modification includes:
- Movement from multi exe to single daemon model.
- Multithreaded approach to parse FRU VPD.
- Better error handling.
- Refactored code for performance optimization.

Note: This code supports all the existing functionalities as it is.

Change-Id: I1ddce1f0725ac59020b72709689a1013643bda8b
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/include/backup_restore.hpp b/vpd-manager/include/backup_restore.hpp
new file mode 100644
index 0000000..12ec384
--- /dev/null
+++ b/vpd-manager/include/backup_restore.hpp
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <tuple>
+
+namespace vpd
+{
+
+// Backup and restore operation status.
+enum class BackupAndRestoreStatus : uint8_t
+{
+    NotStarted,
+    Invoked,
+    Completed
+};
+
+/**
+ * @brief class to implement backup and restore VPD.
+ *
+ */
+
+class BackupAndRestore
+{
+  public:
+    // delete functions
+    BackupAndRestore() = delete;
+    BackupAndRestore(const BackupAndRestore&) = delete;
+    BackupAndRestore& operator=(const BackupAndRestore&) = delete;
+    BackupAndRestore(BackupAndRestore&&) = delete;
+    BackupAndRestore& operator=(BackupAndRestore&&) = delete;
+
+    /**
+     * @brief Constructor.
+     *
+     * @param[in] i_sysCfgJsonObj - System config JSON object.
+     *
+     * @throw std::runtime_error in case constructor failure.
+     */
+    BackupAndRestore(const nlohmann::json& i_sysCfgJsonObj);
+
+    /**
+     * @brief Default destructor.
+     */
+    ~BackupAndRestore() = default;
+
+    /**
+     * @brief An API to backup and restore VPD.
+     *
+     * Note: This API works on the keywords declared in the backup and restore
+     * config JSON. Restore or backup action could be triggered for each
+     * keyword, based on the keyword's value present in the source and
+     * destination keyword.
+     *
+     * Restore source keyword's value with destination keyword's value,
+     * when source keyword has default value but
+     * destination's keyword has non default value.
+     *
+     * Backup the source keyword value to the destination's keyword's value,
+     * when source keyword has non default value but
+     * destination's keyword has default value.
+     *
+     * @return Tuple of updated source and destination VPD map variant.
+     */
+    std::tuple<types::VPDMapVariant, types::VPDMapVariant> backupAndRestore();
+
+    /**
+     * @brief An API to set backup and restore status.
+     *
+     * @param[in] i_status - Status to set.
+     */
+    static void
+        setBackupAndRestoreStatus(const BackupAndRestoreStatus& i_status);
+
+  private:
+    /**
+     * @brief An API to handle backup and restore of IPZ type VPD.
+     *
+     * @param[in,out] io_srcVpdMap - Source VPD map.
+     * @param[in,out] io_dstVpdMap - Destination VPD map.
+     * @param[in] i_srcPath - Source EEPROM file path or inventory path.
+     * @param[in] i_dstPath - Destination EEPROM file path or inventory path.
+     *
+     * @throw std::runtime_error
+     */
+    void backupAndRestoreIpzVpd(
+        types::IPZVpdMap& io_srcVpdMap, types::IPZVpdMap& io_dstVpdMap,
+        const std::string& i_srcPath, const std::string& i_dstPath);
+
+    // System JSON config JSON object.
+    nlohmann::json m_sysCfgJsonObj{};
+
+    // Backup and restore config JSON object.
+    nlohmann::json m_backupAndRestoreCfgJsonObj{};
+
+    // Backup and restore status.
+    static BackupAndRestoreStatus m_backupAndRestoreStatus;
+};
+
+} // namespace vpd
diff --git a/vpd-manager/include/bios_handler.hpp b/vpd-manager/include/bios_handler.hpp
new file mode 100644
index 0000000..916811e
--- /dev/null
+++ b/vpd-manager/include/bios_handler.hpp
@@ -0,0 +1,273 @@
+#pragma once
+#include "manager.hpp"
+#include "types.hpp"
+
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace vpd
+{
+
+/**
+ * @brief Interface class for BIOS handling.
+ *
+ * The class layout has the virtual methods required to be implemented by any
+ * concrete class that intends to use the feature provided via BIOS handler
+ * class.
+ */
+class BiosHandlerInterface
+{
+  public:
+    /**
+     * @brief API to back up or restore BIOS attributes.
+     *
+     * Concrete class should implement the API and read the backed up data from
+     * its designated location and take a call if it should be backed up or
+     * restored.
+     */
+    virtual void backUpOrRestoreBiosAttributes() = 0;
+
+    /**
+     * @brief Callback API to be triggered on BIOS attribute change.
+     *
+     * Concrete class should implement the API to extract the attribute and its
+     * value from DBus message broadcasted on BIOS attribute change.
+     * The definition should be overridden in concrete class to deal with BIOS
+     * attributes interested in.
+     *
+     * @param[in] i_msg - The callback message.
+     */
+    virtual void biosAttributesCallback(sdbusplus::message_t& i_msg) = 0;
+};
+
+/**
+ * @brief IBM specifc BIOS handler class.
+ */
+class IbmBiosHandler : public BiosHandlerInterface
+{
+  public:
+    /**
+     * @brief Construct a new IBM BIOS Handler object
+     *
+     * This constructor constructs a new IBM BIOS Handler object
+     * @param[in] i_manager - Manager object.
+     */
+    explicit IbmBiosHandler(const std::shared_ptr<Manager>& i_manager) :
+        m_manager(i_manager)
+    {}
+
+    /**
+     * @brief API to back up or restore BIOS attributes.
+     *
+     * The API will read the backed up data from the VPD keyword and based on
+     * its value, either backs up or restores the data.
+     */
+    virtual void backUpOrRestoreBiosAttributes();
+
+    /**
+     * @brief Callback API to be triggered on BIOS attribute change.
+     *
+     * The API to extract the required attribute and its value from DBus message
+     * broadcasted on BIOS attribute change.
+     *
+     * @param[in] i_msg - The callback message.
+     */
+    virtual void biosAttributesCallback(sdbusplus::message_t& i_msg);
+
+  private:
+    /**
+     * @brief API to read given attribute from BIOS table.
+     *
+     * @param[in] attributeName - Attribute to be read.
+     * @return - Bios attribute current value.
+     */
+    types::BiosAttributeCurrentValue
+        readBiosAttribute(const std::string& attributeName);
+
+    /**
+     * @brief API to process "hb_field_core_override" attribute.
+     *
+     * The API checks value stored in VPD. If found default then the BIOS value
+     * is saved to VPD else VPD value is restored in BIOS pending attribute
+     * table.
+     */
+    void processFieldCoreOverride();
+
+    /**
+     * @brief API to save FCO data into VPD.
+     *
+     * @param[in] i_fcoInBios - FCO value.
+     */
+    void saveFcoToVpd(int64_t i_fcoInBios);
+
+    /**
+     * @brief API to save given value to "hb_field_core_override" attribute.
+     *
+     * @param[in] i_fcoVal - FCO value.
+     */
+    void saveFcoToBios(const types::BinaryVector& i_fcoVal);
+
+    /**
+     * @brief API to save AMM data into VPD.
+     *
+     * @param[in] i_memoryMirrorMode - Memory mirror mode value.
+     */
+    void saveAmmToVpd(const std::string& i_memoryMirrorMode);
+
+    /**
+     * @brief API to save given value to "hb_memory_mirror_mode" attribute.
+     *
+     * @param[in] i_ammVal - AMM value.
+     */
+    void saveAmmToBios(const std::string& i_ammVal);
+
+    /**
+     * @brief API to process "hb_memory_mirror_mode" attribute.
+     *
+     * The API checks value stored in VPD. If found default then the BIOS value
+     * is saved to VPD else VPD value is restored in BIOS pending attribute
+     * table.
+     */
+    void processActiveMemoryMirror();
+
+    /**
+     * @brief API to process "pvm_create_default_lpar" attribute.
+     *
+     * The API reads the value from VPD and restore it to the BIOS attribute
+     * in BIOS pending attribute table.
+     */
+    void processCreateDefaultLpar();
+
+    /**
+     * @brief API to save given value to "pvm_create_default_lpar" attribute.
+     *
+     * @param[in] i_createDefaultLparVal - Value to be saved;
+     */
+    void saveCreateDefaultLparToBios(const std::string& i_createDefaultLparVal);
+
+    /**
+     * @brief API to save given value to VPD.
+     *
+     * @param[in] i_createDefaultLparVal - Value to be saved.
+     *
+     */
+    void saveCreateDefaultLparToVpd(const std::string& i_createDefaultLparVal);
+
+    /**
+     * @brief API to process "pvm_clear_nvram" attribute.
+     *
+     * The API reads the value from VPD and restores it to the BIOS pending
+     * attribute table.
+     */
+    void processClearNvram();
+
+    /**
+     * @brief API to save given value to "pvm_clear_nvram" attribute.
+     *
+     * @param[in] i_clearNvramVal - Value to be saved.
+     */
+    void saveClearNvramToBios(const std::string& i_clearNvramVal);
+
+    /**
+     * @brief API to save given value to VPD.
+     *
+     * @param[in] i_clearNvramVal - Value to be saved.
+     */
+    void saveClearNvramToVpd(const std::string& i_clearNvramVal);
+
+    /**
+     * @brief API to process "pvm_keep_and_clear" attribute.
+     *
+     * The API reads the value from VPD and restore it to the BIOS pending
+     * attribute table.
+     */
+    void processKeepAndClear();
+
+    /**
+     * @brief API to save given value to "pvm_keep_and_clear" attribute.
+     *
+     * @param[in] i_KeepAndClearVal - Value to be saved.
+     */
+    void saveKeepAndClearToBios(const std::string& i_KeepAndClearVal);
+
+    /**
+     * @brief API to save given value to VPD.
+     *
+     * @param[in] i_KeepAndClearVal - Value to be saved.
+     */
+    void saveKeepAndClearToVpd(const std::string& i_KeepAndClearVal);
+
+    // const reference to shared pointer to Manager object.
+    const std::shared_ptr<Manager>& m_manager;
+};
+
+/**
+ * @brief A class to operate upon BIOS attributes.
+ *
+ * The class along with specific BIOS handler class(es), provides a feature
+ * where specific BIOS attributes identified by the concrete specific class can
+ * be listened for any change and can be backed up to a desired location or
+ * restored back to the BIOS table.
+ *
+ * To use the feature, "BiosHandlerInterface" should be implemented by a
+ * concrete class and the same should be used to instantiate BiosHandler.
+ *
+ * This class registers call back to listen to PLDM service as it is being used
+ * for reading/writing BIOS attributes.
+ *
+ * The feature can be used in a factory reset scenario where backed up values
+ * can be used to restore BIOS.
+ *
+ */
+template <typename T>
+class BiosHandler
+{
+  public:
+    // deleted APIs
+    BiosHandler() = delete;
+    BiosHandler(const BiosHandler&) = delete;
+    BiosHandler& operator=(const BiosHandler&) = delete;
+    BiosHandler& operator=(BiosHandler&&) = delete;
+    ~BiosHandler() = default;
+
+    /**
+     * @brief Constructor.
+     *
+     * @param[in] i_connection - Asio connection object.
+     * @param[in] i_manager - Manager object.
+     */
+    BiosHandler(
+        const std::shared_ptr<sdbusplus::asio::connection>& i_connection,
+        const std::shared_ptr<Manager>& i_manager) : m_asioConn(i_connection)
+    {
+        m_specificBiosHandler = std::make_shared<T>(i_manager);
+        checkAndListenPldmService();
+    }
+
+  private:
+    /**
+     * @brief API to check if PLDM service is running and run BIOS sync.
+     *
+     * This API checks if the PLDM service is running and if yes it will start
+     * an immediate sync of BIOS attributes. If the service is not running, it
+     * registers a listener to be notified when the service starts so that a
+     * restore can be performed.
+     */
+    void checkAndListenPldmService();
+
+    /**
+     * @brief Register listener for BIOS attribute property change.
+     *
+     * The VPD manager needs to listen for property change of certain BIOS
+     * attributes that are backed in VPD. When the attributes change, the new
+     * value is written back to the VPD keywords that backs them up.
+     */
+    void listenBiosAttributes();
+
+    // Reference to the connection.
+    const std::shared_ptr<sdbusplus::asio::connection>& m_asioConn;
+
+    // shared pointer to specific BIOS handler.
+    std::shared_ptr<T> m_specificBiosHandler;
+};
+} // namespace vpd
diff --git a/vpd-manager/include/constants.hpp b/vpd-manager/include/constants.hpp
new file mode 100644
index 0000000..5faf8da
--- /dev/null
+++ b/vpd-manager/include/constants.hpp
@@ -0,0 +1,196 @@
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+namespace vpd
+{
+namespace constants
+{
+static constexpr auto KEYWORD_SIZE = 2;
+static constexpr auto RECORD_SIZE = 4;
+
+static constexpr uint8_t IPZ_DATA_START = 11;
+static constexpr uint8_t IPZ_DATA_START_TAG = 0x84;
+static constexpr uint8_t IPZ_RECORD_END_TAG = 0x78;
+
+static constexpr uint8_t KW_VPD_DATA_START = 0;
+static constexpr uint8_t KW_VPD_START_TAG = 0x82;
+static constexpr uint8_t KW_VPD_PAIR_START_TAG = 0x84;
+static constexpr uint8_t ALT_KW_VPD_PAIR_START_TAG = 0x90;
+static constexpr uint8_t KW_VPD_END_TAG = 0x78;
+static constexpr uint8_t KW_VAL_PAIR_END_TAG = 0x79;
+static constexpr uint8_t AMM_ENABLED_IN_VPD = 2;
+static constexpr uint8_t AMM_DISABLED_IN_VPD = 1;
+
+static constexpr auto DDIMM_11S_BARCODE_START = 416;
+static constexpr auto DDIMM_11S_BARCODE_START_TAG = "11S";
+static constexpr auto DDIMM_11S_FORMAT_LEN = 3;
+static constexpr auto DDIMM_11S_BARCODE_LEN = 26;
+static constexpr auto PART_NUM_LEN = 7;
+static constexpr auto SERIAL_NUM_LEN = 12;
+static constexpr auto CCIN_LEN = 4;
+static constexpr auto CONVERT_MB_TO_KB = 1024;
+static constexpr auto CONVERT_GB_TO_KB = 1024 * 1024;
+
+static constexpr auto SPD_BYTE_2 = 2;
+static constexpr auto SPD_BYTE_3 = 3;
+static constexpr auto SPD_BYTE_4 = 4;
+static constexpr auto SPD_BYTE_6 = 6;
+static constexpr auto SPD_BYTE_12 = 12;
+static constexpr auto SPD_BYTE_13 = 13;
+static constexpr auto SPD_BYTE_18 = 18;
+static constexpr auto SPD_BYTE_234 = 234;
+static constexpr auto SPD_BYTE_235 = 235;
+static constexpr auto SPD_BYTE_BIT_0_3_MASK = 0x0F;
+static constexpr auto SPD_BYTE_MASK = 0xFF;
+static constexpr auto SPD_MODULE_TYPE_DDIMM = 0x0A;
+static constexpr auto SPD_DRAM_TYPE_DDR5 = 0x12;
+static constexpr auto SPD_DRAM_TYPE_DDR4 = 0x0C;
+
+static constexpr auto JEDEC_SDRAM_CAP_MASK = 0x0F;
+static constexpr auto JEDEC_PRI_BUS_WIDTH_MASK = 0x07;
+static constexpr auto JEDEC_SDRAM_WIDTH_MASK = 0x07;
+static constexpr auto JEDEC_NUM_RANKS_MASK = 0x38;
+static constexpr auto JEDEC_DIE_COUNT_MASK = 0x70;
+static constexpr auto JEDEC_SINGLE_LOAD_STACK = 0x02;
+static constexpr auto JEDEC_SIGNAL_LOADING_MASK = 0x03;
+
+static constexpr auto JEDEC_SDRAMCAP_MULTIPLIER = 256;
+static constexpr auto JEDEC_PRI_BUS_WIDTH_MULTIPLIER = 8;
+static constexpr auto JEDEC_SDRAM_WIDTH_MULTIPLIER = 4;
+static constexpr auto JEDEC_SDRAMCAP_RESERVED = 7;
+static constexpr auto JEDEC_RESERVED_BITS = 3;
+static constexpr auto JEDEC_DIE_COUNT_RIGHT_SHIFT = 4;
+
+static constexpr auto LAST_KW = "PF";
+static constexpr auto POUND_KW = '#';
+static constexpr auto POUND_KW_PREFIX = "PD_";
+static constexpr auto MB_YEAR_END = 4;
+static constexpr auto MB_MONTH_END = 7;
+static constexpr auto MB_DAY_END = 10;
+static constexpr auto MB_HOUR_END = 13;
+static constexpr auto MB_MIN_END = 16;
+static constexpr auto MB_RESULT_LEN = 19;
+static constexpr auto MB_LEN_BYTES = 8;
+static constexpr auto UUID_LEN_BYTES = 16;
+static constexpr auto UUID_TIME_LOW_END = 8;
+static constexpr auto UUID_TIME_MID_END = 13;
+static constexpr auto UUID_TIME_HIGH_END = 18;
+static constexpr auto UUID_CLK_SEQ_END = 23;
+static constexpr auto MAC_ADDRESS_LEN_BYTES = 6;
+static constexpr auto ONE_BYTE = 1;
+static constexpr auto TWO_BYTES = 2;
+
+static constexpr auto VALUE_0 = 0;
+static constexpr auto VALUE_1 = 1;
+static constexpr auto VALUE_2 = 2;
+static constexpr auto VALUE_3 = 3;
+static constexpr auto VALUE_4 = 4;
+static constexpr auto VALUE_5 = 5;
+static constexpr auto VALUE_6 = 6;
+static constexpr auto VALUE_7 = 7;
+static constexpr auto VALUE_8 = 8;
+
+static constexpr auto MASK_BYTE_BITS_01 = 0x03;
+static constexpr auto MASK_BYTE_BITS_345 = 0x38;
+static constexpr auto MASK_BYTE_BITS_012 = 0x07;
+static constexpr auto MASK_BYTE_BITS_567 = 0xE0;
+static constexpr auto MASK_BYTE_BITS_01234 = 0x1F;
+
+static constexpr auto MASK_BYTE_BIT_6 = 0x40;
+static constexpr auto MASK_BYTE_BIT_7 = 0x80;
+
+static constexpr auto SHIFT_BITS_0 = 0;
+static constexpr auto SHIFT_BITS_3 = 3;
+static constexpr auto SHIFT_BITS_5 = 5;
+
+static constexpr auto ASCII_OF_SPACE = 32;
+
+// Size of 8 EQs' in CP00's PG keyword
+static constexpr auto SIZE_OF_8EQ_IN_PG = 24;
+
+// Zero based index position of first EQ in CP00's PG keyword
+static constexpr auto INDEX_OF_EQ0_IN_PG = 97;
+
+constexpr auto systemInvPath = "/xyz/openbmc_project/inventory/system";
+constexpr auto pimPath = "/xyz/openbmc_project/inventory";
+constexpr auto pimIntf = "xyz.openbmc_project.Inventory.Manager";
+constexpr auto ipzVpdInf = "com.ibm.ipzvpd.";
+constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI";
+constexpr auto vsysInf = "com.ibm.ipzvpd.VSYS";
+constexpr auto utilInf = "com.ibm.ipzvpd.UTIL";
+constexpr auto vcenInf = "com.ibm.ipzvpd.VCEN";
+constexpr auto kwdCCIN = "CC";
+constexpr auto kwdRG = "RG";
+constexpr auto kwdAMM = "D0";
+constexpr auto kwdClearNVRAM_CreateLPAR = "D1";
+constexpr auto kwdKeepAndClear = "D1";
+constexpr auto kwdFC = "FC";
+constexpr auto kwdTM = "TM";
+constexpr auto kwdSE = "SE";
+constexpr auto recVSYS = "VSYS";
+constexpr auto recVCEN = "VCEN";
+constexpr auto locationCodeInf = "com.ibm.ipzvpd.Location";
+constexpr auto xyzLocationCodeInf =
+    "xyz.openbmc_project.Inventory.Decorator.LocationCode";
+constexpr auto operationalStatusInf =
+    "xyz.openbmc_project.State.Decorator.OperationalStatus";
+constexpr auto enableInf = "xyz.openbmc_project.Object.Enable";
+constexpr auto assetInf = "xyz.openbmc_project.Inventory.Decorator.Asset";
+constexpr auto inventoryItemInf = "xyz.openbmc_project.Inventory.Item";
+constexpr auto pldmServiceName = "xyz.openbmc_project.PLDM";
+constexpr auto pimServiceName = "xyz.openbmc_project.Inventory.Manager";
+constexpr auto biosConfigMgrObjPath =
+    "/xyz/openbmc_project/bios_config/manager";
+constexpr auto biosConfigMgrService = "xyz.openbmc_project.BIOSConfigManager";
+constexpr auto biosConfigMgrInterface =
+    "xyz.openbmc_project.BIOSConfig.Manager";
+constexpr auto objectMapperService = "xyz.openbmc_project.ObjectMapper";
+constexpr auto objectMapperPath = "/xyz/openbmc_project/object_mapper";
+constexpr auto objectMapperInf = "xyz.openbmc_project.ObjectMapper";
+constexpr auto systemVpdInvPath =
+    "/xyz/openbmc_project/inventory/system/chassis/motherboard";
+constexpr auto assetTagInf = "xyz.openbmc_project.Inventory.Decorator.AssetTag";
+constexpr auto hostObjectPath = "/xyz/openbmc_project/state/host0";
+constexpr auto hostInterface = "xyz.openbmc_project.State.Host";
+constexpr auto hostService = "xyz.openbmc_project.State.Host";
+constexpr auto hostRunningState =
+    "xyz.openbmc_project.State.Host.HostState.Running";
+static constexpr auto BD_YEAR_END = 4;
+static constexpr auto BD_MONTH_END = 7;
+static constexpr auto BD_DAY_END = 10;
+static constexpr auto BD_HOUR_END = 13;
+
+constexpr uint8_t UNEXP_LOCATION_CODE_MIN_LENGTH = 4;
+constexpr uint8_t EXP_LOCATION_CODE_MIN_LENGTH = 17;
+static constexpr auto SE_KWD_LENGTH = 7;
+static constexpr auto INVALID_NODE_NUMBER = -1;
+
+static constexpr auto CMD_BUFFER_LENGTH = 256;
+
+// To be explicitly used for string comparision.
+static constexpr auto STR_CMP_SUCCESS = 0;
+
+// Just a random value. Can be adjusted as required.
+static constexpr uint8_t MAX_THREADS = 10;
+
+static constexpr auto FAILURE = -1;
+static constexpr auto SUCCESS = 0;
+
+constexpr auto bmcStateService = "xyz.openbmc_project.State.BMC";
+constexpr auto bmcZeroStateObject = "/xyz/openbmc_project/state/bmc0";
+constexpr auto bmcStateInterface = "xyz.openbmc_project.State.BMC";
+constexpr auto currentBMCStateProperty = "CurrentBMCState";
+constexpr auto bmcReadyState = "xyz.openbmc_project.State.BMC.BMCState.Ready";
+
+static constexpr auto eventLoggingServiceName = "xyz.openbmc_project.Logging";
+static constexpr auto eventLoggingObjectPath = "/xyz/openbmc_project/logging";
+static constexpr auto eventLoggingInterface =
+    "xyz.openbmc_project.Logging.Create";
+
+static constexpr auto systemdService = "org.freedesktop.systemd1";
+static constexpr auto systemdObjectPath = "/org/freedesktop/systemd1";
+static constexpr auto systemdManagerInterface =
+    "org.freedesktop.systemd1.Manager";
+} // namespace constants
+} // namespace vpd
diff --git a/vpd-manager/include/ddimm_parser.hpp b/vpd-manager/include/ddimm_parser.hpp
new file mode 100644
index 0000000..a53ed17
--- /dev/null
+++ b/vpd-manager/include/ddimm_parser.hpp
@@ -0,0 +1,123 @@
+#pragma once
+
+#include "constants.hpp"
+#include "exceptions.hpp"
+#include "logger.hpp"
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+namespace vpd
+{
+/**
+ * @brief Concrete class to implement DDIMM VPD parsing.
+ *
+ * The class inherits ParserInterface interface class and overrides the parser
+ * functionality to implement parsing logic for DDIMM VPD format.
+ */
+class DdimmVpdParser : public ParserInterface
+{
+  public:
+    // Deleted API's
+    DdimmVpdParser() = delete;
+    DdimmVpdParser(const DdimmVpdParser&) = delete;
+    DdimmVpdParser& operator=(const DdimmVpdParser&) = delete;
+    DdimmVpdParser(DdimmVpdParser&&) = delete;
+    DdimmVpdParser& operator=(DdimmVpdParser&&) = delete;
+
+    /**
+     * @brief Defaul destructor.
+     */
+    ~DdimmVpdParser() = default;
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] i_vpdVector - VPD data.
+     */
+    DdimmVpdParser(const types::BinaryVector& i_vpdVector) :
+        m_vpdVector(i_vpdVector)
+    {
+        if ((constants::DDIMM_11S_BARCODE_START +
+             constants::DDIMM_11S_BARCODE_LEN) > m_vpdVector.size())
+        {
+            throw(DataException("Malformed DDIMM VPD"));
+        }
+    }
+
+    /**
+     * @brief API to parse DDIMM VPD file.
+     *
+     * @return parsed VPD data
+     */
+    virtual types::VPDMapVariant parse() override;
+
+  private:
+    /**
+     * @brief API to read keyword data based on the type DDR4/DDR5.
+     *
+     * Updates the m_parsedVpdMap with read keyword data.
+     * @param[in] i_iterator - iterator to buffer containing VPD
+     */
+    void readKeywords(types::BinaryVector::const_iterator i_iterator);
+
+    /**
+     * @brief API to calculate DDIMM size from DDIMM VPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing VPD
+     * @return calculated size or 0 in case of any error.
+     */
+    size_t getDdimmSize(types::BinaryVector::const_iterator i_iterator);
+
+    /**
+     * @brief This function calculates DDR5 based DDIMM's capacity
+     *
+     * @param[in] i_iterator - iterator to buffer containing VPD
+     * @return calculated size or 0 in case of any error.
+     */
+    size_t
+        getDdr5BasedDdimmSize(types::BinaryVector::const_iterator i_iterator);
+
+    /**
+     * @brief This function calculates DDR4 based DDIMM's capacity
+     *
+     * @param[in] i_iterator - iterator to buffer containing VPD
+     * @return calculated size or 0 in case of any error.
+     */
+    size_t
+        getDdr4BasedDdimmSize(types::BinaryVector::const_iterator i_iterator);
+
+    /**
+     * @brief This function calculates DDR5 based die per package
+     *
+     * @param[in] i_ByteValue - the bit value for calculation
+     * @return die per package value.
+     */
+    uint8_t getDdr5DiePerPackage(uint8_t i_ByteValue);
+
+    /**
+     * @brief This function calculates DDR5 based density per die
+     *
+     * @param[in] i_ByteValue - the bit value for calculation
+     * @return density per die.
+     */
+    uint8_t getDdr5DensityPerDie(uint8_t i_ByteValue);
+
+    /**
+     * @brief This function checks the validity of the bits
+     *
+     * @param[in] i_ByteValue - the byte value with relevant bits
+     * @param[in] i_shift - shifter value to selects needed bits
+     * @param[in] i_minValue - minimum value it can contain
+     * @param[in] i_maxValue - maximum value it can contain
+     * @return true if valid else false.
+     */
+    bool checkValidValue(uint8_t i_ByteValue, uint8_t i_shift,
+                         uint8_t i_minValue, uint8_t i_maxValue);
+
+    // VPD file to be parsed
+    const types::BinaryVector& m_vpdVector;
+
+    // Stores parsed VPD data.
+    types::DdimmVpdMap m_parsedVpdMap{};
+};
+} // namespace vpd
diff --git a/vpd-manager/include/event_logger.hpp b/vpd-manager/include/event_logger.hpp
new file mode 100644
index 0000000..0080be6
--- /dev/null
+++ b/vpd-manager/include/event_logger.hpp
@@ -0,0 +1,170 @@
+#pragma once
+
+#include "constants.hpp"
+#include "types.hpp"
+
+#include <iostream>
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+namespace vpd
+{
+/**
+ * @brief Class for logging events.
+ *
+ * Class handles logging PEL under 'logging' service.
+ * Provide separate async API's for calling out inventory_path, device_path and
+ * i2c bus.
+ */
+class EventLogger
+{
+  public:
+    /**
+     * @brief An API to create a PEL with inventory path callout.
+     *
+     * This API calls an async method to create PEL, and also handles inventory
+     * path callout.
+     *
+     * Note: If inventory path callout info is not provided, it will create a
+     * PEL without any callout. Currently only one callout is handled in this
+     * API.
+     *
+     * @todo: Symbolic FRU and procedure callout needs to be handled in this
+     * API.
+     *
+     * @param[in] i_errorType - Enum to map with event message name.
+     * @param[in] i_severity - Severity of the event.
+     * @param[in] i_callouts - Callout information, list of tuple having
+     * inventory path and priority as input [optional].
+     * @param[in] i_fileName - File name.
+     * @param[in] i_funcName - Function name.
+     * @param[in] i_internalRc - Internal return code.
+     * @param[in] i_description - Error description.
+     * @param[in] i_userData1 - Additional user data [optional].
+     * @param[in] i_userData2 - Additional user data [optional].
+     * @param[in] i_symFru - Symblolic FRU callout data [optional].
+     * @param[in] i_procedure - Procedure callout data [optional].
+     *
+     * @throw exception in case of error.
+     */
+    static void createAsyncPelWithInventoryCallout(
+        const types::ErrorType& i_errorType,
+        const types::SeverityType& i_severity,
+        const std::vector<types::InventoryCalloutData>& i_callouts,
+        const std::string& i_fileName, const std::string& i_funcName,
+        const uint8_t i_internalRc, const std::string& i_description,
+        const std::optional<std::string> i_userData1,
+        const std::optional<std::string> i_userData2,
+        const std::optional<std::string> i_symFru,
+        const std::optional<std::string> i_procedure);
+
+    /**
+     * @brief An API to create a PEL with device path callout.
+     *
+     * @param[in] i_errorType - Enum to map with event message name.
+     * @param[in] i_severity - Severity of the event.
+     * @param[in] i_callouts - Callout information, list of tuple having device
+     * path and error number as input.
+     * @param[in] i_fileName - File name.
+     * @param[in] i_funcName - Function name.
+     * @param[in] i_internalRc - Internal return code.
+     * @param[in] i_userData1 - Additional user data [optional].
+     * @param[in] i_userData2 - Additional user data [optional].
+     */
+    static void createAsyncPelWithI2cDeviceCallout(
+        const types::ErrorType i_errorType,
+        const types::SeverityType i_severity,
+        const std::vector<types::DeviceCalloutData>& i_callouts,
+        const std::string& i_fileName, const std::string& i_funcName,
+        const uint8_t i_internalRc,
+        const std::optional<std::pair<std::string, std::string>> i_userData1,
+        const std::optional<std::pair<std::string, std::string>> i_userData2);
+
+    /**
+     * @brief An API to create a PEL with I2c bus callout.
+     *
+     * @param[in] i_errorType - Enum to map with event message name.
+     * @param[in] i_severity - Severity of the event.
+     * @param[in] i_callouts - Callout information, list of tuple having i2c
+     * bus, i2c address and error number as input.
+     * @param[in] i_fileName - File name.
+     * @param[in] i_funcName - Function name.
+     * @param[in] i_internalRc - Internal return code.
+     * @param[in] i_userData1 - Additional user data [optional].
+     * @param[in] i_userData2 - Additional user data [optional].
+     */
+    static void createAsyncPelWithI2cBusCallout(
+        const types::ErrorType i_errorType,
+        const types::SeverityType i_severity,
+        const std::vector<types::I2cBusCalloutData>& i_callouts,
+        const std::string& i_fileName, const std::string& i_funcName,
+        const uint8_t i_internalRc,
+        const std::optional<std::pair<std::string, std::string>> i_userData1,
+        const std::optional<std::pair<std::string, std::string>> i_userData2);
+
+    /**
+     * @brief An API to create a PEL.
+     *
+     * @param[in] i_errorType - Enum to map with event message name.
+     * @param[in] i_severity - Severity of the event.
+     * @param[in] i_fileName - File name.
+     * @param[in] i_funcName - Function name.
+     * @param[in] i_internalRc - Internal return code.
+     * @param[in] i_description - Error description.
+     * @param[in] i_userData1 - Additional user data [optional].
+     * @param[in] i_userData2 - Additional user data [optional].
+     * @param[in] i_symFru - Symblolic FRU callout data [optional].
+     * @param[in] i_procedure - Procedure callout data [optional].
+     *
+     * @todo: Symbolic FRU and procedure callout needs to be handled in this
+     * API.
+     */
+    static void createAsyncPel(
+        const types::ErrorType& i_errorType,
+        const types::SeverityType& i_severity, const std::string& i_fileName,
+        const std::string& i_funcName, const uint8_t i_internalRc,
+        const std::string& i_description,
+        const std::optional<std::string> i_userData1,
+        const std::optional<std::string> i_userData2,
+        const std::optional<std::string> i_symFru,
+        const std::optional<std::string> i_procedure);
+
+    /**
+     * @brief An API to create PEL.
+     *
+     * This API makes synchronous call to phosphor-logging Create method.
+     *
+     * @param[in] i_errorType - Enum to map with event message name.
+     * @param[in] i_severity - Severity of the event.
+     * @param[in] i_fileName - File name.
+     * @param[in] i_funcName - Function name.
+     * @param[in] i_internalRc - Internal return code.
+     * @param[in] i_description - Error description.
+     * @param[in] i_userData1 - Additional user data [optional].
+     * @param[in] i_userData2 - Additional user data [optional].
+     * @param[in] i_symFru - Symblolic FRU callout data [optional].s
+     * @param[in] i_procedure - Procedure callout data [optional].
+     *
+     * @todo: Symbolic FRU and procedure callout needs to be handled in this
+     * API.
+     */
+    static void createSyncPel(
+        const types::ErrorType& i_errorType,
+        const types::SeverityType& i_severity, const std::string& i_fileName,
+        const std::string& i_funcName, const uint8_t i_internalRc,
+        const std::string& i_description,
+        const std::optional<std::string> i_userData1,
+        const std::optional<std::string> i_userData2,
+        const std::optional<std::string> i_symFru,
+        const std::optional<std::string> i_procedure);
+
+  private:
+    static const std::unordered_map<types::SeverityType, std::string>
+        m_severityMap;
+    static const std::unordered_map<types::ErrorType, std::string>
+        m_errorMsgMap;
+    static const std::unordered_map<types::CalloutPriority, std::string>
+        m_priorityMap;
+};
+} // namespace vpd
diff --git a/vpd-manager/include/exceptions.hpp b/vpd-manager/include/exceptions.hpp
new file mode 100644
index 0000000..a787d08
--- /dev/null
+++ b/vpd-manager/include/exceptions.hpp
@@ -0,0 +1,157 @@
+#pragma once
+
+#include <stdexcept>
+
+namespace vpd
+{
+/** @class Exception
+ * @brief This class inherits std::runtime_error and overrrides "what" method
+ * to return the description of exception.
+ * This class also works as base class for custom exception classes for
+ * VPD repository.
+ */
+class Exception : public std::runtime_error
+{
+  public:
+    // deleted methods
+    Exception() = delete;
+    Exception(const Exception&) = delete;
+    Exception(Exception&&) = delete;
+    Exception& operator=(const Exception&) = delete;
+
+    // default destructor
+    ~Exception() = default;
+
+    /** @brief constructor
+     *
+     *  @param[in] msg - Information w.r.t exception.
+     */
+    explicit Exception(const std::string& msg) :
+        std::runtime_error(msg), m_errMsg(msg)
+    {}
+
+    /** @brief inline method to return exception string.
+     *
+     * This is overridden method of std::runtime class.
+     */
+    inline const char* what() const noexcept override
+    {
+        return m_errMsg.c_str();
+    }
+
+  private:
+    /** @brief string to hold the reason of exception */
+    std::string m_errMsg;
+
+}; // class Exception
+
+/** @class EccException
+ *
+ *  @brief This class extends Exceptions class and define type for ECC related
+ * exception in VPD.
+ */
+class EccException : public Exception
+{
+  public:
+    // deleted methods
+    EccException() = delete;
+    EccException(const EccException&) = delete;
+    EccException(EccException&&) = delete;
+    EccException& operator=(const EccException&) = delete;
+
+    // default destructor
+    ~EccException() = default;
+
+    /** @brief constructor
+     *
+     *  @param[in] msg - Information w.r.t exception.
+     */
+    explicit EccException(const std::string& msg) : Exception(msg) {}
+
+}; // class EccException
+
+/** @class DataException
+ *
+ * @brief This class extends Exceptions class and define type for data related
+ * exception in VPD
+ */
+class DataException : public Exception
+{
+  public:
+    // deleted methods
+    DataException() = delete;
+    DataException(const DataException&) = delete;
+    DataException(DataException&&) = delete;
+    DataException& operator=(const DataException&) = delete;
+
+    // default destructor
+    ~DataException() = default;
+
+    /** @brief constructor
+     *
+     *  @param[in] msg - string to define exception
+     */
+    explicit DataException(const std::string& msg) : Exception(msg) {}
+
+}; // class DataException
+
+class JsonException : public Exception
+{
+  public:
+    // deleted methods
+    JsonException() = delete;
+    JsonException(const JsonException&) = delete;
+    JsonException(JsonException&&) = delete;
+    JsonException& operator=(const JsonException&) = delete;
+
+    // default destructor
+    ~JsonException() = default;
+
+    /** @brief constructor
+     *  @param[in] msg - Information w.r.t. exception.
+     *  @param[in] path - Json path
+     */
+    JsonException(const std::string& msg, const std::string& path) :
+        Exception(msg), m_jsonPath(path)
+    {}
+
+    /** @brief Json path getter method.
+     *
+     *  @return - Json path
+     */
+    inline std::string getJsonPath() const
+    {
+        return m_jsonPath;
+    }
+
+  private:
+    /** To hold the path of Json that failed*/
+    std::string m_jsonPath;
+
+}; // class JSonException
+
+/** @class GpioException
+ *  @brief Custom handler for GPIO exception.
+ *
+ *  This class extends Exceptions class and define
+ *  type for GPIO related exception in VPD.
+ */
+class GpioException : public Exception
+{
+  public:
+    // deleted methods
+    GpioException() = delete;
+    GpioException(const GpioException&) = delete;
+    GpioException(GpioException&&) = delete;
+    GpioException& operator=(const GpioException&) = delete;
+
+    // default destructor
+    ~GpioException() = default;
+
+    /** @brief constructor
+     *  @param[in] msg - string to define exception
+     */
+    explicit GpioException(const std::string& msg) : Exception(msg) {}
+};
+
+} // namespace vpd
diff --git a/vpd-manager/include/gpio_monitor.hpp b/vpd-manager/include/gpio_monitor.hpp
new file mode 100644
index 0000000..476a31d
--- /dev/null
+++ b/vpd-manager/include/gpio_monitor.hpp
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "worker.hpp"
+
+#include <boost/asio/steady_timer.hpp>
+#include <nlohmann/json.hpp>
+#include <sdbusplus/asio/connection.hpp>
+
+#include <vector>
+
+namespace vpd
+{
+/**
+ * @brief class for GPIO event handling.
+ *
+ * Responsible for detecting events and handling them. It continuously
+ * monitors the presence of the FRU. If it detects any change, performs
+ * deletion of FRU VPD if FRU is not present, otherwise performs VPD
+ * collection if FRU gets added.
+ */
+class GpioEventHandler
+{
+  public:
+    GpioEventHandler() = delete;
+    ~GpioEventHandler() = default;
+    GpioEventHandler(const GpioEventHandler&) = delete;
+    GpioEventHandler& operator=(const GpioEventHandler&) = delete;
+    GpioEventHandler(GpioEventHandler&&) = delete;
+    GpioEventHandler& operator=(GpioEventHandler&&) = delete;
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] i_fruPath - EEPROM path of the FRU.
+     * @param[in] i_worker - pointer to the worker object.
+     * @param[in] i_ioContext - pointer to the io context object
+     */
+    GpioEventHandler(
+        const std::string i_fruPath, const std::shared_ptr<Worker>& i_worker,
+        const std::shared_ptr<boost::asio::io_context>& i_ioContext) :
+        m_fruPath(i_fruPath), m_worker(i_worker)
+    {
+        setEventHandlerForGpioPresence(i_ioContext);
+    }
+
+  private:
+    /**
+     * @brief API to take action based on GPIO presence pin value.
+     *
+     * This API takes action based on the change in the presence pin value.
+     * It performs deletion of FRU VPD if FRU is not present, otherwise performs
+     * VPD collection if FRU gets added.
+     *
+     * @param[in] i_isFruPresent - Holds the present status of the FRU.
+     */
+    void handleChangeInGpioPin(const bool& i_isFruPresent);
+
+    /**
+     * @brief An API to set event handler for FRUs GPIO presence.
+     *
+     * An API to set timer to call event handler to detect GPIO presence
+     * of the FRU.
+     *
+     * @param[in] i_ioContext - pointer to io context object
+     */
+    void setEventHandlerForGpioPresence(
+        const std::shared_ptr<boost::asio::io_context>& i_ioContext);
+
+    /**
+     * @brief API to handle timer expiry.
+     *
+     * This API handles timer expiry and checks on the GPIO presence state,
+     * takes action if there is any change in the GPIO presence value.
+     *
+     * @param[in] i_errorCode - Error Code
+     * @param[in] i_timerObj - Pointer to timer Object.
+     */
+    void handleTimerExpiry(
+        const boost::system::error_code& i_errorCode,
+        const std::shared_ptr<boost::asio::steady_timer>& i_timerObj);
+
+    const std::string m_fruPath;
+
+    const std::shared_ptr<Worker>& m_worker;
+
+    // Preserves the GPIO pin value to compare. Default value is false.
+    bool m_prevPresencePinValue = false;
+};
+
+class GpioMonitor
+{
+  public:
+    GpioMonitor() = delete;
+    ~GpioMonitor() = default;
+    GpioMonitor(const GpioMonitor&) = delete;
+    GpioMonitor& operator=(const GpioMonitor&) = delete;
+    GpioMonitor(GpioMonitor&&) = delete;
+    GpioMonitor& operator=(GpioMonitor&&) = delete;
+
+    /**
+     * @brief constructor
+     *
+     * @param[in] i_sysCfgJsonObj - System config JSON Object.
+     * @param[in] i_worker - pointer to the worker object.
+     * @param[in] i_ioContext - pointer to IO context object.
+     */
+    GpioMonitor(const nlohmann::json i_sysCfgJsonObj,
+                const std::shared_ptr<Worker>& i_worker,
+                const std::shared_ptr<boost::asio::io_context>& i_ioContext) :
+        m_sysCfgJsonObj(i_sysCfgJsonObj)
+    {
+        if (!m_sysCfgJsonObj.empty())
+        {
+            initHandlerForGpio(i_ioContext, i_worker);
+        }
+        else
+        {
+            throw std::runtime_error(
+                "Gpio Monitoring can't be instantiated with empty config JSON");
+        }
+    }
+
+  private:
+    /**
+     * @brief API to instantiate GpioEventHandler for GPIO pins.
+     *
+     * This API will extract the GPIO information from system config JSON
+     * and instantiate event handler for GPIO pins.
+     *
+     * @param[in] i_ioContext - Pointer to IO context object.
+     * @param[in] i_worker - Pointer to worker class.
+     */
+    void initHandlerForGpio(
+        const std::shared_ptr<boost::asio::io_context>& i_ioContext,
+        const std::shared_ptr<Worker>& i_worker);
+
+    // Array of event handlers for all the attachable FRUs.
+    std::vector<std::shared_ptr<GpioEventHandler>> m_gpioEventHandlerObjects;
+
+    const nlohmann::json& m_sysCfgJsonObj;
+};
+} // namespace vpd
diff --git a/vpd-manager/include/ipz_parser.hpp b/vpd-manager/include/ipz_parser.hpp
new file mode 100644
index 0000000..2d50ddd
--- /dev/null
+++ b/vpd-manager/include/ipz_parser.hpp
@@ -0,0 +1,273 @@
+#pragma once
+
+#include "logger.hpp"
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+#include <fstream>
+#include <string_view>
+
+namespace vpd
+{
+/**
+ * @brief Concrete class to implement IPZ VPD parsing.
+ *
+ * The class inherits ParserInterface interface class and overrides the parser
+ * functionality to implement parsing logic for IPZ VPD format.
+ */
+class IpzVpdParser : public ParserInterface
+{
+  public:
+    // Deleted APIs
+    IpzVpdParser() = delete;
+    IpzVpdParser(const IpzVpdParser&) = delete;
+    IpzVpdParser& operator=(const IpzVpdParser&) = delete;
+    IpzVpdParser(IpzVpdParser&&) = delete;
+    IpzVpdParser& operator=(IpzVpdParser&&) = delete;
+
+    /**
+     * @brief Constructor.
+     *
+     * @param[in] vpdVector - VPD data.
+     * @param[in] vpdFilePath - Path to VPD EEPROM.
+     * @param[in] vpdStartOffset - Offset from where VPD starts in the file.
+     * Defaulted to 0.
+     */
+    IpzVpdParser(const types::BinaryVector& vpdVector,
+                 const std::string& vpdFilePath, size_t vpdStartOffset = 0) :
+        m_vpdVector(vpdVector), m_vpdFilePath(vpdFilePath),
+        m_vpdStartOffset(vpdStartOffset)
+    {
+        try
+        {
+            m_vpdFileStream.exceptions(
+                std::ifstream::badbit | std::ifstream::failbit);
+            m_vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::out |
+                                                  std::ios::binary);
+        }
+        catch (const std::fstream::failure& e)
+        {
+            logging::logMessage(e.what());
+        }
+    }
+
+    /**
+     * @brief Defaul destructor.
+     */
+    ~IpzVpdParser() = default;
+
+    /**
+     * @brief API to parse IPZ VPD file.
+     *
+     * Note: Caller needs to check validity of the map returned. Throws
+     * exception in certain situation, needs to be handled accordingly.
+     *
+     * @return parsed VPD data.
+     */
+    virtual types::VPDMapVariant parse() override;
+
+    /**
+     * @brief API to check validity of VPD header.
+     *
+     * Note: The API throws exception in case of any failure or malformed VDP.
+     *
+     * @param[in] itrToVPD - Iterator to the beginning of VPD file.
+     * Don't change the parameter to reference as movement of passsed iterator
+     * to an offset is not required after header check.
+     */
+    void checkHeader(types::BinaryVector::const_iterator itrToVPD);
+
+    /**
+     * @brief API to read keyword's value from hardware
+     *
+     * @param[in] i_paramsToReadData - Data required to perform read
+     *
+     * @throw
+     * sdbusplus::xyz::openbmc_project::Common::Device::Error::ReadFailure.
+     *
+     * @return On success return the value read. On failure throw exception.
+     */
+    types::DbusVariantType
+        readKeywordFromHardware(const types::ReadVpdParams i_paramsToReadData);
+
+    /**
+     * @brief API to write keyword's value on hardware.
+     *
+     * @param[in] i_paramsToWriteData - Data required to perform write.
+     *
+     * @throw sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument.
+     * @throw sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed.
+     * @throw DataException
+     * @throw EccException
+     *
+     *
+     * @return On success returns number of bytes written on hardware, On
+     * failure throws exception.
+     */
+    int writeKeywordOnHardware(const types::WriteVpdParams i_paramsToWriteData);
+
+  private:
+    /**
+     * @brief Check ECC of VPD header.
+     *
+     * @return true/false based on check result.
+     */
+    bool vhdrEccCheck();
+
+    /**
+     * @brief Check ECC of VTOC.
+     *
+     * @return true/false based on check result.
+     */
+    bool vtocEccCheck();
+
+    /**
+     * @brief Check ECC of a record.
+     *
+     * Note: Throws exception in case of failure. Caller need to handle as
+     * required.
+     *
+     * @param[in] iterator - Iterator to the record.
+     * @return success/failre
+     */
+    bool recordEccCheck(types::BinaryVector::const_iterator iterator);
+
+    /**
+     * @brief API to read VTOC record.
+     *
+     * The API reads VTOC record and returns the length of PT keyword.
+     *
+     * Note: Throws exception in case of any error. Caller need to handle as
+     * required.
+     *
+     * @param[in] itrToVPD - Iterator to begining of VPD data.
+     * @return Length of PT keyword.
+     */
+    auto readTOC(types::BinaryVector::const_iterator& itrToVPD);
+
+    /**
+     * @brief API to read PT record.
+     *
+     * Note: Throws exception in case ECC check fails.
+     *
+     * @param[in] itrToPT - Iterator to PT record in VPD vector.
+     * @param[in] ptLength - length of the PT record.
+     * @return List of record's offset.
+     */
+    types::RecordOffsetList readPT(types::BinaryVector::const_iterator& itrToPT,
+                                   auto ptLength);
+
+    /**
+     * @brief API to read keyword data based on its encoding type.
+     *
+     * @param[in] kwdName - Name of the keyword.
+     * @param[in] kwdDataLength - Length of keyword data.
+     * @param[in] itrToKwdData - Iterator to start of keyword data.
+     * @return keyword data, empty otherwise.
+     */
+    std::string readKwData(std::string_view kwdName, std::size_t kwdDataLength,
+                           types::BinaryVector::const_iterator itrToKwdData);
+
+    /**
+     * @brief API to read keyword and its value under a record.
+     *
+     * @param[in] iterator - pointer to the start of keywords under the record.
+     * @return keyword-value map of keywords under that record.
+     */
+    types::IPZVpdMap::mapped_type
+        readKeywords(types::BinaryVector::const_iterator& itrToKwds);
+
+    /**
+     * @brief API to process a record.
+     *
+     * @param[in] recordOffset - Offset of the record in VPD.
+     */
+    void processRecord(auto recordOffset);
+
+    /**
+     * @brief Get keyword's value from record
+     *
+     * @param[in] i_record - Record's name
+     * @param[in] i_keyword - Keyword's name
+     * @param[in] i_recordDataOffset - Record's offset value
+     *
+     * @throw std::runtime_error
+     *
+     * @return On success return bytes read, on failure throws error.
+     */
+    types::BinaryVector getKeywordValueFromRecord(
+        const types::Record& i_recordName, const types::Keyword& i_keywordName,
+        const types::RecordOffset& i_recordDataOffset);
+
+    /**
+     * @brief Get record's details from VTOC's PT keyword value
+     *
+     * This API parses through VTOC's PT keyword value and returns the given
+     * record's offset, record's length, ECC offset and ECC length.
+     *
+     * @param[in] i_record - Record's name.
+     * @param[in] i_vtocOffset - Offset to VTOC record
+     *
+     * @return On success return record's details, on failure return empty
+     * buffer.
+     */
+    types::RecordData
+        getRecordDetailsFromVTOC(const types::Record& l_recordName,
+                                 const types::RecordOffset& i_vtocOffset);
+
+    /**
+     * @brief API to update record's ECC
+     *
+     * This API is required to update the record's ECC based on the record's
+     * current data.
+     *
+     * @param[in] i_recordDataOffset - Record's data offset
+     * @param[in] i_recordDataLength - Record's data length
+     * @param[in] i_recordECCOffset - Record's ECC offset
+     * @param[in] i_recordECCLength - Record's ECC length
+     * @param[in,out] io_vpdVector - FRU VPD in vector to update record's ECC.
+     *
+     * @throw EccException
+     */
+    void updateRecordECC(const auto& i_recordDataOffset,
+                         const auto& i_recordDataLength,
+                         const auto& i_recordECCOffset,
+                         size_t i_recordECCLength,
+                         types::BinaryVector& io_vpdVector);
+
+    /**
+     * @brief API to set record's keyword's value on hardware.
+     *
+     * @param[in] i_recordName - Record name.
+     * @param[in] i_keywordName - Keyword name.
+     * @param[in] i_keywordData - Keyword data.
+     * @param[in] i_recordDataOffset - Offset to record's data.
+     * @param[in,out] io_vpdVector - FRU VPD in vector to read and write
+     * keyword's value.
+     *
+     * @throw DataException
+     *
+     * @return On success returns number of bytes set. On failure returns -1.
+     */
+    int setKeywordValueInRecord(const types::Record& i_recordName,
+                                const types::Keyword& i_keywordName,
+                                const types::BinaryVector& i_keywordData,
+                                const types::RecordOffset& i_recordDataOffset,
+                                types::BinaryVector& io_vpdVector);
+
+    // Holds VPD data.
+    const types::BinaryVector& m_vpdVector;
+
+    // stores parsed VPD data.
+    types::IPZVpdMap m_parsedVPDMap{};
+
+    // Holds the VPD file path
+    const std::string& m_vpdFilePath;
+
+    // Stream to the VPD file. Required to correct ECC
+    std::fstream m_vpdFileStream;
+
+    // VPD start offset. Required for ECC correction.
+    size_t m_vpdStartOffset = 0;
+};
+} // namespace vpd
diff --git a/vpd-manager/include/isdimm_parser.hpp b/vpd-manager/include/isdimm_parser.hpp
new file mode 100644
index 0000000..091285c
--- /dev/null
+++ b/vpd-manager/include/isdimm_parser.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+#include <string_view>
+
+namespace vpd
+{
+/**
+ * @brief Concrete class to implement JEDEC SPD parsing.
+ *
+ * The class inherits ParserInterface interface class and overrides the parser
+ * functionality to implement parsing logic for JEDEC SPD format.
+ */
+class JedecSpdParser : public ParserInterface
+{
+  public:
+    // Deleted API's
+    JedecSpdParser() = delete;
+    JedecSpdParser(const JedecSpdParser&) = delete;
+    JedecSpdParser& operator=(const JedecSpdParser&) = delete;
+    JedecSpdParser(JedecSpdParser&&) = delete;
+    JedecSpdParser& operator=(JedecSpdParser&&) = delete;
+    ~JedecSpdParser() = default;
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] i_spdVector - JEDEC SPD data.
+     */
+    explicit JedecSpdParser(const types::BinaryVector& i_spdVector) :
+        m_memSpd(i_spdVector)
+    {}
+
+    /**
+     * @brief Parse the memory SPD binary data.
+     *
+     * Collects and emplace the keyword-value pairs in map.
+     *
+     * @return map of keyword:value
+     */
+    types::VPDMapVariant parse();
+
+  private:
+    /**
+     * @brief An API to read keywords.
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return- map of kwd:value
+     */
+    types::JedecSpdMap
+        readKeywords(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function calculates DIMM size from DDR4 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated size or 0 in case of any error.
+     */
+    auto getDDR4DimmCapacity(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function calculates part number from DDR4 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated part number or a default value.
+     */
+    std::string_view
+        getDDR4PartNumber(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function calculates serial number from DDR4 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated serial number or a default value.
+     */
+    std::string
+        getDDR4SerialNumber(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function allocates FRU number based on part number
+     *
+     * Mappings for FRU number from calculated part number is used
+     * for DDR4 ISDIMM.
+     *
+     * @param[in] i_partNumber - part number of the DIMM
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return allocated FRU number or a default value
+     */
+    std::string_view
+        getDDR4FruNumber(const std::string& i_partNumber,
+                         types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function allocates CCIN based on part number for DDR4 SPD
+     *
+     * @param[in] i_partNumber - part number of the DIMM
+     * @return allocated CCIN or a default value.
+     */
+    std::string_view getDDR4CCIN(const std::string& i_partNumber);
+
+    /**
+     * @brief This function calculates DIMM size from DDR5 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated size or 0 in case of any error.
+     */
+    auto getDDR5DimmCapacity(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function calculates part number from DDR5 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated part number or a default value.
+     */
+    auto getDDR5PartNumber(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function calculates serial number from DDR5 SPD
+     *
+     * @param[in] i_iterator - iterator to buffer containing SPD
+     * @return calculated serial number.
+     */
+    auto getDDR5SerialNumber(types::BinaryVector::const_iterator& i_iterator);
+
+    /**
+     * @brief This function allocates FRU number based on part number
+     *
+     * Mappings for FRU number from calculated part number is used
+     * for DDR5 ISDIMM.
+     *
+     * @param[in] i_partNumber - part number of the DIMM
+     * @return allocated FRU number.
+     */
+    auto getDDR5FruNumber(const std::string& i_partNumber);
+
+    /**
+     * @brief This function allocates CCIN based on part number for DDR5 SPD
+     *
+     * @param[in] i_partNumber - part number of the DIMM
+     * @return allocated CCIN.
+     */
+    auto getDDR5CCIN(const std::string& i_partNumber);
+
+    // SPD file to be parsed
+    const types::BinaryVector& m_memSpd;
+};
+
+} // namespace vpd
diff --git a/vpd-manager/include/keyword_vpd_parser.hpp b/vpd-manager/include/keyword_vpd_parser.hpp
new file mode 100644
index 0000000..ae30a34
--- /dev/null
+++ b/vpd-manager/include/keyword_vpd_parser.hpp
@@ -0,0 +1,97 @@
+#pragma once
+
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+namespace vpd
+{
+
+/**
+ * @brief Concrete class to implement Keyword VPD parsing
+ *
+ * The class inherits ParserInterface class and overrides the parser
+ * functionality to implement parsing logic for Keyword VPD format.
+ */
+class KeywordVpdParser : public ParserInterface
+{
+  public:
+    KeywordVpdParser() = delete;
+    KeywordVpdParser(const KeywordVpdParser&) = delete;
+    KeywordVpdParser(KeywordVpdParser&&) = delete;
+    ~KeywordVpdParser() = default;
+
+    /**
+     * @brief Constructor
+     *
+     * @param kwVpdVector - move it to object's m_keywordVpdVector
+     */
+    KeywordVpdParser(const types::BinaryVector& kwVpdVector) :
+        m_keywordVpdVector(kwVpdVector),
+        m_vpdIterator(m_keywordVpdVector.begin())
+    {}
+
+    /**
+     * @brief A wrapper function to parse the keyword VPD binary data.
+     *
+     * It validates certain tags and checksum data, calls helper function
+     * to parse and emplace the data as keyword-value pairs in KeywordVpdMap.
+     *
+     * @throw DataException - VPD is not valid
+     * @return map of keyword:value
+     */
+    types::VPDMapVariant parse();
+
+  private:
+    /**
+     * @brief Parse the VPD data and emplace them as pair into the Map.
+     *
+     * @throw DataException - VPD data size is 0, check VPD
+     * @return map of keyword:value
+     */
+    types::KeywordVpdMap populateVpdMap();
+
+    /**
+     * @brief Validate checksum.
+     *
+     * Finding the 2's complement of sum of all the
+     * keywords,values and large resource identifier string.
+     *
+     * @param[in] i_checkSumStart - VPD iterator pointing at checksum start
+     * value
+     * @param[in] i_checkSumEnd - VPD iterator pointing at checksum end value
+     * @throw DataException - checksum invalid, check VPD
+     */
+    void validateChecksum(types::BinaryVector::const_iterator i_checkSumStart,
+                          types::BinaryVector::const_iterator i_checkSumEnd);
+
+    /**
+     * @brief It reads 2 bytes from current VPD pointer
+     *
+     * @return 2 bytes of VPD data
+     */
+    inline size_t getKwDataSize()
+    {
+        return (*(m_vpdIterator + 1) << 8 | *m_vpdIterator);
+    }
+
+    /**
+     * @brief Check for given number of bytes validity
+     *
+     * Check if number of elements from (begining of the vector) to (iterator +
+     * numberOfBytes) is lesser than or equal to the total no.of elements in
+     * the vector. This check is performed before advancement of the iterator.
+     *
+     * @param[in] numberOfBytes - no.of positions the iterator is going to be
+     * iterated
+     *
+     * @throw DataException - Truncated VPD data, check VPD.
+     */
+    void checkNextBytesValidity(uint8_t numberOfBytes);
+
+    /*Vector of keyword VPD data*/
+    const types::BinaryVector& m_keywordVpdVector;
+
+    /*Iterator to VPD data*/
+    types::BinaryVector::const_iterator m_vpdIterator;
+};
+} // namespace vpd
diff --git a/vpd-manager/include/logger.hpp b/vpd-manager/include/logger.hpp
new file mode 100644
index 0000000..a4160c1
--- /dev/null
+++ b/vpd-manager/include/logger.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <iostream>
+#include <source_location>
+#include <string_view>
+
+namespace vpd
+{
+/**
+ * @brief The namespace defines logging related methods for VPD.
+ */
+namespace logging
+{
+
+/**
+ * @brief An api to log message.
+ * This API should be called to log message. It will auto append information
+ * like file name, line and function name to the message being logged.
+ *
+ * @param[in] message - Information that we want  to log.
+ * @param[in] location - Object of source_location class.
+ */
+void logMessage(std::string_view message, const std::source_location& location =
+                                              std::source_location::current());
+} // namespace logging
+} // namespace vpd
diff --git a/vpd-manager/include/manager.hpp b/vpd-manager/include/manager.hpp
new file mode 100644
index 0000000..cb64123
--- /dev/null
+++ b/vpd-manager/include/manager.hpp
@@ -0,0 +1,300 @@
+#pragma once
+
+#include "constants.hpp"
+#include "gpio_monitor.hpp"
+#include "types.hpp"
+#include "worker.hpp"
+
+#include <sdbusplus/asio/object_server.hpp>
+
+namespace vpd
+{
+/**
+ * @brief Class to manage VPD processing.
+ *
+ * The class is responsible to implement methods to manage VPD on the system.
+ * It also implements methods to be exposed over D-Bus required to access/edit
+ * VPD data.
+ */
+class Manager
+{
+  public:
+    /**
+     * List of deleted methods.
+     */
+    Manager(const Manager&) = delete;
+    Manager& operator=(const Manager&) = delete;
+    Manager(Manager&&) = delete;
+
+    /**
+     * @brief Constructor.
+     *
+     * @param[in] ioCon - IO context.
+     * @param[in] iFace - interface to implement.
+     * @param[in] connection - Dbus Connection.
+     */
+    Manager(const std::shared_ptr<boost::asio::io_context>& ioCon,
+            const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
+            const std::shared_ptr<sdbusplus::asio::connection>& asioConnection);
+
+    /**
+     * @brief Destructor.
+     */
+    ~Manager() = default;
+
+    /**
+     * @brief Update keyword value.
+     *
+     * This API is used to update keyword value on the given input path and its
+     * redundant path(s) if any taken from system config JSON.
+     *
+     * To update IPZ type VPD, input parameter for writing should be in the form
+     * of (Record, Keyword, Value). Eg: ("VINI", "SN", {0x01, 0x02, 0x03}).
+     *
+     * To update Keyword type VPD, input parameter for writing should be in the
+     * form of (Keyword, Value). Eg: ("PE", {0x01, 0x02, 0x03}).
+     *
+     * @param[in] i_vpdPath - Path (inventory object path/FRU EEPROM path).
+     * @param[in] i_paramsToWriteData - Input details.
+     *
+     * @return On success returns number of bytes written, on failure returns
+     * -1.
+     */
+    int updateKeyword(const types::Path i_vpdPath,
+                      const types::WriteVpdParams i_paramsToWriteData);
+
+    /**
+     * @brief Update keyword value on hardware.
+     *
+     * This API is used to update keyword value on hardware. Updates only on the
+     * given input hardware path, does not look for corresponding redundant or
+     * primary path against the given path. To update corresponding paths, make
+     * separate call with respective path.
+     *
+     * To update IPZ type VPD, input parameter for writing should be in the form
+     * of (Record, Keyword, Value). Eg: ("VINI", "SN", {0x01, 0x02, 0x03}).
+     *
+     * To update Keyword type VPD, input parameter for writing should be in the
+     * form of (Keyword, Value). Eg: ("PE", {0x01, 0x02, 0x03}).
+     *
+     * @param[in] i_fruPath - EEPROM path of the FRU.
+     * @param[in] i_paramsToWriteData - Input details.
+     *
+     * @return On success returns number of bytes written, on failure returns
+     * -1.
+     */
+    int updateKeywordOnHardware(
+        const types::Path i_fruPath,
+        const types::WriteVpdParams i_paramsToWriteData) noexcept;
+
+    /**
+     * @brief Read keyword value.
+     *
+     * API can be used to read VPD keyword from the given input path.
+     *
+     * To read keyword of type IPZ, input parameter for reading should be in the
+     * form of (Record, Keyword). Eg: ("VINI", "SN").
+     *
+     * To read keyword from keyword type VPD, just keyword name has to be
+     * supplied in the input parameter. Eg: ("SN").
+     *
+     * @param[in] i_fruPath - EEPROM path.
+     * @param[in] i_paramsToReadData - Input details.
+     *
+     * @throw
+     * sdbusplus::xyz::openbmc_project::Common::Device::Error::ReadFailure.
+     *
+     * @return On success returns the read value in variant of array of bytes.
+     * On failure throws exception.
+     */
+    types::DbusVariantType
+        readKeyword(const types::Path i_fruPath,
+                    const types::ReadVpdParams i_paramsToReadData);
+
+    /**
+     * @brief Collect single FRU VPD
+     * API can be used to perform VPD collection for the given FRU, only if the
+     * current state of the system matches with the state at which the FRU is
+     * allowed for VPD recollection.
+     *
+     * @param[in] i_dbusObjPath - D-bus object path
+     */
+    void collectSingleFruVpd(
+        const sdbusplus::message::object_path& i_dbusObjPath);
+
+    /**
+     * @brief Delete single FRU VPD
+     * API can be used to perform VPD deletion for the given FRU.
+     *
+     * @param[in] i_dbusObjPath - D-bus object path
+     */
+    void deleteSingleFruVpd(
+        const sdbusplus::message::object_path& i_dbusObjPath);
+
+    /**
+     * @brief Get expanded location code.
+     *
+     * API to get expanded location code from the unexpanded location code.
+     *
+     * @param[in] i_unexpandedLocationCode - Unexpanded location code.
+     * @param[in] i_nodeNumber - Denotes the node in case of a multi-node
+     * configuration, defaulted to zero incase of single node system.
+     *
+     * @throw xyz.openbmc_project.Common.Error.InvalidArgument for
+     * invalid argument.
+     *
+     * @return Location code of the FRU.
+     */
+    std::string getExpandedLocationCode(
+        const std::string& i_unexpandedLocationCode,
+        [[maybe_unused]] const uint16_t i_nodeNumber = 0);
+
+    /**
+     * @brief Get D-Bus object path of FRUs from expanded location code.
+     *
+     * An API to get list of FRU D-Bus object paths for a given expanded
+     * location code.
+     *
+     * @param[in] i_expandedLocationCode - Expanded location code.
+     *
+     * @throw xyz.openbmc_project.Common.Error.InvalidArgument for
+     * invalid argument.
+     *
+     * @return List of FRUs D-Bus object paths for the given location code.
+     */
+    types::ListOfPaths getFrusByExpandedLocationCode(
+        const std::string& i_expandedLocationCode);
+
+    /**
+     * @brief Get D-Bus object path of FRUs from unexpanded location code.
+     *
+     * An API to get list of FRU D-Bus object paths for a given unexpanded
+     * location code.
+     *
+     * @param[in] i_unexpandedLocationCode - Unexpanded location code.
+     * @param[in] i_nodeNumber - Denotes the node in case of a multi-node
+     * configuration, defaulted to zero incase of single node system.
+     *
+     * @throw xyz.openbmc_project.Common.Error.InvalidArgument for
+     * invalid argument.
+     *
+     * @return List of FRUs D-Bus object paths for the given location code.
+     */
+    types::ListOfPaths getFrusByUnexpandedLocationCode(
+        const std::string& i_unexpandedLocationCode,
+        [[maybe_unused]] const uint16_t i_nodeNumber = 0);
+
+    /**
+     * @brief Get Hardware path
+     * API can be used to get EEPROM path for the given inventory path.
+     *
+     * @param[in] i_dbusObjPath - D-bus object path
+     *
+     * @return Corresponding EEPROM path.
+     */
+    std::string getHwPath(const sdbusplus::message::object_path& i_dbusObjPath);
+
+    /**
+     * @brief  Perform VPD recollection
+     * This api will trigger parser to perform VPD recollection for FRUs that
+     * can be replaced at standby.
+     */
+    void performVpdRecollection();
+
+    /**
+     * @brief Get unexpanded location code.
+     *
+     * An API to get unexpanded location code and node number from expanded
+     * location code.
+     *
+     * @param[in] i_expandedLocationCode - Expanded location code.
+     *
+     * @throw xyz.openbmc_project.Common.Error.InvalidArgument for
+     * invalid argument.
+     *
+     * @return Location code in unexpanded format and its node number.
+     */
+    std::tuple<std::string, uint16_t>
+        getUnexpandedLocationCode(const std::string& i_expandedLocationCode);
+
+  private:
+#ifdef IBM_SYSTEM
+    /**
+     * @brief API to set timer to detect system VPD over D-Bus.
+     *
+     * System VPD is required before bus name for VPD-Manager is claimed. Once
+     * system VPD is published, VPD for other FRUs should be collected. This API
+     * detects id system VPD is already published on D-Bus and based on that
+     * triggers VPD collection for rest of the FRUs.
+     *
+     * Note: Throws exception in case of any failure. Needs to be handled by the
+     * caller.
+     */
+    void SetTimerToDetectSVPDOnDbus();
+
+    /**
+     * @brief Set timer to detect and set VPD collection status for the system.
+     *
+     * Collection of FRU VPD is triggered in a separate thread. Resulting in
+     * multiple threads at  a given time. The API creates a timer which on
+     * regular interval will check if all the threads were collected back and
+     * sets the status of the VPD collection for the system accordingly.
+     *
+     * @throw std::runtime_error
+     */
+    void SetTimerToDetectVpdCollectionStatus();
+
+    /**
+     * @brief API to register callback for "AssetTag" property change.
+     */
+    void registerAssetTagChangeCallback();
+
+    /**
+     * @brief Callback API to be triggered on "AssetTag" property change.
+     *
+     * @param[in] i_msg - The callback message.
+     */
+    void processAssetTagChangeCallback(sdbusplus::message_t& i_msg);
+#endif
+
+    /**
+     * @brief An api to check validity of unexpanded location code.
+     *
+     * @param[in] i_locationCode - Unexpanded location code.
+     *
+     * @return True/False based on validity check.
+     */
+    bool isValidUnexpandedLocationCode(const std::string& i_locationCode);
+
+    /**
+     * @brief API to register callback for Host state change.
+     */
+    void registerHostStateChangeCallback();
+
+    /**
+     * @brief API to process host state change callback.
+     *
+     * @param[in] i_msg - Callback message.
+     */
+    void hostStateChangeCallBack(sdbusplus::message_t& i_msg);
+
+    // Shared pointer to asio context object.
+    const std::shared_ptr<boost::asio::io_context>& m_ioContext;
+
+    // Shared pointer to Dbus interface class.
+    const std::shared_ptr<sdbusplus::asio::dbus_interface>& m_interface;
+
+    // Shared pointer to bus connection.
+    const std::shared_ptr<sdbusplus::asio::connection>& m_asioConnection;
+
+    // Shared pointer to worker class
+    std::shared_ptr<Worker> m_worker;
+
+    // Shared pointer to GpioMonitor class
+    std::shared_ptr<GpioMonitor> m_gpioMonitor;
+
+    // Variable to hold current collection status
+    std::string m_vpdCollectionStatus = "NotStarted";
+};
+
+} // namespace vpd
diff --git a/vpd-manager/include/parser.hpp b/vpd-manager/include/parser.hpp
new file mode 100644
index 0000000..9af3088
--- /dev/null
+++ b/vpd-manager/include/parser.hpp
@@ -0,0 +1,126 @@
+#pragma once
+
+#include "parser_factory.hpp"
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+#include <string.h>
+
+#include <nlohmann/json.hpp>
+
+#include <iostream>
+
+namespace vpd
+{
+/**
+ * @brief Class to implement a wrapper around concrete parser class.
+ * The class based on VPD file passed, selects the required parser and exposes
+ * API to parse the VPD and return the parsed data in required format to the
+ * caller.
+ */
+class Parser
+{
+  public:
+    /**
+     * @brief Constructor
+     *
+     * @param[in] vpdFilePath - Path to the VPD file.
+     * @param[in] parsedJson - Parsed JSON.
+     */
+    Parser(const std::string& vpdFilePath, nlohmann::json parsedJson);
+
+    /**
+     * @brief API to implement a generic parsing logic.
+     *
+     * This API is called to select parser based on the vpd data extracted from
+     * the VPD file path passed to the constructor of the class.
+     * It further parses the data based on the parser selected and returned
+     * parsed map to the caller.
+     */
+    types::VPDMapVariant parse();
+
+    /**
+     * @brief API to get parser instance based on VPD type.
+     *
+     * This API detects the VPD type based on the file path passed to the
+     * constructor of the class and returns the respective parser instance.
+     *
+     * @return Parser instance.
+     */
+    std::shared_ptr<vpd::ParserInterface> getVpdParserInstance();
+
+    /**
+     * @brief Update keyword value.
+     *
+     * This API is used to update keyword value on the EEPROM path and its
+     * redundant path(s) if any taken from system config JSON. And also updates
+     * keyword value on DBus.
+     *
+     * To update IPZ type VPD, input parameter for writing should be in the form
+     * of (Record, Keyword, Value). Eg: ("VINI", "SN", {0x01, 0x02, 0x03}).
+     *
+     * To update Keyword type VPD, input parameter for writing should be in the
+     * form of (Keyword, Value). Eg: ("PE", {0x01, 0x02, 0x03}).
+     *
+     * @param[in] i_paramsToWriteData - Input details.
+     *
+     * @return On success returns number of bytes written, on failure returns
+     * -1.
+     */
+    int updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData);
+
+    /**
+     * @brief Update keyword value on hardware.
+     *
+     * This API is used to update keyword value on the hardware path.
+     *
+     * To update IPZ type VPD, input parameter for writing should be in the form
+     * of (Record, Keyword, Value). Eg: ("VINI", "SN", {0x01, 0x02, 0x03}).
+     *
+     * To update Keyword type VPD, input parameter for writing should be in the
+     * form of (Keyword, Value). Eg: ("PE", {0x01, 0x02, 0x03}).
+     *
+     * @param[in] i_paramsToWriteData - Input details.
+     *
+     * @return On success returns number of bytes written, on failure returns
+     * -1.
+     */
+    int updateVpdKeywordOnHardware(
+        const types::WriteVpdParams& i_paramsToWriteData);
+
+  private:
+    /**
+     * @brief Update keyword value on redundant path.
+     *
+     * This API is used to update keyword value on the given redundant path(s).
+     *
+     * To update IPZ type VPD, input parameter for writing should be in the form
+     * of (Record, Keyword, Value). Eg: ("VINI", "SN", {0x01, 0x02, 0x03}).
+     *
+     * To update Keyword type VPD, input parameter for writing should be in the
+     * form of (Keyword, Value). Eg: ("PE", {0x01, 0x02, 0x03}).
+     *
+     * @param[in] i_fruPath - Redundant EEPROM path.
+     * @param[in] i_paramsToWriteData - Input details.
+     *
+     * @return On success returns number of bytes written, on failure returns
+     * -1.
+     */
+    int updateVpdKeywordOnRedundantPath(
+        const std::string& i_fruPath,
+        const types::WriteVpdParams& i_paramsToWriteData);
+
+    // holds offfset to VPD if applicable.
+    size_t m_vpdStartOffset = 0;
+
+    // Path to the VPD file
+    const std::string& m_vpdFilePath;
+
+    // Path to configuration file, can be empty.
+    nlohmann::json m_parsedJson;
+
+    // Vector to hold VPD.
+    types::BinaryVector m_vpdVector;
+
+}; // parser
+} // namespace vpd
diff --git a/vpd-manager/include/parser_factory.hpp b/vpd-manager/include/parser_factory.hpp
new file mode 100644
index 0000000..819ec59
--- /dev/null
+++ b/vpd-manager/include/parser_factory.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "logger.hpp"
+#include "parser_interface.hpp"
+#include "types.hpp"
+
+#include <memory>
+
+namespace vpd
+{
+/**
+ * @brief Factory calss to instantiate concrete parser class.
+ *
+ * This class should be used to instantiate an instance of parser class based
+ * on the type of vpd file.
+ */
+class ParserFactory
+{
+  public:
+    // Deleted APIs
+    ParserFactory() = delete;
+    ~ParserFactory() = delete;
+    ParserFactory(const ParserFactory&) = delete;
+    ParserFactory& operator=(const ParserFactory&) = delete;
+    ParserFactory(ParserFactory&&) = delete;
+    ParserFactory& operator=(ParserFactory&&) = delete;
+
+    /**
+     * @brief An API to get object of concrete parser class.
+     *
+     * The method is used to get object of respective parser class based on the
+     * type of VPD extracted from VPD vector passed to the API.
+     * To detect respective parser from VPD vector, add logic into the API
+     * vpdTypeCheck.
+     *
+     * Note: API throws DataException in case vpd type check fails for any
+     * unknown type. Caller responsibility to handle the exception.
+     *
+     * @param[in] i_vpdVector - vpd file content to check for the type.
+     * @param[in] i_vpdFilePath - FRU EEPROM path.
+     * @param[in] i_vpdStartOffset - Offset from where VPD starts in the VPD
+     * file.
+     *
+     * @return - Pointer to concrete parser class object.
+     */
+    static std::shared_ptr<ParserInterface>
+        getParser(const types::BinaryVector& i_vpdVector,
+                  const std::string& i_vpdFilePath, size_t i_vpdStartOffset);
+};
+} // namespace vpd
diff --git a/vpd-manager/include/parser_interface.hpp b/vpd-manager/include/parser_interface.hpp
new file mode 100644
index 0000000..0ff2862
--- /dev/null
+++ b/vpd-manager/include/parser_interface.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <variant>
+
+namespace vpd
+{
+/**
+ * @brief Interface class for parsers.
+ *
+ * Any concrete parser class, implementing parsing logic need to derive from
+ * this interface class and override the parse method declared in this class.
+ */
+class ParserInterface
+{
+  public:
+    /**
+     * @brief Pure virtual function for parsing VPD file.
+     *
+     * The API needs to be overridden by all the classes deriving from parser
+     * inerface class to implement respective VPD parsing logic.
+     *
+     * @return parsed format for VPD data, depending upon the
+     * parsing logic.
+     */
+    virtual types::VPDMapVariant parse() = 0;
+
+    /**
+     * @brief Read keyword's value from hardware
+     *
+     * @param[in] types::ReadVpdParams - Parameters required to perform read.
+     *
+     * @return keyword's value on successful read. Exception on failure.
+     */
+    virtual types::DbusVariantType
+        readKeywordFromHardware(const types::ReadVpdParams)
+    {
+        return types::DbusVariantType();
+    }
+
+    /**
+     * @brief API to write keyword's value on hardware.
+     *
+     * This virtual method is created to achieve runtime polymorphism for
+     * hardware writes on VPD of different types. This virtual method can be
+     * redefined at derived classess to implement write according to the type of
+     * VPD.
+     *
+     * @param[in] i_paramsToWriteData - Data required to perform write.
+     *
+     * @throw May throw exception depending on the implementation of derived
+     * methods.
+     * @return On success returns number of bytes written on hardware, On
+     * failure returns -1.
+     */
+    virtual int
+        writeKeywordOnHardware(const types::WriteVpdParams i_paramsToWriteData)
+    {
+        (void)i_paramsToWriteData;
+        return -1;
+    }
+
+    /**
+     * @brief Virtual destructor.
+     */
+    virtual ~ParserInterface() {}
+};
+} // namespace vpd
diff --git a/vpd-manager/include/types.hpp b/vpd-manager/include/types.hpp
new file mode 100644
index 0000000..314aebd
--- /dev/null
+++ b/vpd-manager/include/types.hpp
@@ -0,0 +1,192 @@
+#pragma once
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <sdbusplus/asio/property.hpp>
+#include <sdbusplus/server.hpp>
+#include <xyz/openbmc_project/Common/Device/error.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+#include <tuple>
+#include <unordered_map>
+#include <variant>
+
+namespace vpd
+{
+namespace types
+{
+
+using BiosProperty = std::tuple<
+    std::string, bool, std::string, std::string, std::string,
+    std::variant<int64_t, std::string>, std::variant<int64_t, std::string>,
+    std::vector<std::tuple<std::string, std::variant<int64_t, std::string>,
+                           std::string>>>;
+using BiosBaseTable =
+    std::variant<std::monostate, std::map<std::string, BiosProperty>>;
+using BiosBaseTableType = std::map<std::string, BiosBaseTable>;
+using BiosAttributeCurrentValue =
+    std::variant<std::monostate, int64_t, std::string>;
+using BiosAttributePendingValue = std::variant<int64_t, std::string>;
+using BiosGetAttrRetType = std::tuple<std::string, BiosAttributeCurrentValue,
+                                      BiosAttributePendingValue>;
+using PendingBIOSAttrItem =
+    std::pair<std::string, std::tuple<std::string, BiosAttributePendingValue>>;
+using PendingBIOSAttrs = std::vector<PendingBIOSAttrItem>;
+
+using BinaryVector = std::vector<uint8_t>;
+
+// This covers mostly all the data type supported over Dbus for a property.
+// clang-format off
+using DbusVariantType = std::variant<
+    std::vector<std::tuple<std::string, std::string, std::string>>,
+    std::vector<std::string>,
+    std::vector<double>,
+    std::string,
+    int64_t,
+    uint64_t,
+    double,
+    int32_t,
+    uint32_t,
+    int16_t,
+    uint16_t,
+    uint8_t,
+    bool,
+    BinaryVector,
+    std::vector<uint32_t>,
+    std::vector<uint16_t>,
+    sdbusplus::message::object_path,
+    std::tuple<uint64_t, std::vector<std::tuple<std::string, std::string, double, uint64_t>>>,
+    std::vector<std::tuple<std::string, std::string>>,
+    std::vector<std::tuple<uint32_t, std::vector<uint32_t>>>,
+    std::vector<std::tuple<uint32_t, size_t>>,
+    std::vector<std::tuple<sdbusplus::message::object_path, std::string,
+                           std::string, std::string>>,
+    PendingBIOSAttrs
+ >;
+
+using MapperGetObject =
+    std::vector<std::pair<std::string, std::vector<std::string>>>;
+using MapperGetSubTree = std::map<std::string, std::map<std::string, std::vector<std::string>>>;
+
+/* A type for holding the innermost map of property::value.*/
+using IPZKwdValueMap = std::unordered_map<std::string, std::string>;
+/*IPZ VPD Map of format <Record name, <keyword, value>>*/
+using IPZVpdMap = std::unordered_map<std::string, IPZKwdValueMap>;
+
+/*Value types supported by Keyword VPD*/
+using KWdVPDValueType = std::variant<BinaryVector,std::string, size_t>;
+/* This hold map of parsed data of keyword VPD type*/
+using KeywordVpdMap = std::unordered_map<std::string, KWdVPDValueType>;
+
+/**
+ * Both Keyword VPD parser and DDIMM parser stores the
+ * parsed VPD in the same format.
+ * To have better readability, two types are defined for underneath data structure.
+*/
+using DdimmVpdMap = KeywordVpdMap;
+
+/**
+ * Both Keyword VPD parser and ISDIMM parser stores the
+ * parsed SPD in the same format.
+*/
+using JedecSpdMap = KeywordVpdMap;
+
+/**
+ * Type to hold keyword::value map of a VPD.
+ * Variant can be extended to support additional type.
+*/
+using VPDKWdValueMap = std::variant<IPZKwdValueMap, KeywordVpdMap>;
+
+/* Map<Property, Value>*/
+using PropertyMap = std::map<std::string, DbusVariantType>;
+/* Map<Interface<Property, Value>>*/
+using InterfaceMap = std::map<std::string, PropertyMap>;
+using ObjectMap = std::map<sdbusplus::message::object_path, InterfaceMap>;
+
+using KwSize = uint8_t;
+using RecordId = uint8_t;
+using RecordSize = uint16_t;
+using RecordType = uint16_t;
+using RecordOffset = uint16_t;
+using RecordLength = uint16_t;
+using ECCOffset = uint16_t;
+using ECCLength = uint16_t;
+using PoundKwSize = uint16_t;
+
+using RecordOffsetList = std::vector<uint32_t>;
+
+using VPDMapVariant = std::variant<std::monostate, IPZVpdMap, KeywordVpdMap>;
+
+using HWVerList = std::vector<std::pair<std::string, std::string>>;
+/**
+ * Map of <systemIM, pair<Default version, vector<HW version, JSON suffix>>>
+*/
+using SystemTypeMap =
+    std::unordered_map<std::string, std::pair<std::string, HWVerList>>;
+
+using Path = std::string;
+using Record = std::string;
+using Keyword = std::string;
+
+using IpzData = std::tuple<Record, Keyword, BinaryVector>;
+using KwData = std::tuple<Keyword, BinaryVector>;
+using VpdData = std::variant<IpzData, KwData>;
+
+using IpzType = std::tuple<Record, Keyword>;
+using ReadVpdParams = std::variant<IpzType, Keyword>;
+using WriteVpdParams = std::variant<IpzData, KwData>;
+
+using ListOfPaths = std::vector<sdbusplus::message::object_path>;
+using RecordData = std::tuple<RecordOffset, RecordLength, ECCOffset, ECCLength>;
+
+using DbusInvalidArgument =
+    sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
+using DbusNotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
+
+using InvalidArgument = phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
+
+namespace DeviceError = sdbusplus::xyz::openbmc_project::Common::Device::Error;
+
+/* PEL Severity enum as defined in [xyz.openbmc_project.Logging.Entry.Level]log.hpp from 'phosphor-logging' repo. */
+enum SeverityType
+{
+    Notice,
+    Informational,
+    Debug,
+    Warning,
+    Critical,
+    Emergency,
+    Alert,
+    Error
+};
+
+/* PEL callout priority from 'phosphor-logging' pel_types.hpp. If any change in 'phosphor-logging', it needs update here as well. */
+enum CalloutPriority
+{
+    High,
+    Medium,
+    MediumGroupA,
+    MediumGroupB,
+    MediumGroupC,
+    Low
+};
+
+/* The Message property of the event entry for creating PEL, to introduce new message needs to be added in 'phosphor-logging' message_registry.json as well. */
+enum ErrorType
+{
+    DefaultValue,
+    InvalidVpdMessage,
+    VpdMismatch,
+    InvalidEeprom,
+    EccCheckFailed,
+    JsonFailure,
+    DbusFailure,
+    InvalidSystem,
+    EssentialFru,
+    GpioError
+};
+
+using InventoryCalloutData = std::tuple<std::string, CalloutPriority>;
+using DeviceCalloutData = std::tuple<std::string, std::string>;
+using I2cBusCalloutData = std::tuple<std::string, std::string, std::string>;
+} // namespace types
+} // namespace vpd
diff --git a/vpd-manager/include/utility/common_utility.hpp b/vpd-manager/include/utility/common_utility.hpp
new file mode 100644
index 0000000..15b33a2
--- /dev/null
+++ b/vpd-manager/include/utility/common_utility.hpp
@@ -0,0 +1,117 @@
+#pragma once
+
+#include "constants.hpp"
+#include "logger.hpp"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <vector>
+
+/**
+ * @brief Namespace to host common utility methods.
+ *
+ * A method qualifies as a common utility function if,
+ * A)It is being used by the utility namespace at the same level as well as
+ * other files directly.
+ * B) The utility should be a leaf node and should not be dependent on any other
+ * utility.
+ *                  *******************
+ *                  | Commmon Utility | - - - - - - -
+ *                  *******************              |
+ *                          /\                       |
+ *                         /  \                      |
+ *         ****************    ****************      |
+ *         | json utility |    | dbus utility |      |
+ *         ****************    ****************      |
+ *                 \                 /               |
+ *                  \               /                |
+ *               ************************            |
+ *               | Vpd specific Utility | - - - - - - -
+ *               ************************
+ */
+
+namespace vpd
+{
+
+namespace commonUtility
+{
+/** @brief Return the hex representation of the incoming byte.
+ *
+ * @param [in] i_aByte - The input byte.
+ * @returns Hex representation of the byte as a character.
+ */
+constexpr auto toHex(size_t i_aByte)
+{
+    constexpr auto l_map = "0123456789abcdef";
+    return l_map[i_aByte];
+}
+
+/**
+ * @brief API to return null at the end of variadic template args.
+ *
+ * @return empty string.
+ */
+inline std::string getCommand()
+{
+    return "";
+}
+
+/**
+ * @brief API to arrange create command.
+ *
+ * @param[in] arguments to create the command
+ * @return Command string
+ */
+template <typename T, typename... Types>
+inline std::string getCommand(T i_arg1, Types... i_args)
+{
+    std::string l_cmd = " " + i_arg1 + getCommand(i_args...);
+
+    return l_cmd;
+}
+
+/**
+ * @brief API to create shell command and execute.
+ *
+ * @throw std::runtime_error.
+ *
+ * @param[in] arguments for command
+ * @returns output of that command
+ */
+template <typename T, typename... Types>
+inline std::vector<std::string> executeCmd(T&& i_path, Types... i_args)
+{
+    std::vector<std::string> l_cmdOutput;
+    std::array<char, constants::CMD_BUFFER_LENGTH> l_buffer;
+
+    std::string l_cmd = i_path + getCommand(i_args...);
+
+    std::unique_ptr<FILE, decltype(&pclose)> l_cmdPipe(
+        popen(l_cmd.c_str(), "r"), pclose);
+
+    if (!l_cmdPipe)
+    {
+        logging::logMessage(
+            "popen failed with error " + std::string(strerror(errno)));
+        throw std::runtime_error("popen failed!");
+    }
+    while (fgets(l_buffer.data(), l_buffer.size(), l_cmdPipe.get()) != nullptr)
+    {
+        l_cmdOutput.emplace_back(l_buffer.data());
+    }
+
+    return l_cmdOutput;
+}
+
+/** @brief Converts string to lower case.
+ *
+ * @param [in] i_string - Input string.
+ */
+inline void toLower(std::string& i_string)
+{
+    std::transform(i_string.begin(), i_string.end(), i_string.begin(),
+                   [](unsigned char l_char) { return std::tolower(l_char); });
+}
+} // namespace commonUtility
+} // namespace vpd
diff --git a/vpd-manager/include/utility/dbus_utility.hpp b/vpd-manager/include/utility/dbus_utility.hpp
new file mode 100644
index 0000000..4c81815
--- /dev/null
+++ b/vpd-manager/include/utility/dbus_utility.hpp
@@ -0,0 +1,567 @@
+#pragma once
+
+#include "constants.hpp"
+#include "logger.hpp"
+#include "types.hpp"
+
+#include <chrono>
+
+namespace vpd
+{
+/**
+ * @brief The namespace defines utlity methods for generic D-Bus operations.
+ */
+namespace dbusUtility
+{
+
+/**
+ * @brief An API to get Map of service and interfaces for an object path.
+ *
+ * The API returns a Map of service name and interfaces for a given pair of
+ * object path and interface list. It can be used to determine service name
+ * which implemets a particular object path and interface.
+ *
+ * Note: It will be caller's responsibility to check for empty map returned and
+ * generate appropriate error.
+ *
+ * @param [in] objectPath - Object path under the service.
+ * @param [in] interfaces - Array of interface(s).
+ * @return - A Map of service name to object to interface(s), if success.
+ *           If failed,  empty map.
+ */
+inline types::MapperGetObject getObjectMap(const std::string& objectPath,
+                                           std::span<const char*> interfaces)
+{
+    types::MapperGetObject getObjectMap;
+
+    // interface list is optional argument, hence no check required.
+    if (objectPath.empty())
+    {
+        logging::logMessage("Path value is empty, invalid call to GetObject");
+        return getObjectMap;
+    }
+
+    try
+    {
+        auto bus = sdbusplus::bus::new_default();
+        auto method = bus.new_method_call(
+            "xyz.openbmc_project.ObjectMapper",
+            "/xyz/openbmc_project/object_mapper",
+            "xyz.openbmc_project.ObjectMapper", "GetObject");
+
+        method.append(objectPath, interfaces);
+        auto result = bus.call(method);
+        result.read(getObjectMap);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        // logging::logMessage(e.what());
+        return getObjectMap;
+    }
+
+    return getObjectMap;
+}
+
+/**
+ * @brief An API to get property map for an interface.
+ *
+ * This API returns a map of property and its value with respect to a particular
+ * interface.
+ *
+ * Note: It will be caller's responsibility to check for empty map returned and
+ * generate appropriate error.
+ *
+ * @param[in] i_service - Service name.
+ * @param[in] i_objectPath - object path.
+ * @param[in] i_interface - Interface, for the properties to be listed.
+ *
+ * @return - A map of property and value of an interface, if success.
+ *           if failed, empty map.
+ */
+inline types::PropertyMap getPropertyMap(const std::string& i_service,
+                                         const std::string& i_objectPath,
+                                         const std::string& i_interface)
+{
+    types::PropertyMap l_propertyValueMap;
+    if (i_service.empty() || i_objectPath.empty() || i_interface.empty())
+    {
+        logging::logMessage("Invalid parameters to get property map");
+        return l_propertyValueMap;
+    }
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method =
+            l_bus.new_method_call(i_service.c_str(), i_objectPath.c_str(),
+                                  "org.freedesktop.DBus.Properties", "GetAll");
+        l_method.append(i_interface);
+        auto l_result = l_bus.call(l_method);
+        l_result.read(l_propertyValueMap);
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        logging::logMessage(l_ex.what());
+    }
+
+    return l_propertyValueMap;
+}
+
+/**
+ * @brief API to get object subtree from D-bus.
+ *
+ * The API returns the map of object, services and interfaces in the
+ * subtree that implement a certain interface. If no interfaces are provided
+ * then all the objects, services and interfaces under the subtree will
+ * be returned.
+ *
+ * Note: Depth can be 0 and interfaces can be null.
+ * It will be caller's responsibility to check for empty vector returned
+ * and generate appropriate error.
+ *
+ * @param[in] i_objectPath - Path to search for an interface.
+ * @param[in] i_depth - Maximum depth of the tree to search.
+ * @param[in] i_interfaces - List of interfaces to search.
+ *
+ * @return - A map of object and its related services and interfaces, if
+ *           success. If failed, empty map.
+ */
+
+inline types::MapperGetSubTree
+    getObjectSubTree(const std::string& i_objectPath, const int& i_depth,
+                     const std::vector<std::string>& i_interfaces)
+{
+    types::MapperGetSubTree l_subTreeMap;
+
+    if (i_objectPath.empty())
+    {
+        logging::logMessage("Object path is empty.");
+        return l_subTreeMap;
+    }
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method = l_bus.new_method_call(
+            constants::objectMapperService, constants::objectMapperPath,
+            constants::objectMapperInf, "GetSubTree");
+        l_method.append(i_objectPath, i_depth, i_interfaces);
+        auto l_result = l_bus.call(l_method);
+        l_result.read(l_subTreeMap);
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        logging::logMessage(l_ex.what());
+    }
+
+    return l_subTreeMap;
+}
+
+/**
+ * @brief An API to read property from Dbus.
+ *
+ * The caller of the API needs to validate the validatity and correctness of the
+ * type and value of data returned. The API will just fetch and retun the data
+ * without any data validation.
+ *
+ * Note: It will be caller's responsibility to check for empty value returned
+ * and generate appropriate error if required.
+ *
+ * @param [in] serviceName - Name of the Dbus service.
+ * @param [in] objectPath - Object path under the service.
+ * @param [in] interface - Interface under which property exist.
+ * @param [in] property - Property whose value is to be read.
+ * @return - Value read from Dbus, if success.
+ *           If failed, empty variant.
+ */
+inline types::DbusVariantType readDbusProperty(
+    const std::string& serviceName, const std::string& objectPath,
+    const std::string& interface, const std::string& property)
+{
+    types::DbusVariantType propertyValue;
+
+    // Mandatory fields to make a read dbus call.
+    if (serviceName.empty() || objectPath.empty() || interface.empty() ||
+        property.empty())
+    {
+        logging::logMessage(
+            "One of the parameter to make Dbus read call is empty.");
+        return propertyValue;
+    }
+
+    try
+    {
+        auto bus = sdbusplus::bus::new_default();
+        auto method =
+            bus.new_method_call(serviceName.c_str(), objectPath.c_str(),
+                                "org.freedesktop.DBus.Properties", "Get");
+        method.append(interface, property);
+
+        auto result = bus.call(method);
+        result.read(propertyValue);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        return propertyValue;
+    }
+    return propertyValue;
+}
+
+/**
+ * @brief An API to write property on Dbus.
+ *
+ * The caller of this API needs to handle exception thrown by this method to
+ * identify any write failure. The API in no other way indicate write  failure
+ * to the caller.
+ *
+ * Note: It will be caller's responsibility ho handle the exception thrown in
+ * case of write failure and generate appropriate error.
+ *
+ * @param [in] serviceName - Name of the Dbus service.
+ * @param [in] objectPath - Object path under the service.
+ * @param [in] interface - Interface under which property exist.
+ * @param [in] property - Property whose value is to be written.
+ * @param [in] propertyValue - The value to be written.
+ */
+inline void writeDbusProperty(
+    const std::string& serviceName, const std::string& objectPath,
+    const std::string& interface, const std::string& property,
+    const types::DbusVariantType& propertyValue)
+{
+    // Mandatory fields to make a write dbus call.
+    if (serviceName.empty() || objectPath.empty() || interface.empty() ||
+        property.empty())
+    {
+        logging::logMessage(
+            "One of the parameter to make Dbus read call is empty.");
+
+        // caller need to handle the throw to ensure Dbus write success.
+        throw std::runtime_error("Dbus write failed, Parameter empty");
+    }
+
+    try
+    {
+        auto bus = sdbusplus::bus::new_default();
+        auto method =
+            bus.new_method_call(serviceName.c_str(), objectPath.c_str(),
+                                "org.freedesktop.DBus.Properties", "Set");
+        method.append(interface, property, propertyValue);
+        bus.call(method);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        logging::logMessage(e.what());
+
+        // caller needs to handle this throw to handle error in writing Dbus.
+        throw std::runtime_error("Dbus write failed");
+    }
+}
+
+/**
+ * @brief API to publish data on PIM
+ *
+ * The API calls notify on PIM object to publlish VPD.
+ *
+ * @param[in] objectMap - Object, its interface and data.
+ * @return bool - Status of call to PIM notify.
+ */
+inline bool callPIM(types::ObjectMap&& objectMap)
+{
+    try
+    {
+        for (const auto& l_objectKeyValue : objectMap)
+        {
+            auto l_nodeHandle = objectMap.extract(l_objectKeyValue.first);
+
+            if (l_nodeHandle.key().str.find(constants::pimPath, 0) !=
+                std::string::npos)
+            {
+                l_nodeHandle.key() = l_nodeHandle.key().str.replace(
+                    0, std::strlen(constants::pimPath), "");
+                objectMap.insert(std::move(l_nodeHandle));
+            }
+        }
+
+        auto bus = sdbusplus::bus::new_default();
+        auto pimMsg =
+            bus.new_method_call(constants::pimServiceName, constants::pimPath,
+                                constants::pimIntf, "Notify");
+        pimMsg.append(std::move(objectMap));
+        bus.call(pimMsg);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        return false;
+    }
+    return true;
+}
+
+/**
+ * @brief API to check if a D-Bus service is running or not.
+ *
+ * Any failure in calling the method "NameHasOwner" implies that the service is
+ * not in a running state. Hence the API returns false in case of any exception
+ * as well.
+ *
+ * @param[in] i_serviceName - D-Bus service name whose status is to be checked.
+ * @return bool - True if the service is running, false otherwise.
+ */
+inline bool isServiceRunning(const std::string& i_serviceName)
+{
+    bool l_retVal = false;
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method = l_bus.new_method_call(
+            "org.freedesktop.DBus", "/org/freedesktop/DBus",
+            "org.freedesktop.DBus", "NameHasOwner");
+        l_method.append(i_serviceName);
+
+        l_bus.call(l_method).read(l_retVal);
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        logging::logMessage(
+            "Call to check service status failed with exception: " +
+            std::string(l_ex.what()));
+    }
+
+    return l_retVal;
+}
+
+/**
+ * @brief API to call "GetAttribute" method uner BIOS manager.
+ *
+ * The API reads the given attribuute from BIOS and returns a tuple of both
+ * current as well as pending value for that attribute.
+ * The API return only the current attribute value if found.
+ * API returns an empty variant of type BiosAttributeCurrentValue in case of any
+ * error.
+ *
+ * @param[in] i_attributeName - Attribute to be read.
+ * @return Tuple of PLDM attribute Type, current attribute value and pending
+ * attribute value.
+ */
+inline types::BiosAttributeCurrentValue
+    biosGetAttributeMethodCall(const std::string& i_attributeName)
+{
+    auto l_bus = sdbusplus::bus::new_default();
+    auto l_method = l_bus.new_method_call(
+        constants::biosConfigMgrService, constants::biosConfigMgrObjPath,
+        constants::biosConfigMgrInterface, "GetAttribute");
+    l_method.append(i_attributeName);
+
+    types::BiosGetAttrRetType l_attributeVal;
+    try
+    {
+        auto l_result = l_bus.call(l_method);
+        l_result.read(std::get<0>(l_attributeVal), std::get<1>(l_attributeVal),
+                      std::get<2>(l_attributeVal));
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        logging::logMessage(
+            "Failed to read BIOS Attribute: " + i_attributeName +
+            " due to error " + std::string(l_ex.what()));
+
+        // TODO: Log an informational PEL here.
+    }
+
+    return std::get<1>(l_attributeVal);
+}
+
+/**
+ * @brief API to check if Chassis is powered on.
+ *
+ * This API queries Phosphor Chassis State Manager to know whether
+ * Chassis is powered on.
+ *
+ * @return true if chassis is powered on, false otherwise
+ */
+inline bool isChassisPowerOn()
+{
+    auto powerState = dbusUtility::readDbusProperty(
+        "xyz.openbmc_project.State.Chassis",
+        "/xyz/openbmc_project/state/chassis0",
+        "xyz.openbmc_project.State.Chassis", "CurrentPowerState");
+
+    if (auto curPowerState = std::get_if<std::string>(&powerState))
+    {
+        if ("xyz.openbmc_project.State.Chassis.PowerState.On" == *curPowerState)
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /*
+        TODO: Add PEL.
+        Callout: Firmware callout
+        Type: Informational
+        Description: Chassis state can't be determined, defaulting to chassis
+        off. : e.what()
+    */
+    return false;
+}
+
+/**
+ * @brief API to check if host is in running state.
+ *
+ * This API reads the current host state from D-bus and returns true if the host
+ * is running.
+ *
+ * @return true if host is in running state. false otherwise.
+ */
+inline bool isHostRunning()
+{
+    const auto l_hostState = dbusUtility::readDbusProperty(
+        constants::hostService, constants::hostObjectPath,
+        constants::hostInterface, "CurrentHostState");
+
+    if (const auto l_currHostState = std::get_if<std::string>(&l_hostState))
+    {
+        if (*l_currHostState == constants::hostRunningState)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * @brief API to check if BMC is in ready state.
+ *
+ * This API reads the current state of BMC from D-bus and returns true if BMC is
+ * in ready state.
+ *
+ * @return true if BMC is ready, false otherwise.
+ */
+inline bool isBMCReady()
+{
+    const auto l_bmcState = dbusUtility::readDbusProperty(
+        constants::bmcStateService, constants::bmcZeroStateObject,
+        constants::bmcStateInterface, constants::currentBMCStateProperty);
+
+    if (const auto l_currBMCState = std::get_if<std::string>(&l_bmcState))
+    {
+        if (*l_currBMCState == constants::bmcReadyState)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * @brief An API to enable BMC reboot guard
+ *
+ * This API does a D-Bus method call to enable BMC reboot guard.
+ *
+ * @return On success, returns 0, otherwise returns -1.
+ */
+inline int EnableRebootGuard() noexcept
+{
+    int l_rc{constants::FAILURE};
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method = l_bus.new_method_call(
+            constants::systemdService, constants::systemdObjectPath,
+            constants::systemdManagerInterface, "StartUnit");
+        l_method.append("reboot-guard-enable.service", "replace");
+        l_bus.call_noreply(l_method);
+        l_rc = constants::SUCCESS;
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        std::string l_errMsg =
+            "D-Bus call to enable BMC reboot guard failed for reason: ";
+        l_errMsg += l_ex.what();
+
+        logging::logMessage(l_errMsg);
+    }
+    return l_rc;
+}
+
+/**
+ * @brief An API to disable BMC reboot guard
+ *
+ * This API disables BMC reboot guard. This API has an inbuilt re-try mechanism.
+ * If Disable Reboot Guard fails, this API attempts to Disable Reboot Guard for
+ * 3 more times at an interval of 333ms.
+ *
+ * @return On success, returns 0, otherwise returns -1.
+ */
+inline int DisableRebootGuard() noexcept
+{
+    int l_rc{constants::FAILURE};
+
+    // A lambda which executes the DBus call to disable BMC reboot guard.
+    auto l_executeDisableRebootGuard = []() -> int {
+        int l_dBusCallRc{constants::FAILURE};
+        try
+        {
+            auto l_bus = sdbusplus::bus::new_default();
+            auto l_method = l_bus.new_method_call(
+                constants::systemdService, constants::systemdObjectPath,
+                constants::systemdManagerInterface, "StartUnit");
+            l_method.append("reboot-guard-disable.service", "replace");
+            l_bus.call_noreply(l_method);
+            l_dBusCallRc = constants::SUCCESS;
+        }
+        catch (const sdbusplus::exception::SdBusError& l_ex)
+        {}
+        return l_dBusCallRc;
+    };
+
+    if (constants::FAILURE == l_executeDisableRebootGuard())
+    {
+        std::function<void()> l_retryDisableRebootGuard;
+
+        // A lambda which tries to disable BMC reboot guard for 3 times at an
+        // interval of 333 ms.
+        l_retryDisableRebootGuard = [&]() {
+            constexpr int MAX_RETRIES{3};
+            static int l_numRetries{0};
+
+            if (l_numRetries < MAX_RETRIES)
+            {
+                l_numRetries++;
+                if (constants::FAILURE == l_executeDisableRebootGuard())
+                {
+                    // sleep for 333ms before next retry. This is just a random
+                    // value so that 3 re-tries * 333ms takes ~1 second in the
+                    // worst case.
+                    const std::chrono::milliseconds l_sleepTime{333};
+                    std::this_thread::sleep_for(l_sleepTime);
+                    l_retryDisableRebootGuard();
+                }
+                else
+                {
+                    l_numRetries = 0;
+                    l_rc = constants::SUCCESS;
+                }
+            }
+            else
+            {
+                // Failed to Disable Reboot Guard even after 3 retries.
+                logging::logMessage("Failed to Disable Reboot Guard after " +
+                                    std::to_string(MAX_RETRIES) + " re-tries");
+                l_numRetries = 0;
+            }
+        };
+
+        l_retryDisableRebootGuard();
+    }
+    else
+    {
+        l_rc = constants::SUCCESS;
+    }
+    return l_rc;
+}
+
+} // namespace dbusUtility
+} // namespace vpd
diff --git a/vpd-manager/include/utility/json_utility.hpp b/vpd-manager/include/utility/json_utility.hpp
new file mode 100644
index 0000000..3dab105
--- /dev/null
+++ b/vpd-manager/include/utility/json_utility.hpp
@@ -0,0 +1,1043 @@
+#pragma once
+
+#include "event_logger.hpp"
+#include "exceptions.hpp"
+#include "logger.hpp"
+#include "types.hpp"
+
+#include <gpiod.hpp>
+#include <nlohmann/json.hpp>
+#include <utility/common_utility.hpp>
+
+#include <fstream>
+#include <type_traits>
+#include <unordered_map>
+
+namespace vpd
+{
+namespace jsonUtility
+{
+
+// forward declaration of API for function map.
+bool processSystemCmdTag(const nlohmann::json& i_parsedConfigJson,
+                         const std::string& i_vpdFilePath,
+                         const std::string& i_baseAction,
+                         const std::string& i_flagToProcess);
+
+// forward declaration of API for function map.
+bool processGpioPresenceTag(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess);
+
+// forward declaration of API for function map.
+bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
+                      const std::string& i_vpdFilePath,
+                      const std::string& i_baseAction,
+                      const std::string& i_flagToProcess);
+
+// Function pointers to process tags from config JSON.
+typedef bool (*functionPtr)(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess);
+
+inline std::unordered_map<std::string, functionPtr> funcionMap{
+    {"gpioPresence", processGpioPresenceTag},
+    {"setGpio", procesSetGpioTag},
+    {"systemCmd", processSystemCmdTag}};
+
+/**
+ * @brief API to read VPD offset from JSON file.
+ *
+ * @param[in] i_sysCfgJsonObj - Parsed system config JSON object.
+ * @param[in] i_vpdFilePath - VPD file path.
+ * @return VPD offset if found in JSON, 0 otherwise.
+ */
+inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj,
+                           const std::string& i_vpdFilePath)
+{
+    if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) ||
+        (!i_sysCfgJsonObj.contains("frus")))
+    {
+        return 0;
+    }
+
+    if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath))
+    {
+        return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0);
+    }
+
+    const nlohmann::json& l_fruList =
+        i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+    for (const auto& l_fru : l_fruList.items())
+    {
+        const auto l_fruPath = l_fru.key();
+
+        // check if given path is redundant FRU path
+        if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
+                                 "redundantEeprom", ""))
+        {
+            // Return the offset of redundant EEPROM taken from JSON.
+            return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0);
+        }
+    }
+
+    return 0;
+}
+
+/**
+ * @brief API to parse respective JSON.
+ *
+ * Exception is thrown in case of JSON parse error.
+ *
+ * @param[in] pathToJson - Path to JSON.
+ * @return Parsed JSON.
+ */
+inline nlohmann::json getParsedJson(const std::string& pathToJson)
+{
+    if (pathToJson.empty())
+    {
+        throw std::runtime_error("Path to JSON is missing");
+    }
+
+    if (!std::filesystem::exists(pathToJson) ||
+        std::filesystem::is_empty(pathToJson))
+    {
+        throw std::runtime_error("Incorrect File Path or empty file");
+    }
+
+    std::ifstream jsonFile(pathToJson);
+    if (!jsonFile)
+    {
+        throw std::runtime_error("Failed to access Json path = " + pathToJson);
+    }
+
+    try
+    {
+        return nlohmann::json::parse(jsonFile);
+    }
+    catch (const nlohmann::json::parse_error& e)
+    {
+        throw std::runtime_error("Failed to parse JSON file");
+    }
+}
+
+/**
+ * @brief Get inventory object path from system config JSON.
+ *
+ * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
+ * this API returns D-bus inventory path if present in JSON.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object
+ * @param[in] i_vpdPath - Path to where VPD is stored.
+ *
+ * @throw std::runtime_error.
+ *
+ * @return On success a valid path is returned, on failure an empty string is
+ * returned or an exception is thrown.
+ */
+inline std::string getInventoryObjPathFromJson(
+    const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath)
+{
+    if (i_vpdPath.empty())
+    {
+        throw std::runtime_error("Path parameter is empty.");
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        throw std::runtime_error("Missing frus tag in system config JSON.");
+    }
+
+    // check if given path is FRU path
+    if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
+    {
+        return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
+            "inventoryPath", "");
+    }
+
+    const nlohmann::json& l_fruList =
+        i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+    for (const auto& l_fru : l_fruList.items())
+    {
+        const auto l_fruPath = l_fru.key();
+        const auto l_invObjPath =
+            i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "");
+
+        // check if given path is redundant FRU path or inventory path
+        if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
+                             "redundantEeprom", "") ||
+            (i_vpdPath == l_invObjPath))
+        {
+            return l_invObjPath;
+        }
+    }
+    return std::string();
+}
+
+/**
+ * @brief Process "PostFailAction" defined in config JSON.
+ *
+ * In case there is some error in the processing of "preAction" execution and a
+ * set of procedure needs to be done as a part of post fail action. This base
+ * action can be defined in the config JSON for that FRU and it will be handled
+ * under this API.
+ *
+ * @param[in] i_parsedConfigJson - config JSON
+ * @param[in] i_vpdFilePath - EEPROM file path
+ * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
+ * under PostFailAction tag of config JSON.
+ * @return - success or failure
+ */
+inline bool executePostFailAction(const nlohmann::json& i_parsedConfigJson,
+                                  const std::string& i_vpdFilePath,
+                                  const std::string& i_flagToProcess)
+{
+    if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
+        i_flagToProcess.empty())
+    {
+        logging::logMessage(
+            "Invalid parameters. Abort processing for post fail action");
+
+        return false;
+    }
+
+    if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["PostFailAction"]
+             .contains(i_flagToProcess))
+    {
+        logging::logMessage(
+            "Config JSON missing flag " + i_flagToProcess +
+            " to execute post fail action for path = " + i_vpdFilePath);
+
+        return false;
+    }
+
+    for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
+             0))["PostFailAction"][i_flagToProcess]
+                                  .items())
+    {
+        auto itrToFunction = funcionMap.find(l_tags.key());
+        if (itrToFunction != funcionMap.end())
+        {
+            if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
+                                       "PostFailAction", i_flagToProcess))
+            {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+/**
+ * @brief Process "systemCmd" tag for a given FRU.
+ *
+ * The API will process "systemCmd" tag if it is defined in the config
+ * JSON for the given FRU.
+ *
+ * @param[in] i_parsedConfigJson - config JSON
+ * @param[in] i_vpdFilePath - EEPROM file path
+ * @param[in] i_baseAction - Base action for which this tag has been called.
+ * @param[in] i_flagToProcess - Flag nested under the base action for which this
+ * tag has been called.
+ * @return Execution status.
+ */
+inline bool processSystemCmdTag(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess)
+{
+    if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
+        i_baseAction.empty() || i_flagToProcess.empty())
+    {
+        logging::logMessage(
+            "Invalid parameter. Abort processing of processSystemCmd.");
+        return false;
+    }
+
+    if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+               0)[i_baseAction][i_flagToProcess]["systemCmd"])
+              .contains("cmd")))
+    {
+        logging::logMessage(
+            "Config JSON missing required information to execute system command for EEPROM " +
+            i_vpdFilePath);
+
+        return false;
+    }
+
+    try
+    {
+        const std::string& l_systemCommand =
+            i_parsedConfigJson["frus"][i_vpdFilePath].at(
+                0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
+
+        commonUtility::executeCmd(l_systemCommand);
+        return true;
+    }
+    catch (const std::exception& e)
+    {
+        std::string l_errMsg = "Process system tag failed for exception: ";
+        l_errMsg += e.what();
+
+        logging::logMessage(l_errMsg);
+        return false;
+    }
+}
+
+/**
+ * @brief Checks for presence of a given FRU using GPIO line.
+ *
+ * This API returns the presence information of the FRU corresponding to the
+ * given VPD file path by setting the presence pin.
+ *
+ * @param[in] i_parsedConfigJson - config JSON
+ * @param[in] i_vpdFilePath - EEPROM file path
+ * @param[in] i_baseAction - Base action for which this tag has been called.
+ * @param[in] i_flagToProcess - Flag nested under the base action for which this
+ * tag has been called.
+ * @return Execution status.
+ */
+inline bool processGpioPresenceTag(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess)
+{
+    if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
+        i_baseAction.empty() || i_flagToProcess.empty())
+    {
+        logging::logMessage(
+            "Invalid parameter. Abort processing of processGpioPresence tag");
+        return false;
+    }
+
+    if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+                0)[i_baseAction][i_flagToProcess]["gpioPresence"])
+               .contains("pin")) &&
+          ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+                0)[i_baseAction][i_flagToProcess]["gpioPresence"])
+               .contains("value"))))
+    {
+        logging::logMessage(
+            "Config JSON missing required information to detect presence for EEPROM " +
+            i_vpdFilePath);
+
+        return false;
+    }
+
+    // get the pin name
+    const std::string& l_presencePinName =
+        i_parsedConfigJson["frus"][i_vpdFilePath].at(
+            0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
+
+    // get the pin value
+    uint8_t l_presencePinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
+        0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
+
+    try
+    {
+        gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
+
+        if (!l_presenceLine)
+        {
+            throw GpioException("Couldn't find the GPIO line.");
+        }
+
+        l_presenceLine.request({"Read the presence line",
+                                gpiod::line_request::DIRECTION_INPUT, 0});
+
+        return (l_presencePinValue == l_presenceLine.get_value());
+    }
+    catch (const std::exception& ex)
+    {
+        std::string l_errMsg = "Exception on GPIO line: ";
+        l_errMsg += l_presencePinName;
+        l_errMsg += " Reason: ";
+        l_errMsg += ex.what();
+        l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
+
+        // ToDo -- Update Internal Rc code.
+        EventLogger::createAsyncPelWithInventoryCallout(
+            types::ErrorType::GpioError, types::SeverityType::Informational,
+            {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath),
+              types::CalloutPriority::High}},
+            std::source_location::current().file_name(),
+            std::source_location::current().function_name(), 0, l_errMsg,
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+
+        logging::logMessage(l_errMsg);
+
+        // Except when GPIO pin value is false, we go and try collecting the
+        // FRU VPD as we couldn't able to read GPIO pin value due to some
+        // error/exception. So returning true in error scenario.
+        return true;
+    }
+}
+
+/**
+ * @brief Process "setGpio" tag for a given FRU.
+ *
+ * This API enables the GPIO line.
+ *
+ * @param[in] i_parsedConfigJson - config JSON
+ * @param[in] i_vpdFilePath - EEPROM file path
+ * @param[in] i_baseAction - Base action for which this tag has been called.
+ * @param[in] i_flagToProcess - Flag nested under the base action for which this
+ * tag has been called.
+ * @return Execution status.
+ */
+inline bool procesSetGpioTag(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess)
+{
+    if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
+        i_baseAction.empty() || i_flagToProcess.empty())
+    {
+        logging::logMessage(
+            "Invalid parameter. Abort processing of procesSetGpio.");
+        return false;
+    }
+
+    if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+                0)[i_baseAction][i_flagToProcess]["setGpio"])
+               .contains("pin")) &&
+          ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+                0)[i_baseAction][i_flagToProcess]["setGpio"])
+               .contains("value"))))
+    {
+        logging::logMessage(
+            "Config JSON missing required information to set gpio line for EEPROM " +
+            i_vpdFilePath);
+
+        return false;
+    }
+
+    const std::string& l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
+        0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
+
+    // Get the value to set
+    uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
+        0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
+
+    logging::logMessage(
+        "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
+    try
+    {
+        gpiod::line l_outputLine = gpiod::find_line(l_pinName);
+
+        if (!l_outputLine)
+        {
+            throw GpioException("Couldn't find GPIO line.");
+        }
+
+        l_outputLine.request(
+            {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
+            l_pinValue);
+        return true;
+    }
+    catch (const std::exception& ex)
+    {
+        std::string l_errMsg = "Exception on GPIO line: ";
+        l_errMsg += l_pinName;
+        l_errMsg += " Reason: ";
+        l_errMsg += ex.what();
+        l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
+
+        // ToDo -- Update Internal RC code
+        EventLogger::createAsyncPelWithInventoryCallout(
+            types::ErrorType::GpioError, types::SeverityType::Informational,
+            {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath),
+              types::CalloutPriority::High}},
+            std::source_location::current().file_name(),
+            std::source_location::current().function_name(), 0, l_errMsg,
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+
+        logging::logMessage(l_errMsg);
+
+        return false;
+    }
+}
+
+/**
+ * @brief Process any action, if defined in config JSON.
+ *
+ * If any FRU(s) requires any special handling, then this base action can be
+ * defined for that FRU in the config JSON, processing of which will be handled
+ * in this API.
+ * Examples of action - preAction, PostAction etc.
+ *
+ * @param[in] i_parsedConfigJson - config JSON
+ * @param[in] i_action - Base action to be performed.
+ * @param[in] i_vpdFilePath - EEPROM file path
+ * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
+ * under PreAction tag of config JSON.
+ * @return - success or failure
+ */
+inline bool executeBaseAction(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
+    const std::string& i_vpdFilePath, const std::string& i_flagToProcess)
+{
+    if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() ||
+        !i_parsedConfigJson.contains("frus"))
+    {
+        logging::logMessage("Invalid parameter");
+        return false;
+    }
+
+    if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
+    {
+        logging::logMessage(
+            "File path: " + i_vpdFilePath + " not found in JSON");
+        return false;
+    }
+
+    if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
+    {
+        logging::logMessage("Action [" + i_action +
+                            "] not defined for file path:" + i_vpdFilePath);
+        return false;
+    }
+
+    if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains(
+            i_flagToProcess))
+    {
+        logging::logMessage("Config JSON missing flag [" + i_flagToProcess +
+                            "] to execute action for path = " + i_vpdFilePath);
+
+        return false;
+    }
+
+    const nlohmann::json& l_tagsJson =
+        (i_parsedConfigJson["frus"][i_vpdFilePath].at(
+            0))[i_action][i_flagToProcess];
+
+    for (const auto& l_tag : l_tagsJson.items())
+    {
+        auto itrToFunction = funcionMap.find(l_tag.key());
+        if (itrToFunction != funcionMap.end())
+        {
+            if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
+                                       i_action, i_flagToProcess))
+            {
+                // In case any of the tag fails to execute. Mark action
+                // as failed for that flag.
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+/**
+ * @brief Get redundant FRU path from system config JSON
+ *
+ * Given either D-bus inventory path/FRU path/redundant FRU path, this
+ * API returns the redundant FRU path taken from "redundantEeprom" tag from
+ * system config JSON.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] i_vpdPath - Path to where VPD is stored.
+ *
+ * @throw std::runtime_error.
+ * @return On success return valid path, on failure return empty string.
+ */
+inline std::string getRedundantEepromPathFromJson(
+    const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath)
+{
+    if (i_vpdPath.empty())
+    {
+        throw std::runtime_error("Path parameter is empty.");
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        throw std::runtime_error("Missing frus tag in system config JSON.");
+    }
+
+    // check if given path is FRU path
+    if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
+    {
+        return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
+            "redundantEeprom", "");
+    }
+
+    const nlohmann::json& l_fruList =
+        i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+    for (const auto& l_fru : l_fruList.items())
+    {
+        const std::string& l_fruPath = l_fru.key();
+        const std::string& l_redundantFruPath =
+            i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom",
+                                                           "");
+
+        // check if given path is inventory path or redundant FRU path
+        if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath",
+                                                            "") == i_vpdPath) ||
+            (l_redundantFruPath == i_vpdPath))
+        {
+            return l_redundantFruPath;
+        }
+    }
+    return std::string();
+}
+
+/**
+ * @brief Get FRU EEPROM path from system config JSON
+ *
+ * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
+ * this API returns FRU EEPROM path if present in JSON.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object
+ * @param[in] i_vpdPath - Path to where VPD is stored.
+ *
+ * @throw std::runtime_error.
+ *
+ * @return On success return valid path, on failure return empty string.
+ */
+inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
+                                      const std::string& i_vpdPath)
+{
+    if (i_vpdPath.empty())
+    {
+        throw std::runtime_error("Path parameter is empty.");
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        throw std::runtime_error("Missing frus tag in system config JSON.");
+    }
+
+    // check if given path is FRU path
+    if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
+    {
+        return i_vpdPath;
+    }
+
+    const nlohmann::json& l_fruList =
+        i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+    for (const auto& l_fru : l_fruList.items())
+    {
+        const auto l_fruPath = l_fru.key();
+
+        // check if given path is redundant FRU path or inventory path
+        if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
+                             "redundantEeprom", "") ||
+            (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
+                              "inventoryPath", "")))
+        {
+            return l_fruPath;
+        }
+    }
+    return std::string();
+}
+
+/**
+ * @brief An API to check backup and restore VPD is required.
+ *
+ * The API checks if there is provision for backup and restore mentioned in the
+ * system config JSON, by looking "backupRestoreConfigPath" tag.
+ * Checks if the path mentioned is a hardware path, by checking if the file path
+ * exists and size of contents in the path.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ *
+ * @return true if backup and restore is required, false otherwise.
+ */
+inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj)
+{
+    try
+    {
+        const std::string& l_backupAndRestoreCfgFilePath =
+            i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
+        if (!l_backupAndRestoreCfgFilePath.empty() &&
+            std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
+            !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
+        {
+            return true;
+        }
+    }
+    catch (std::exception& ex)
+    {
+        logging::logMessage(ex.what());
+    }
+    return false;
+}
+
+/** @brief API to check if an action is required for given EEPROM path.
+ *
+ * System config JSON can contain pre-action, post-action etc. like actions
+ * defined for an EEPROM path. The API will check if any such action is defined
+ * for the EEPROM.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] i_vpdFruPath - EEPROM path.
+ * @param[in] i_action - Action to be checked.
+ * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
+ * triggered.
+ * @return - True if action is defined for the flow, false otherwise.
+ */
+inline bool isActionRequired(
+    const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath,
+    const std::string& i_action, const std::string& i_flowFlag)
+{
+    if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
+    {
+        logging::logMessage("Invalid parameters recieved.");
+        return false;
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        logging::logMessage("Invalid JSON object recieved.");
+        return false;
+    }
+
+    if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
+    {
+        logging::logMessage(
+            "JSON object does not contain EEPROM path " + i_vpdFruPath);
+        return false;
+    }
+
+    if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
+    {
+        if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
+                i_flowFlag))
+        {
+            return true;
+        }
+
+        logging::logMessage("Flow flag: [" + i_flowFlag +
+                            "], not found in JSON for path: " + i_vpdFruPath);
+        return false;
+    }
+    return false;
+}
+
+/**
+ * @brief An API to return list of FRUs that needs GPIO polling.
+ *
+ * An API that checks for the FRUs that requires GPIO polling and returns
+ * a list of FRUs that needs polling. Returns an empty list if there are
+ * no FRUs that requires polling.
+ *
+ * @throw std::runtime_error
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ *
+ * @return list of FRUs parameters that needs polling.
+ */
+inline std::vector<std::string>
+    getListOfGpioPollingFrus(const nlohmann::json& i_sysCfgJsonObj)
+{
+    if (i_sysCfgJsonObj.empty())
+    {
+        throw std::runtime_error("Invalid Parameters");
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        throw std::runtime_error("Missing frus section in system config JSON");
+    }
+
+    std::vector<std::string> l_gpioPollingRequiredFrusList;
+
+    for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
+    {
+        const auto l_fruPath = l_fru.key();
+
+        try
+        {
+            if (isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
+                                 "hotPlugging"))
+            {
+                if (i_sysCfgJsonObj["frus"][l_fruPath]
+                        .at(0)["pollingRequired"]["hotPlugging"]
+                        .contains("gpioPresence"))
+                {
+                    l_gpioPollingRequiredFrusList.push_back(l_fruPath);
+                }
+            }
+        }
+        catch (const std::exception& l_ex)
+        {
+            logging::logMessage(l_ex.what());
+        }
+    }
+
+    return l_gpioPollingRequiredFrusList;
+}
+
+/**
+ * @brief Get all related path(s) to update keyword value.
+ *
+ * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
+ * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
+ * exists in the system config JSON.
+ *
+ * Note: If the inventory object path or redundant EEPROM path(s) are not found
+ * in the system config JSON, corresponding fields will have empty value in the
+ * returning tuple.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
+ *
+ * @return On success returns tuple of EEPROM path, inventory path & redundant
+ * path, on failure returns tuple with given input path alone.
+ */
+inline std::tuple<std::string, std::string, std::string>
+    getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
+                               std::string io_vpdPath)
+{
+    types::Path l_inventoryObjPath;
+    types::Path l_redundantFruPath;
+    try
+    {
+        if (!i_sysCfgJsonObj.empty())
+        {
+            // Get hardware path from system config JSON.
+            const types::Path l_fruPath =
+                jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath);
+
+            if (!l_fruPath.empty())
+            {
+                io_vpdPath = l_fruPath;
+
+                // Get inventory object path from system config JSON
+                l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
+                    i_sysCfgJsonObj, l_fruPath);
+
+                // Get redundant hardware path if present in system config JSON
+                l_redundantFruPath =
+                    jsonUtility::getRedundantEepromPathFromJson(i_sysCfgJsonObj,
+                                                                l_fruPath);
+            }
+        }
+    }
+    catch (const std::exception& l_exception)
+    {
+        logging::logMessage(
+            "Failed to get all paths to update keyword value, error " +
+            std::string(l_exception.what()));
+    }
+    return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
+}
+
+/**
+ * @brief An API to get DBus service name.
+ *
+ * Given DBus inventory path, this API returns DBus service name if present in
+ * the JSON.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] l_inventoryPath - DBus inventory path.
+ *
+ * @return On success returns the service name present in the system config
+ * JSON, otherwise empty string.
+ *
+ * Note: Caller has to handle in case of empty string received.
+ */
+inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
+                                  const std::string& l_inventoryPath)
+{
+    try
+    {
+        if (l_inventoryPath.empty())
+        {
+            throw std::runtime_error("Path parameter is empty.");
+        }
+
+        if (!i_sysCfgJsonObj.contains("frus"))
+        {
+            throw std::runtime_error("Missing frus tag in system config JSON.");
+        }
+
+        const nlohmann::json& l_listOfFrus =
+            i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+        for (const auto& l_frus : l_listOfFrus.items())
+        {
+            for (const auto& l_inventoryItem : l_frus.value())
+            {
+                if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
+                    constants::STR_CMP_SUCCESS)
+                {
+                    return l_inventoryItem["serviceName"];
+                }
+            }
+        }
+        throw std::runtime_error(
+            "Inventory path not found in the system config JSON");
+    }
+    catch (const std::exception& l_exception)
+    {
+        logging::logMessage(
+            "Error while getting DBus service name for given path " +
+            l_inventoryPath + ", error: " + std::string(l_exception.what()));
+        // TODO:log PEL
+    }
+    return std::string{};
+}
+
+/**
+ * @brief An API to check if a FRU is tagged as "powerOffOnly"
+ *
+ * Given the system config JSON and VPD FRU path, this API checks if the FRU
+ * VPD can be collected at Chassis Power Off state only.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] i_vpdFruPath - EEPROM path.
+ * @return - True if FRU VPD can be collected at Chassis Power Off state only.
+ *           False otherwise
+ */
+inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
+                              const std::string& i_vpdFruPath)
+{
+    if (i_vpdFruPath.empty())
+    {
+        logging::logMessage("FRU path is empty.");
+        return false;
+    }
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        logging::logMessage("Missing frus tag in system config JSON.");
+        return false;
+    }
+
+    if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
+    {
+        logging::logMessage("JSON object does not contain EEPROM path \'" +
+                            i_vpdFruPath + "\'");
+        return false;
+    }
+
+    return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
+                .contains("powerOffOnly") &&
+            (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
+}
+
+/**
+ * @brief API which tells if the FRU is replaceable at runtime
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] i_vpdFruPath - EEPROM path.
+ *
+ * @return true if FRU is replaceable at runtime. false otherwise.
+ */
+inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
+                                      const std::string& i_vpdFruPath)
+{
+    try
+    {
+        if (i_vpdFruPath.empty())
+        {
+            throw std::runtime_error("Given FRU path is empty.");
+        }
+
+        if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
+        {
+            throw std::runtime_error("Invalid system config JSON object.");
+        }
+
+        return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
+                    .contains("replaceableAtRuntime") &&
+                (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
+                    0)["replaceableAtRuntime"]));
+    }
+    catch (const std::exception& l_error)
+    {
+        // TODO: Log PEL
+        logging::logMessage(l_error.what());
+    }
+
+    return false;
+}
+
+/**
+ * @brief API which tells if the FRU is replaceable at standby
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ * @param[in] i_vpdFruPath - EEPROM path.
+ *
+ * @return true if FRU is replaceable at standby. false otherwise.
+ */
+inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
+                                      const std::string& i_vpdFruPath)
+{
+    try
+    {
+        if (i_vpdFruPath.empty())
+        {
+            throw std::runtime_error("Given FRU path is empty.");
+        }
+
+        if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
+        {
+            throw std::runtime_error("Invalid system config JSON object.");
+        }
+
+        return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
+                    .contains("replaceableAtStandby") &&
+                (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
+                    0)["replaceableAtStandby"]));
+    }
+    catch (const std::exception& l_error)
+    {
+        // TODO: Log PEL
+        logging::logMessage(l_error.what());
+    }
+
+    return false;
+}
+
+/**
+ * @brief API to get list of FRUs replaceable at standby from JSON.
+ *
+ * The API will return a vector of FRUs inventory path which are replaceable at
+ * standby.
+ * The API can throw exception in case of error scenarios. Caller's
+ * responsibility to handle those exceptions.
+ *
+ * @param[in] i_sysCfgJsonObj - System config JSON object.
+ *
+ * @return - List of FRUs replaceable at standby.
+ */
+inline std::vector<std::string>
+    getListOfFrusReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj)
+{
+    std::vector<std::string> l_frusReplaceableAtStandby;
+
+    if (!i_sysCfgJsonObj.contains("frus"))
+    {
+        logging::logMessage("Missing frus tag in system config JSON.");
+        return l_frusReplaceableAtStandby;
+    }
+
+    const nlohmann::json& l_fruList =
+        i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
+
+    for (const auto& l_fru : l_fruList.items())
+    {
+        if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
+                "replaceableAtStandby", false))
+        {
+            const std::string& l_inventoryObjectPath =
+                i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
+                    "inventoryPath", "");
+
+            if (!l_inventoryObjectPath.empty())
+            {
+                l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath);
+            }
+        }
+    }
+
+    return l_frusReplaceableAtStandby;
+}
+
+} // namespace jsonUtility
+} // namespace vpd
diff --git a/vpd-manager/include/utility/vpd_specific_utility.hpp b/vpd-manager/include/utility/vpd_specific_utility.hpp
new file mode 100644
index 0000000..d6b92fd
--- /dev/null
+++ b/vpd-manager/include/utility/vpd_specific_utility.hpp
@@ -0,0 +1,556 @@
+#pragma once
+
+#include "config.h"
+
+#include "constants.hpp"
+#include "exceptions.hpp"
+#include "logger.hpp"
+#include "types.hpp"
+
+#include <nlohmann/json.hpp>
+#include <utility/common_utility.hpp>
+#include <utility/dbus_utility.hpp>
+
+#include <filesystem>
+#include <fstream>
+#include <regex>
+
+namespace vpd
+{
+namespace vpdSpecificUtility
+{
+/**
+ * @brief API to generate file name for bad VPD.
+ *
+ * For i2c eeproms - the pattern of the vpd-name will be
+ * i2c-<bus-number>-<eeprom-address>.
+ * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>.
+ *
+ * @param[in] vpdFilePath - file path of the vpd.
+ * @return Generated file name.
+ */
+inline std::string generateBadVPDFileName(const std::string& vpdFilePath)
+{
+    std::string badVpdFileName = BAD_VPD_DIR;
+    if (vpdFilePath.find("i2c") != std::string::npos)
+    {
+        badVpdFileName += "i2c-";
+        std::regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
+        std::smatch match;
+        if (std::regex_search(vpdFilePath, match, i2cPattern))
+        {
+            badVpdFileName += match.str(2);
+        }
+    }
+    else if (vpdFilePath.find("spi") != std::string::npos)
+    {
+        std::regex spiPattern("((spi)[0-9]+)(.0)");
+        std::smatch match;
+        if (std::regex_search(vpdFilePath, match, spiPattern))
+        {
+            badVpdFileName += match.str(1);
+        }
+    }
+    return badVpdFileName;
+}
+
+/**
+ * @brief API which dumps the broken/bad vpd in a directory.
+ * When the vpd is bad, this API places  the bad vpd file inside
+ * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
+ * initiated BMC dump.
+ *
+ * Note: Throws exception in case of any failure.
+ *
+ * @param[in] vpdFilePath - vpd file path
+ * @param[in] vpdVector - vpd vector
+ */
+inline void dumpBadVpd(const std::string& vpdFilePath,
+                       const types::BinaryVector& vpdVector)
+{
+    std::filesystem::create_directory(BAD_VPD_DIR);
+    auto badVpdPath = generateBadVPDFileName(vpdFilePath);
+
+    if (std::filesystem::exists(badVpdPath))
+    {
+        std::error_code ec;
+        std::filesystem::remove(badVpdPath, ec);
+        if (ec) // error code
+        {
+            std::string error = "Error removing the existing broken vpd in ";
+            error += badVpdPath;
+            error += ". Error code : ";
+            error += ec.value();
+            error += ". Error message : ";
+            error += ec.message();
+            throw std::runtime_error(error);
+        }
+    }
+
+    std::ofstream badVpdFileStream(badVpdPath, std::ofstream::binary);
+    if (badVpdFileStream.is_open())
+    {
+        throw std::runtime_error(
+            "Failed to open bad vpd file path in /tmp/bad-vpd. "
+            "Unable to dump the broken/bad vpd file.");
+    }
+
+    badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()),
+                           vpdVector.size());
+}
+
+/**
+ * @brief An API to read value of a keyword.
+ *
+ * Note: Throws exception. Caller needs to handle.
+ *
+ * @param[in] kwdValueMap - A map having Kwd value pair.
+ * @param[in] kwd - keyword name.
+ * @param[out] kwdValue - Value of the keyword read from map.
+ */
+inline void getKwVal(const types::IPZKwdValueMap& kwdValueMap,
+                     const std::string& kwd, std::string& kwdValue)
+{
+    if (kwd.empty())
+    {
+        logging::logMessage("Invalid parameters");
+        throw std::runtime_error("Invalid parameters");
+    }
+
+    auto itrToKwd = kwdValueMap.find(kwd);
+    if (itrToKwd != kwdValueMap.end())
+    {
+        kwdValue = itrToKwd->second;
+        return;
+    }
+
+    throw std::runtime_error("Keyword not found");
+}
+
+/**
+ * @brief An API to process encoding of a keyword.
+ *
+ * @param[in] keyword - Keyword to be processed.
+ * @param[in] encoding - Type of encoding.
+ * @return Value after being processed for encoded type.
+ */
+inline std::string encodeKeyword(const std::string& keyword,
+                                 const std::string& encoding)
+{
+    // Default value is keyword value
+    std::string result(keyword.begin(), keyword.end());
+
+    if (encoding == "MAC")
+    {
+        result.clear();
+        size_t firstByte = keyword[0];
+        result += commonUtility::toHex(firstByte >> 4);
+        result += commonUtility::toHex(firstByte & 0x0f);
+        for (size_t i = 1; i < keyword.size(); ++i)
+        {
+            result += ":";
+            result += commonUtility::toHex(keyword[i] >> 4);
+            result += commonUtility::toHex(keyword[i] & 0x0f);
+        }
+    }
+    else if (encoding == "DATE")
+    {
+        // Date, represent as
+        // <year>-<month>-<day> <hour>:<min>
+        result.clear();
+        static constexpr uint8_t skipPrefix = 3;
+
+        auto strItr = keyword.begin();
+        advance(strItr, skipPrefix);
+        for_each(strItr, keyword.end(), [&result](size_t c) { result += c; });
+
+        result.insert(constants::BD_YEAR_END, 1, '-');
+        result.insert(constants::BD_MONTH_END, 1, '-');
+        result.insert(constants::BD_DAY_END, 1, ' ');
+        result.insert(constants::BD_HOUR_END, 1, ':');
+    }
+
+    return result;
+}
+
+/**
+ * @brief Helper function to insert or merge in map.
+ *
+ * This method checks in an interface if the given interface exists. If the
+ * interface key already exists, property map is inserted corresponding to it.
+ * If the key does'nt exist then given interface and property map pair is newly
+ * created. If the property present in propertymap already exist in the
+ * InterfaceMap, then the new property value is ignored.
+ *
+ * @param[in,out] map - Interface map.
+ * @param[in] interface - Interface to be processed.
+ * @param[in] propertyMap - new property map that needs to be emplaced.
+ */
+inline void insertOrMerge(types::InterfaceMap& map,
+                          const std::string& interface,
+                          types::PropertyMap&& propertyMap)
+{
+    if (map.find(interface) != map.end())
+    {
+        try
+        {
+            auto& prop = map.at(interface);
+            std::for_each(propertyMap.begin(), propertyMap.end(),
+                          [&prop](auto l_keyValue) {
+                              prop[l_keyValue.first] = l_keyValue.second;
+                          });
+        }
+        catch (const std::exception& l_ex)
+        {
+            // ToDo:: Log PEL
+            logging::logMessage(
+                "Inserting properties into interface[" + interface +
+                "] map is failed, reason: " + std::string(l_ex.what()));
+        }
+    }
+    else
+    {
+        map.emplace(interface, propertyMap);
+    }
+}
+
+/**
+ * @brief API to expand unpanded location code.
+ *
+ * Note: The API handles all the exception internally, in case of any error
+ * unexpanded location code will be returned as it is.
+ *
+ * @param[in] unexpandedLocationCode - Unexpanded location code.
+ * @param[in] parsedVpdMap - Parsed VPD map.
+ * @return Expanded location code. In case of any error, unexpanded is returned
+ * as it is.
+ */
+inline std::string
+    getExpandedLocationCode(const std::string& unexpandedLocationCode,
+                            const types::VPDMapVariant& parsedVpdMap)
+{
+    auto expanded{unexpandedLocationCode};
+
+    try
+    {
+        // Expanded location code is formed by combining two keywords
+        // depending on type in unexpanded one. Second one is always "SE".
+        std::string kwd1, kwd2{constants::kwdSE};
+
+        // interface to search for required keywords;
+        std::string kwdInterface;
+
+        // record which holds the required keywords.
+        std::string recordName;
+
+        auto pos = unexpandedLocationCode.find("fcs");
+        if (pos != std::string::npos)
+        {
+            kwd1 = constants::kwdFC;
+            kwdInterface = constants::vcenInf;
+            recordName = constants::recVCEN;
+        }
+        else
+        {
+            pos = unexpandedLocationCode.find("mts");
+            if (pos != std::string::npos)
+            {
+                kwd1 = constants::kwdTM;
+                kwdInterface = constants::vsysInf;
+                recordName = constants::recVSYS;
+            }
+            else
+            {
+                throw std::runtime_error(
+                    "Error detecting type of unexpanded location code.");
+            }
+        }
+
+        std::string firstKwdValue, secondKwdValue;
+
+        if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
+            ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
+        {
+            auto itrToVCEN = (*ipzVpdMap).find(recordName);
+            // The exceptions will be cautght at end.
+            getKwVal(itrToVCEN->second, kwd1, firstKwdValue);
+            getKwVal(itrToVCEN->second, kwd2, secondKwdValue);
+        }
+        else
+        {
+            std::array<const char*, 1> interfaceList = {kwdInterface.c_str()};
+
+            types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
+                std::string(constants::systemVpdInvPath), interfaceList);
+
+            if (mapperRetValue.empty())
+            {
+                throw std::runtime_error("Mapper failed to get service");
+            }
+
+            const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
+
+            auto retVal = dbusUtility::readDbusProperty(
+                serviceName, std::string(constants::systemVpdInvPath),
+                kwdInterface, kwd1);
+
+            if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
+            {
+                firstKwdValue.assign(
+                    reinterpret_cast<const char*>(kwdVal->data()),
+                    kwdVal->size());
+            }
+            else
+            {
+                throw std::runtime_error(
+                    "Failed to read value of " + kwd1 + " from Bus");
+            }
+
+            retVal = dbusUtility::readDbusProperty(
+                serviceName, std::string(constants::systemVpdInvPath),
+                kwdInterface, kwd2);
+
+            if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
+            {
+                secondKwdValue.assign(
+                    reinterpret_cast<const char*>(kwdVal->data()),
+                    kwdVal->size());
+            }
+            else
+            {
+                throw std::runtime_error(
+                    "Failed to read value of " + kwd2 + " from Bus");
+            }
+        }
+
+        if (unexpandedLocationCode.find("fcs") != std::string::npos)
+        {
+            // TODO: See if ND0 can be placed in the JSON
+            expanded.replace(
+                pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
+        }
+        else
+        {
+            replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
+            expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        logging::logMessage("Failed to expand location code with exception: " +
+                            std::string(ex.what()));
+    }
+
+    return expanded;
+}
+
+/**
+ * @brief An API to get VPD in a vector.
+ *
+ * The vector is required by the respective parser to fill the VPD map.
+ * Note: API throws exception in case of failure. Caller needs to handle.
+ *
+ * @param[in] vpdFilePath - EEPROM path of the FRU.
+ * @param[out] vpdVector - VPD in vector form.
+ * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
+ */
+inline void getVpdDataInVector(const std::string& vpdFilePath,
+                               types::BinaryVector& vpdVector,
+                               size_t& vpdStartOffset)
+{
+    try
+    {
+        std::fstream vpdFileStream;
+        vpdFileStream.exceptions(
+            std::ifstream::badbit | std::ifstream::failbit);
+        vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
+        auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
+                                      static_cast<uintmax_t>(65504));
+        vpdVector.resize(vpdSizeToRead);
+
+        vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
+        vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
+                           vpdSizeToRead);
+
+        vpdVector.resize(vpdFileStream.gcount());
+        vpdFileStream.clear(std::ios_base::eofbit);
+    }
+    catch (const std::ifstream::failure& fail)
+    {
+        std::cerr << "Exception in file handling [" << vpdFilePath
+                  << "] error : " << fail.what();
+        throw;
+    }
+}
+
+/**
+ * @brief An API to get D-bus representation of given VPD keyword.
+ *
+ * @param[in] i_keywordName - VPD keyword name.
+ *
+ * @return D-bus representation of given keyword.
+ */
+inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName)
+{
+    // Check for "#" prefixed VPD keyword.
+    if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
+        (i_keywordName.at(0) == constants::POUND_KW))
+    {
+        // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
+        // prefixed keywords.
+        return (std::string(constants::POUND_KW_PREFIX) +
+                i_keywordName.substr(1));
+    }
+
+    // Return the keyword name back, if D-bus representation is same as the VPD
+    // keyword name.
+    return i_keywordName;
+}
+
+/**
+ * @brief API to find CCIN in parsed VPD map.
+ *
+ * Few FRUs need some special handling. To identify those FRUs CCIN are used.
+ * The API will check from parsed VPD map if the FRU is the one with desired
+ * CCIN.
+ *
+ * @throw std::runtime_error
+ * @throw DataException
+ *
+ * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
+ * @param[in] i_parsedVpdMap - Parsed VPD map.
+ * @return True if found, false otherwise.
+ */
+inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
+                          const types::VPDMapVariant& i_parsedVpdMap)
+{
+    if (i_JsonObject.empty())
+    {
+        throw std::runtime_error("Json object is empty. Can't find CCIN");
+    }
+
+    if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
+    {
+        auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
+        if (l_itrToRec == (*l_ipzVPDMap).end())
+        {
+            throw DataException(
+                "VINI record not found in parsed VPD. Can't find CCIN");
+        }
+
+        std::string l_ccinFromVpd;
+        vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC", l_ccinFromVpd);
+        if (l_ccinFromVpd.empty())
+        {
+            throw DataException("Empty CCIN value in VPD map. Can't find CCIN");
+        }
+
+        transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
+                  l_ccinFromVpd.begin(), ::toupper);
+
+        for (std::string l_ccinValue : i_JsonObject["ccin"])
+        {
+            transform(l_ccinValue.begin(), l_ccinValue.end(),
+                      l_ccinValue.begin(), ::toupper);
+
+            if (l_ccinValue.compare(l_ccinFromVpd) ==
+                constants::STR_CMP_SUCCESS)
+            {
+                // CCIN found
+                return true;
+            }
+        }
+
+        logging::logMessage("No match found for CCIN");
+        return false;
+    }
+
+    logging::logMessage("VPD type not supported. Can't find CCIN");
+    return false;
+}
+
+/**
+ * @brief API to reset data of a FRU populated under PIM.
+ *
+ * This API resets the data for particular interfaces of a FRU under PIM.
+ *
+ * @param[in] i_objectPath - DBus object path of the FRU.
+ * @param[in] io_interfaceMap - Interface and its properties map.
+ */
+inline void resetDataUnderPIM(const std::string& i_objectPath,
+                              types::InterfaceMap& io_interfaceMap)
+{
+    try
+    {
+        std::array<const char*, 0> l_interfaces;
+        const types::MapperGetObject& l_getObjectMap =
+            dbusUtility::getObjectMap(i_objectPath, l_interfaces);
+
+        const std::vector<std::string>& l_vpdRelatedInterfaces{
+            constants::operationalStatusInf, constants::inventoryItemInf,
+            constants::assetInf};
+
+        for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
+        {
+            if (l_service.compare(constants::pimServiceName) !=
+                constants::STR_CMP_SUCCESS)
+            {
+                continue;
+            }
+
+            for (const auto& l_interface : l_interfaceList)
+            {
+                if ((l_interface.find(constants::ipzVpdInf) !=
+                     std::string::npos) ||
+                    ((std::find(l_vpdRelatedInterfaces.begin(),
+                                l_vpdRelatedInterfaces.end(), l_interface)) !=
+                     l_vpdRelatedInterfaces.end()))
+                {
+                    const types::PropertyMap& l_propertyValueMap =
+                        dbusUtility::getPropertyMap(l_service, i_objectPath,
+                                                    l_interface);
+
+                    types::PropertyMap l_propertyMap;
+
+                    for (const auto& l_aProperty : l_propertyValueMap)
+                    {
+                        const std::string& l_propertyName = l_aProperty.first;
+                        const auto& l_propertyValue = l_aProperty.second;
+
+                        if (std::holds_alternative<types::BinaryVector>(
+                                l_propertyValue))
+                        {
+                            l_propertyMap.emplace(l_propertyName,
+                                                  types::BinaryVector{});
+                        }
+                        else if (std::holds_alternative<std::string>(
+                                     l_propertyValue))
+                        {
+                            l_propertyMap.emplace(l_propertyName,
+                                                  std::string{});
+                        }
+                        else if (std::holds_alternative<bool>(l_propertyValue))
+                        {
+                            // ToDo -- Update the functional status property
+                            // to true.
+                            if (l_propertyName.compare("Present") ==
+                                constants::STR_CMP_SUCCESS)
+                            {
+                                l_propertyMap.emplace(l_propertyName, false);
+                            }
+                        }
+                    }
+                    io_interfaceMap.emplace(l_interface,
+                                            std::move(l_propertyMap));
+                }
+            }
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath +
+                            " with error: " + std::string(l_ex.what()));
+    }
+}
+} // namespace vpdSpecificUtility
+} // namespace vpd
diff --git a/vpd-manager/include/worker.hpp b/vpd-manager/include/worker.hpp
new file mode 100644
index 0000000..85a1818
--- /dev/null
+++ b/vpd-manager/include/worker.hpp
@@ -0,0 +1,529 @@
+#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.
+     *
+     * Note: Throws std::exception in case of construction failure. Caller needs
+     * to handle to detect successful object creation.
+     */
+    Worker(std::string pathToConfigJson = std::string());
+
+    /**
+     * @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;
+    }
+
+  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::runtime_error
+     */
+    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.
+     *
+     * @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 Helper function to insert or merge in map.
+     *
+     * This method checks in the given inventory::InterfaceMap if the given
+     * interface key is existing or not. If the interface key already exists,
+     * given property map is inserted into it. If the key does'nt exist then
+     * given interface and property map pair is newly created. If the property
+     * present in propertymap already exist in the InterfaceMap, then the new
+     * property value is ignored.
+     *
+     * @param[in,out] interfaceMap - map object of type inventory::InterfaceMap
+     * only.
+     * @param[in] interface - Interface name.
+     * @param[in] property - new property map that needs to be emplaced.
+     */
+    void insertOrMerge(types::InterfaceMap& interfaceMap,
+                       const std::string& interface,
+                       types::PropertyMap&& property);
+
+    /**
+     * @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);
+
+    // 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{
+        constants::MAX_THREADS};
+};
+} // namespace vpd