fru: Function to remove the individual FRU Record
When there is a concurrent maintenance operation a FRU can be
removed or added. When the FRU is removed we must make sure that
the associated FRU Record set PDRs, State Effecter PDRs, State
Sensor PDRs, EntityAssociation PDRs need to be removed from the
repository. This commit adds the function that does the required
functionality.
Tested: Removal of a FRU say a Fan by making the present property
of the FRU as false. This action removes the corresponding
FRURecordSet PDRs, State effecter PDRs, State sensor PDRs and
also the Entity association PDRs from the repo. This also removes
the node corresponding to that FRU from the entity association
tree.
This behavior is observed for other FRUs as well.
Change-Id: I6c6e17e21807940ce6d4a230dbceafd9f7c5c958
Signed-off-by: Pavithra Barithaya <pavithrabarithaya07@gmail.com>
diff --git a/libpldmresponder/fru.cpp b/libpldmresponder/fru.cpp
index 3d170ec..c8e54e8 100644
--- a/libpldmresponder/fru.cpp
+++ b/libpldmresponder/fru.cpp
@@ -1,6 +1,7 @@
#include "fru.hpp"
#include "common/utils.hpp"
+#include "libpldmresponder/platform.hpp"
#include <libpldm/entity.h>
#include <libpldm/utils.h>
@@ -414,6 +415,230 @@
table = std::move(updatedFruTbl);
}
+void FruImpl::removeIndividualFRU(const std::string& fruObjPath)
+{
+ uint16_t rsi = objectPathToRSIMap[fruObjPath];
+ if (!rsi)
+ {
+ info("No Pdrs to delete for the object path {PATH}", "PATH",
+ fruObjPath);
+ return;
+ }
+ pldm_entity removeEntity;
+ uint16_t terminusHdl{};
+ uint16_t entityType{};
+ uint16_t entityInsNum{};
+ uint16_t containerId{};
+ uint32_t updateRecordHdlBmc = 0;
+ uint32_t updateRecordHdlHost = 0;
+ uint32_t deleteRecordHdl = 0;
+ bool hasError = false;
+
+ auto fruRecord = pldm_pdr_fru_record_set_find_by_rsi(
+ pdrRepo, rsi, &terminusHdl, &entityType, &entityInsNum, &containerId);
+
+ if (fruRecord == nullptr)
+ {
+ error("No matching FRU record found for RSI {RSI}", "RSI", rsi);
+ hasError = true;
+ return;
+ }
+
+ removeEntity = {entityType, entityInsNum, containerId};
+
+ auto removeBmcEntityRc =
+ pldm_entity_association_pdr_remove_contained_entity(
+ pdrRepo, &removeEntity, false, &updateRecordHdlBmc);
+ if (removeBmcEntityRc)
+ {
+ hasError = true;
+ error(
+ "Failed to remove entity [Type={TYPE}, Instance={INS}, Container={CONT}] "
+ "from BMC PDR. RC = {RC}",
+ "TYPE", static_cast<unsigned>(removeEntity.entity_type), "INS",
+ static_cast<unsigned>(removeEntity.entity_instance_num), "CONT",
+ static_cast<unsigned>(removeEntity.entity_container_id), "RC",
+ static_cast<int>(removeBmcEntityRc));
+ }
+
+ pldm::responder::pdr_utils::PdrEntry pdrEntry;
+ uint8_t* pdrData = nullptr;
+ auto record =
+ pldm_pdr_find_record(pdrRepo, updateRecordHdlBmc, &pdrData,
+ &pdrEntry.size, &pdrEntry.handle.nextRecordHandle);
+ if (record)
+ {
+ info("Found BMC Record {REC}", "REC", updateRecordHdlBmc);
+ }
+ auto bmcEventDataOps =
+ record ? PLDM_RECORDS_MODIFIED : PLDM_RECORDS_DELETED;
+
+ int removeHostEntityRc = -1;
+ uint8_t hostEventDataOps = 0;
+ if (!hasError)
+ {
+ removeHostEntityRc =
+ pldm_entity_association_pdr_remove_contained_entity(
+ pdrRepo, &removeEntity, true, &updateRecordHdlHost);
+ if (removeHostEntityRc)
+ {
+ hasError = true;
+ error(
+ "Failed to remove entity [Type={TYPE}, Instance={INS}, Container={CONT}] "
+ "from Host PDR. RC = {RC}",
+ "TYPE", static_cast<unsigned>(removeEntity.entity_type), "INS",
+ static_cast<unsigned>(removeEntity.entity_instance_num), "CONT",
+ static_cast<unsigned>(removeEntity.entity_container_id), "RC",
+ static_cast<int>(removeHostEntityRc));
+ }
+
+ record = pldm_pdr_find_record(pdrRepo, updateRecordHdlHost, &pdrData,
+ &pdrEntry.size,
+ &pdrEntry.handle.nextRecordHandle);
+ if (record)
+ {
+ info("Found Host Record {REC}", "REC", updateRecordHdlHost);
+ }
+
+ hostEventDataOps = record ? PLDM_RECORDS_MODIFIED
+ : PLDM_RECORDS_DELETED;
+ }
+ if (hasError)
+ {
+ error("Partial failure occurred while removing FRU {FRU_OBJ_PATH}",
+ "FRU_OBJ_PATH", fruObjPath);
+ return;
+ }
+
+ auto rc = pldm_pdr_remove_fru_record_set_by_rsi(pdrRepo, rsi, false,
+ &deleteRecordHdl);
+ if (rc)
+ {
+ hasError = true;
+ error("Failed to remove FRU record set for RSI {RSI}. RC = {RC}", "RSI",
+ rsi, "RC", rc);
+ }
+
+ if (!hasError)
+ {
+ auto rc =
+ pldm_entity_association_tree_delete_node(entityTree, &removeEntity);
+ if (rc)
+ {
+ hasError = true;
+ error("Failed to delete entity from association tree. RC = {RC}",
+ "RC", rc);
+ }
+
+ rc = pldm_entity_association_tree_delete_node(bmcEntityTree,
+ &removeEntity);
+ if (rc)
+ {
+ hasError = true;
+ error(
+ "Failed to delete entity from BMC association tree. RC = {RC}",
+ "RC", rc);
+ }
+ }
+
+ if (hasError)
+ {
+ error("Partial failure occurred while removing FRU {FRU_OBJ_PATH}",
+ "FRU_OBJ_PATH", fruObjPath);
+ return;
+ }
+
+ objectPathToRSIMap.erase(fruObjPath);
+ objToEntityNode.erase(fruObjPath);
+ info(
+ "Removing Individual FRU [ {FRU_OBJ_PATH} ] with entityid [ {ENTITY_TYPE}, {ENTITY_NUM}, {ENTITY_ID} ]",
+ "FRU_OBJ_PATH", fruObjPath, "ENTITY_TYPE",
+ static_cast<unsigned>(removeEntity.entity_type), "ENTITY_NUM",
+ static_cast<unsigned>(removeEntity.entity_instance_num), "ENTITY_ID",
+ static_cast<unsigned>(removeEntity.entity_container_id));
+ associatedEntityMap.erase(fruObjPath);
+
+ deleteFRURecord(rsi);
+
+ std::vector<ChangeEntry> handlesTobeDeleted;
+ if (deleteRecordHdl != 0)
+ {
+ handlesTobeDeleted.push_back(deleteRecordHdl);
+ }
+
+ std::vector<uint16_t> effecterIDs = pldm::utils::findEffecterIds(
+ pdrRepo, removeEntity.entity_type, removeEntity.entity_instance_num,
+ removeEntity.entity_container_id);
+
+ for (const auto& ids : effecterIDs)
+ {
+ uint32_t delEffecterHdl = 0;
+ int rc = pldm_pdr_delete_by_effecter_id(pdrRepo, ids, false,
+ &delEffecterHdl);
+
+ if (rc != 0)
+ {
+ error("Failed to delete PDR by effecter ID {ID}. RC = {RC}", "ID",
+ ids, "RC", rc);
+ continue;
+ }
+ effecterDbusObjMaps.erase(ids);
+ if (delEffecterHdl != 0)
+ {
+ handlesTobeDeleted.push_back(delEffecterHdl);
+ }
+ }
+ std::vector<uint16_t> sensorIDs = pldm::utils::findSensorIds(
+ pdrRepo, removeEntity.entity_type, removeEntity.entity_instance_num,
+ removeEntity.entity_container_id);
+
+ for (const auto& ids : sensorIDs)
+ {
+ uint32_t delSensorHdl = 0;
+ int rc =
+ pldm_pdr_delete_by_sensor_id(pdrRepo, ids, false, &delSensorHdl);
+
+ if (rc != 0)
+ {
+ error("Failed to delete PDR by sensor ID {ID}. RC = {RC}", "ID",
+ ids, "RC", rc);
+ continue;
+ }
+ sensorDbusObjMaps.erase(ids);
+ if (delSensorHdl != 0)
+ {
+ handlesTobeDeleted.push_back(delSensorHdl);
+ }
+ }
+
+ // need to send both remote and local records. Host keeps track of BMC
+ // only records
+ std::vector<ChangeEntry> handlesTobeModified;
+ if (removeBmcEntityRc == 0 && updateRecordHdlBmc != 0)
+ {
+ (bmcEventDataOps == PLDM_RECORDS_DELETED)
+ ? handlesTobeDeleted.push_back(updateRecordHdlBmc)
+ : handlesTobeModified.push_back(updateRecordHdlBmc);
+ }
+ if (removeHostEntityRc == 0 && updateRecordHdlHost != 0)
+ {
+ (hostEventDataOps == PLDM_RECORDS_DELETED)
+ ? handlesTobeDeleted.push_back(updateRecordHdlHost)
+ : handlesTobeModified.push_back(updateRecordHdlHost);
+ }
+ // Adapter PDRs can have deleted records
+ if (!handlesTobeDeleted.empty())
+ {
+ platformHandler->sendPDRRepositoryChgEventbyPDRHandles(
+ handlesTobeDeleted, std::vector<uint8_t>{PLDM_RECORDS_DELETED});
+ }
+ if (!handlesTobeModified.empty())
+ {
+ platformHandler->sendPDRRepositoryChgEventbyPDRHandles(
+ handlesTobeModified, std::vector<uint8_t>{PLDM_RECORDS_MODIFIED});
+ }
+}
+
std::vector<uint8_t> FruImpl::tableResize()
{
std::vector<uint8_t> tempTable;
diff --git a/libpldmresponder/fru.hpp b/libpldmresponder/fru.hpp
index 2cc9f43..8e7efdd 100644
--- a/libpldmresponder/fru.hpp
+++ b/libpldmresponder/fru.hpp
@@ -20,6 +20,10 @@
namespace responder
{
+namespace platform
+{
+class Handler; // forward declaration
+}
namespace dbus
{
@@ -33,6 +37,7 @@
using ObjectValueTree = std::map<sdbusplus::message::object_path, InterfaceMap>;
using ObjectPath = std::string;
using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>;
+using ObjectPathToRSIMap = std::map<ObjectPath, uint16_t>;
} // namespace dbus
@@ -219,6 +224,11 @@
oemFruHandler = handler;
}
+ inline void setPlatformHandler(pldm::responder::platform::Handler* handler)
+ {
+ platformHandler = handler;
+ }
+
private:
uint16_t nextRSI()
{
@@ -244,12 +254,18 @@
pldm_entity_association_tree* bmcEntityTree;
pldm::responder::oem_fru::Handler* oemFruHandler = nullptr;
dbus::ObjectValueTree objects;
+ pldm::responder::platform::Handler* platformHandler = nullptr;
/** @OEM platform handler */
pldm::responder::oem_platform::Handler* oemPlatformHandler;
std::map<dbus::ObjectPath, pldm_entity_node*> objToEntityNode{};
+ dbus::ObjectPathToRSIMap objectPathToRSIMap{};
+
+ pdr_utils::DbusObjMaps effecterDbusObjMaps{};
+ pdr_utils::DbusObjMaps sensorDbusObjMaps{};
+
/** @brief populateRecord builds the FRU records for an instance of FRU and
* updates the FRU table with the FRU records.
*
@@ -279,6 +295,13 @@
*/
void deleteFRURecord(uint16_t rsi);
+ /** @brief Deletes a FRU record set PDR and it's associated PDRs after
+ * a concurrent remove operation.
+ * @param[in] fruObjectPath - the FRU object path
+ * @return
+ */
+ void removeIndividualFRU(const std::string& fruObjPath);
+
/** @brief Associate sensor/effecter to FRU entity
*/
dbus::AssociatedEntityMap associatedEntityMap;
@@ -394,6 +417,11 @@
impl.setOemFruHandler(handler);
}
+ void setPlatformHandler(pldm::responder::platform::Handler* handler)
+ {
+ impl.setPlatformHandler(handler);
+ }
+
using Table = std::vector<uint8_t>;
private:
diff --git a/libpldmresponder/pdr_utils.hpp b/libpldmresponder/pdr_utils.hpp
index 8167ea7..80fb104 100644
--- a/libpldmresponder/pdr_utils.hpp
+++ b/libpldmresponder/pdr_utils.hpp
@@ -76,9 +76,11 @@
/** @brief Map of DBus property State to attribute value
*/
+using EffecterId = uint16_t;
using StatestoDbusVal = std::map<State, pldm::utils::PropertyValue>;
using DbusMappings = std::vector<pldm::utils::DBusMapping>;
using DbusValMaps = std::vector<StatestoDbusVal>;
+using DbusObjMaps = std::map<EffecterId, std::tuple<DbusMappings, DbusValMaps>>;
using EventStates = std::array<uint8_t, 8>;
/** @brief Parse PDR JSON file and output Json object
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index 52864e8..0aec17f 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -311,6 +311,8 @@
platformConfigHandler.get(), &reqHandler, event, true,
addOnEventHandlers);
+ fruHandler->setPlatformHandler(platformHandler.get());
+
auto biosHandler = std::make_unique<pldm::responder::bios::Handler>(
pldmTransport.getEventSource(), hostEID, &instanceIdDb, &reqHandler,
platformConfigHandler.get(), requestPLDMServiceName);