pdr: Add pldm_pdr_find_container_id_range_exclude() API
This API is necessary to find the container id of contained entity
which is not within the record handle ranges of the remote endpoint
PDRs.The remote endpoint has their own set of PDRs and have record
handle ranges defined.
Change-Id: If28325869d4c5c797c33bc4efd41bee16777a7aa
Signed-off-by: Pavithra Barithaya <pavithra.b@ibm.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b1b249..59fe3bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@
4. pdr: Add APIs for creating and locating remote PDRs
5. pdr: Add pldm_pdr_find_last_in_range()
6. pdr: Add pldm_entity_association_pdr_add_from_node_with_record_handle()
+7. pdr: Add pldm_pdr_find_container_id_range_exclude()
### Changed
diff --git a/include/libpldm/pdr.h b/include/libpldm/pdr.h
index c38f097..27ad6f1 100644
--- a/include/libpldm/pdr.h
+++ b/include/libpldm/pdr.h
@@ -180,6 +180,26 @@
pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
uint32_t first, uint32_t last);
+/** @brief find the container ID of the contained entity which is not in the
+ * particular range of record handles given
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] entity_type - entity type
+ * @param[in] entity_instance - instance of the entity
+ * @param[in] range_exclude_start_handle - first record handle in the range of the remote endpoint
+ * which is ignored
+ * @param[in] range_exclude_end_handle - last record handle in the range of the remote endpoint
+ * which is ignored
+ * @param[out] container_id - container id of the contained entity
+ *
+ * @return container id of the PDR record found on success, -EINVAL when repo is NULL, or -ENOKEY if
+ * the container id is not found.
+ */
+int pldm_pdr_find_container_id_range_exclude(
+ const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
+ uint32_t range_exclude_start_handle, uint32_t range_exclude_end_handle,
+ uint16_t *container_id);
+
/* ======================= */
/* FRU Record Set PDR APIs */
/* ======================= */
diff --git a/src/pdr.c b/src/pdr.c
index 0d6ce76..a78593c 100644
--- a/src/pdr.c
+++ b/src/pdr.c
@@ -365,6 +365,65 @@
} while (record);
}
+static bool pldm_record_handle_in_range(uint32_t record_handle,
+ uint32_t first_record_handle,
+ uint32_t last_record_handle)
+{
+ return record_handle >= first_record_handle &&
+ record_handle <= last_record_handle;
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_pdr_find_container_id_range_exclude(
+ const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
+ uint32_t range_exclude_start_handle, uint32_t range_exclude_end_handle,
+ uint16_t *container_id)
+{
+ pldm_pdr_record *record;
+ if (!repo) {
+ return -EINVAL;
+ }
+
+ for (record = repo->first; record; record = record->next) {
+ bool is_container_entity_instance_number;
+ struct pldm_pdr_entity_association *pdr;
+ bool is_container_entity_type;
+ struct pldm_entity *child;
+ struct pldm_pdr_hdr *hdr;
+ bool in_range;
+
+ // pldm_pdr_add() takes only uint8_t* data as an argument.
+ // The expectation here is the pldm_pdr_hdr is the first field of the record data
+ hdr = (struct pldm_pdr_hdr *)record->data;
+ if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
+ continue;
+ }
+ in_range = pldm_record_handle_in_range(
+ record->record_handle, range_exclude_start_handle,
+ range_exclude_end_handle);
+ if (in_range) {
+ continue;
+ }
+
+ // this cast is valid with respect to alignment because
+ // struct pldm_pdr_hdr is declared with __attribute__((packed))
+ pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
+ if (pdr->num_children == 0) {
+ continue;
+ }
+ child = (&pdr->children[0]);
+ is_container_entity_type = pdr->container.entity_type ==
+ entity_type;
+ is_container_entity_instance_number =
+ pdr->container.entity_instance_num == entity_instance;
+ if (is_container_entity_type &&
+ is_container_entity_instance_number) {
+ *container_id = le16toh(child->entity_container_id);
+ }
+ }
+ return -ENOKEY;
+}
+
typedef struct pldm_entity_association_tree {
pldm_entity_node *root;
uint16_t last_used_container_id;
diff --git a/tests/libpldm_pdr_test.cpp b/tests/libpldm_pdr_test.cpp
index f29fb97..48e8dfa 100644
--- a/tests/libpldm_pdr_test.cpp
+++ b/tests/libpldm_pdr_test.cpp
@@ -1641,3 +1641,49 @@
pldm_pdr_destroy(repo);
pldm_entity_association_tree_destroy(tree);
}
+
+TEST(EntityAssociationPDR, testFindContainerID)
+{
+ pldm_entity entities[3]{};
+ entities[0].entity_type = 1;
+ entities[1].entity_type = 2;
+ entities[2].entity_type = 3;
+ entities[1].entity_container_id = 2;
+ entities[1].entity_instance_num = 1;
+
+ auto tree = pldm_entity_association_tree_init();
+ auto l1 = pldm_entity_association_tree_add_entity(
+ tree, &entities[0], 0xFFFF, nullptr, PLDM_ENTITY_ASSOCIAION_LOGICAL,
+ false, true, 0xFFFF);
+
+ EXPECT_NE(l1, nullptr);
+ auto l2 = pldm_entity_association_tree_add_entity(
+ tree, &entities[1], 0xFFFF, l1, PLDM_ENTITY_ASSOCIAION_PHYSICAL, false,
+ false, 0xFFFF);
+ EXPECT_NE(l2, nullptr);
+ auto l3 = pldm_entity_association_tree_add_entity(
+ tree, &entities[2], 0xFFFF, l1, PLDM_ENTITY_ASSOCIAION_PHYSICAL, false,
+ true, 0xFFFF);
+ EXPECT_NE(l3, nullptr);
+
+ EXPECT_EQ(pldm_entity_get_num_children(l1, PLDM_ENTITY_ASSOCIAION_PHYSICAL),
+ 2);
+
+ auto repo = pldm_pdr_init();
+ pldm_entity_association_pdr_add(tree, repo, false, 1);
+
+ EXPECT_EQ(pldm_pdr_get_record_count(repo), 1u);
+
+ uint16_t container_id{};
+ pldm_pdr_find_container_id_range_exclude(repo, 1, 1, 0x01000000, 0x01FFFFFF,
+ &container_id);
+ EXPECT_EQ(container_id, 2);
+
+ uint16_t container_id1{};
+ pldm_pdr_find_container_id_range_exclude(repo, 1, 1, 0x00000001, 0x00FFFFFF,
+ &container_id1);
+ EXPECT_EQ(container_id1, 0);
+
+ pldm_pdr_destroy(repo);
+ pldm_entity_association_tree_destroy(tree);
+}