Add support for vendor specific FruDbusLookup

In the current state, a vendor could not define the FRU's
that he wants to send to the host.

This commit adds a fru_master.json that can be used while
building the master , and the json would be replaced with
fru_master.json from the oem/<vendor>/configurations
directory when compiling for oem's.

Tested By:

IBM machine test :
1. meson build -Doem-ibm=enabled -Dprefix=<>
2. ninja -C build && ninja install
3. in the prefix directory we should see the json file
   from the oem/ibm/configurations folder

Non IBM machine test :
1. meson build -Doem-ibm=disabled -Dprefix=<>
2. ninja -C build && ninja install
3. in the prefix directory we should see the json file
   from the pldm/configurations folder.

Runtime test:
1. on an IBM machine make sure the pldm builds the fru record
   table.

Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: Id3c2746c51a1f99f2038b2af48137133e9d0b405
diff --git a/configurations/fru_master.json b/configurations/fru_master.json
new file mode 100644
index 0000000..5a87eb7
--- /dev/null
+++ b/configurations/fru_master.json
@@ -0,0 +1,21 @@
+{
+        "FruDBusLookupMap":{
+                        "xyz.openbmc_project.Inventory.Item.Chassis" : 45,
+                        "xyz.openbmc_project.Inventory.Item.Board": 60,
+                        "xyz.openbmc_project.Inventory.Item.PCIeDevice": 61,
+                        "xyz.openbmc_project.Inventory.Item.Board.Motherboard": 64,
+                        "xyz.openbmc_project.Inventory.Item.Dimm": 66,
+                        "xyz.openbmc_project.Inventory.Item.Panel": 69,
+                        "xyz.openbmc_project.Inventory.Item.DiskBackplane": 73,
+                        "xyz.openbmc_project.Inventory.Item.Fan": 93,
+                        "xyz.openbmc_project.Inventory.Item.PowerSupply": 120,
+                        "xyz.openbmc_project.Inventory.Item.Battery": 121,
+                        "xyz.openbmc_project.Inventory.Item.Vrm": 123,
+                        "xyz.openbmc_project.Inventory.Item.Cpu": 135,
+                        "xyz.openbmc_project.Inventory.Item.Bmc": 137,
+                        "xyz.openbmc_project.Inventory.Item.Connector": 185,
+                        "xyz.openbmc_project.Inventory.Item.PCIeSlot": 186,
+                        "xyz.openbmc_project.Inventory.Item.System": 11521,
+                        "xyz.openbmc_project.Inventory.Item.Tpm": 24576
+           }
+}
diff --git a/configurations/meson.build b/configurations/meson.build
index 99accae..ccb9b62 100644
--- a/configurations/meson.build
+++ b/configurations/meson.build
@@ -11,10 +11,15 @@
 
 install_subdir('events', install_dir: packagedir)
 
+if get_option('oem-ibm').disabled()
+install_data('fru_master.json', install_dir: packagedir)
+endif
+
 if get_option('oem-ibm').enabled()
     install_subdir('../oem/ibm/configurations/fru', install_dir: packagedir)
     install_subdir('../oem/ibm/configurations/events', install_dir: packagedir)
     install_subdir('../oem/ibm/configurations/bios', install_dir: packagedir)
+    install_data('../oem/ibm/configurations/fru_master.json',install_dir: packagedir)
     install_data('../oem/ibm/configurations/fileTable.json',
         install_dir: packagedir)
     install_data('../oem/ibm/configurations/host_eid', install_dir: packagedir)
diff --git a/libpldmresponder/fru.hpp b/libpldmresponder/fru.hpp
index 18c7882..963a606 100644
--- a/libpldmresponder/fru.hpp
+++ b/libpldmresponder/fru.hpp
@@ -55,15 +55,18 @@
      *
      *  @param[in] configPath - path to the directory containing config files
      *                          for PLDM FRU
+     *  @param[in] fruMasterJsonPath - path to the file containing the FRU D-Bus
+     *                                 Lookup Map
      *  @param[in] pdrRepo - opaque pointer to PDR repository
      *  @param[in] entityTree - opaque pointer to the entity association tree
      *  @param[in] bmcEntityTree - opaque pointer to bmc's entity association
      *                             tree
      */
-    FruImpl(const std::string& configPath, pldm_pdr* pdrRepo,
+    FruImpl(const std::string& configPath,
+            const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo,
             pldm_entity_association_tree* entityTree,
             pldm_entity_association_tree* bmcEntityTree) :
-        parser(configPath),
+        parser(configPath, fruMasterJsonPath),
         pdrRepo(pdrRepo), entityTree(entityTree), bmcEntityTree(bmcEntityTree)
     {}
 
@@ -190,10 +193,11 @@
 {
 
   public:
-    Handler(const std::string& configPath, pldm_pdr* pdrRepo,
+    Handler(const std::string& configPath,
+            const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo,
             pldm_entity_association_tree* entityTree,
             pldm_entity_association_tree* bmcEntityTree) :
-        impl(configPath, pdrRepo, entityTree, bmcEntityTree)
+        impl(configPath, fruMasterJsonPath, pdrRepo, entityTree, bmcEntityTree)
     {
         handlers.emplace(PLDM_GET_FRU_RECORD_TABLE_METADATA,
                          [this](const pldm_msg* request, size_t payloadLength) {
diff --git a/libpldmresponder/fru_parser.cpp b/libpldmresponder/fru_parser.cpp
index a59d61a..28f48a7 100644
--- a/libpldmresponder/fru_parser.cpp
+++ b/libpldmresponder/fru_parser.cpp
@@ -24,9 +24,13 @@
 const std::vector<Json> emptyJsonList{};
 const std::vector<std::string> emptyStringVec{};
 
-FruParser::FruParser(const std::string& dirPath)
+FruParser::FruParser(const std::string& dirPath,
+                     const fs::path& fruMasterJsonPath)
 {
-    setupDefaultDBusLookup();
+    if (fs::exists(fruMasterJsonPath))
+    {
+        setupDefaultDBusLookup(fruMasterJsonPath);
+    }
     setupDefaultFruRecordMap();
 
     fs::path dir(dirPath);
@@ -36,31 +40,35 @@
     }
 }
 
-void FruParser::setupDefaultDBusLookup()
+void FruParser::setupDefaultDBusLookup(const fs::path& masterJsonPath)
 {
     constexpr auto service = "xyz.openbmc_project.Inventory.Manager";
     constexpr auto rootPath = "/xyz/openbmc_project/inventory";
+    std::ifstream jsonFile(masterJsonPath);
+    auto data = Json::parse(jsonFile, nullptr, false);
+    if (data.is_discarded())
+    {
 
-    // DSP0249 1.0.0    Table 15 Entity ID Codes
-    const std::map<Interface, EntityType> defIntfToEntityType = {
-        {"xyz.openbmc_project.Inventory.Item.Chassis", 45},
-        {"xyz.openbmc_project.Inventory.Item.Board", 60},
-        {"xyz.openbmc_project.Inventory.Item.PCIeDevice", 61},
-        {"xyz.openbmc_project.Inventory.Item.Board.Motherboard", 64},
-        {"xyz.openbmc_project.Inventory.Item.Dimm", 66},
-        {"xyz.openbmc_project.Inventory.Item.Panel", 69},
-        {"xyz.openbmc_project.Inventory.Item.DiskBackplane", 73},
-        {"xyz.openbmc_project.Inventory.Item.Fan", 93},
-        {"xyz.openbmc_project.Inventory.Item.PowerSupply", 120},
-        {"xyz.openbmc_project.Inventory.Item.Battery", 121},
-        {"xyz.openbmc_project.Inventory.Item.Vrm", 123},
-        {"xyz.openbmc_project.Inventory.Item.Cpu", 135},
-        {"xyz.openbmc_project.Inventory.Item.Bmc", 137},
-        {"xyz.openbmc_project.Inventory.Item.Connector", 185},
-        {"xyz.openbmc_project.Inventory.Item.PCIeSlot", 186},
-        {"xyz.openbmc_project.Inventory.Item.System", 11521},
-        {"xyz.openbmc_project.Inventory.Item.Tpm", 24576},
-    };
+        std::cerr << "Parsing FRU Dbus Lookup Map config file failed, FILE="
+                  << masterJsonPath;
+        std::abort();
+    }
+    std::map<Interface, EntityType> defIntfToEntityType;
+    auto dbusMap = data.value("FruDBusLookupMap", emptyJson);
+    for (const auto& element : dbusMap.items())
+
+    {
+        try
+        {
+            defIntfToEntityType[static_cast<Interface>(element.key())] =
+                static_cast<EntityType>(element.value());
+        }
+        catch (const std::exception& e)
+        {
+            std::cerr << "FRU DBus lookup map format error\n";
+            throw InternalFailure();
+        }
+    }
 
     Interfaces interfaces{};
     for (auto [intf, entityType] : defIntfToEntityType)
diff --git a/libpldmresponder/fru_parser.hpp b/libpldmresponder/fru_parser.hpp
index ce09986..fc3234e 100644
--- a/libpldmresponder/fru_parser.hpp
+++ b/libpldmresponder/fru_parser.hpp
@@ -67,7 +67,8 @@
 
   public:
     FruParser() = delete;
-    explicit FruParser(const std::string& dirPath);
+    explicit FruParser(const std::string& dirPath,
+                       const std::filesystem::path& fruMasterJsonPath);
     virtual ~FruParser() = default;
     FruParser(const FruParser&) = default;
     FruParser& operator=(const FruParser&) = default;
@@ -121,8 +122,11 @@
     void setupFruRecordMap(const std::string& dirPath);
 
     /** @brief Set the default service root D-Bus path and the item interfaces.
+     *
+     *  @param[in] fruMasterJsonPath - json file path that contains the FRU
+     * D-Bus lookup map
      */
-    void setupDefaultDBusLookup();
+    void setupDefaultDBusLookup(const std::filesystem::path& fruMasterJsonPath);
 
     /** @brief Build the default FRU record informations
      */
diff --git a/libpldmresponder/test/fru_jsons/fru_master/fru_master.json b/libpldmresponder/test/fru_jsons/fru_master/fru_master.json
new file mode 100644
index 0000000..5a87eb7
--- /dev/null
+++ b/libpldmresponder/test/fru_jsons/fru_master/fru_master.json
@@ -0,0 +1,21 @@
+{
+        "FruDBusLookupMap":{
+                        "xyz.openbmc_project.Inventory.Item.Chassis" : 45,
+                        "xyz.openbmc_project.Inventory.Item.Board": 60,
+                        "xyz.openbmc_project.Inventory.Item.PCIeDevice": 61,
+                        "xyz.openbmc_project.Inventory.Item.Board.Motherboard": 64,
+                        "xyz.openbmc_project.Inventory.Item.Dimm": 66,
+                        "xyz.openbmc_project.Inventory.Item.Panel": 69,
+                        "xyz.openbmc_project.Inventory.Item.DiskBackplane": 73,
+                        "xyz.openbmc_project.Inventory.Item.Fan": 93,
+                        "xyz.openbmc_project.Inventory.Item.PowerSupply": 120,
+                        "xyz.openbmc_project.Inventory.Item.Battery": 121,
+                        "xyz.openbmc_project.Inventory.Item.Vrm": 123,
+                        "xyz.openbmc_project.Inventory.Item.Cpu": 135,
+                        "xyz.openbmc_project.Inventory.Item.Bmc": 137,
+                        "xyz.openbmc_project.Inventory.Item.Connector": 185,
+                        "xyz.openbmc_project.Inventory.Item.PCIeSlot": 186,
+                        "xyz.openbmc_project.Inventory.Item.System": 11521,
+                        "xyz.openbmc_project.Inventory.Item.Tpm": 24576
+           }
+}
diff --git a/libpldmresponder/test/libpldmresponder_fru_test.cpp b/libpldmresponder/test/libpldmresponder_fru_test.cpp
index 8219d75..6c942da 100644
--- a/libpldmresponder/test/libpldmresponder_fru_test.cpp
+++ b/libpldmresponder/test/libpldmresponder_fru_test.cpp
@@ -5,7 +5,8 @@
 {
     using namespace pldm::responder::fru_parser;
 
-    FruParser parser{"./fru_jsons/good"};
+    FruParser parser{"./fru_jsons/good",
+                     "./fru_jsons/fru_master/fru_master.json"};
 
     // Get an item with a single PLDM FRU record
     FruRecordInfos cpu{
diff --git a/meson.build b/meson.build
index c5ca30e..949d889 100644
--- a/meson.build
+++ b/meson.build
@@ -27,6 +27,7 @@
 conf_data.set_quoted('BIOS_TABLES_DIR', '/var/lib/pldm/bios')
 conf_data.set_quoted('PDR_JSONS_DIR', '/usr/share/pldm/pdr')
 conf_data.set_quoted('FRU_JSONS_DIR', '/usr/share/pldm/fru')
+conf_data.set_quoted('FRU_MASTER_JSON', '/usr/share/pldm/fru_master.json')
 conf_data.set_quoted('HOST_JSONS_DIR', '/usr/share/pldm/host')
 conf_data.set_quoted('EVENTS_JSONS_DIR', '/usr/share/pldm/events')
 add_project_arguments('-DLIBPLDMRESPONDER', language : ['c','cpp'])
diff --git a/oem/ibm/configurations/fru_master.json b/oem/ibm/configurations/fru_master.json
new file mode 100644
index 0000000..1b913ea
--- /dev/null
+++ b/oem/ibm/configurations/fru_master.json
@@ -0,0 +1,19 @@
+{
+        "FruDBusLookupMap":{
+                        "xyz.openbmc_project.Inventory.Item.Chassis" : 45,
+                        "xyz.openbmc_project.Inventory.Item.Board": 60,
+                        "xyz.openbmc_project.Inventory.Item.PCIeDevice": 61,
+                        "xyz.openbmc_project.Inventory.Item.Board.Motherboard": 64,
+                        "xyz.openbmc_project.Inventory.Item.Panel": 69,
+                        "xyz.openbmc_project.Inventory.Item.DiskBackplane": 73,
+                        "xyz.openbmc_project.Inventory.Item.Fan": 93,
+                        "xyz.openbmc_project.Inventory.Item.PowerSupply": 120,
+                        "xyz.openbmc_project.Inventory.Item.Battery": 121,
+                        "xyz.openbmc_project.Inventory.Item.Vrm": 123,
+                        "xyz.openbmc_project.Inventory.Item.Bmc": 137,
+                        "xyz.openbmc_project.Inventory.Item.Connector": 185,
+                        "xyz.openbmc_project.Inventory.Item.PCIeSlot": 186,
+                        "xyz.openbmc_project.Inventory.Item.System": 11521,
+                        "xyz.openbmc_project.Inventory.Item.Tpm": 24576
+           }
+}
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index ca62bbd..58d71ce 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -221,7 +221,8 @@
         PLDM_BIOS, std::make_unique<bios::Handler>(sockfd, hostEID,
                                                    &dbusImplReq, &reqHandler));
     auto fruHandler = std::make_unique<fru::Handler>(
-        FRU_JSONS_DIR, pdrRepo.get(), entityTree.get(), bmcEntityTree.get());
+        FRU_JSONS_DIR, FRU_MASTER_JSON, pdrRepo.get(), entityTree.get(),
+        bmcEntityTree.get());
     // FRU table is built lazily when a FRU command or Get PDR command is
     // handled. To enable building FRU table, the FRU handler is passed to the
     // Platform handler.