1 #include "utils.hpp"
2
3 #include <libpldm/entity.h>
4
5 #include <cstdlib>
6 #include <iostream>
7
8 using namespace pldm::utils;
9
10 namespace pldm
11 {
12 namespace hostbmc
13 {
14 namespace utils
15 {
getParentEntites(const EntityAssociations & entityAssoc)16 Entities getParentEntites(const EntityAssociations& entityAssoc)
17 {
18 Entities parents{};
19 for (const auto& et : entityAssoc)
20 {
21 parents.push_back(et[0]);
22 }
23
24 bool found = false;
25 for (auto it = parents.begin(); it != parents.end();
26 it = found ? parents.erase(it) : std::next(it))
27 {
28 uint16_t parent_contained_id =
29 pldm_entity_node_get_remote_container_id(*it);
30 found = false;
31 for (const auto& evs : entityAssoc)
32 {
33 for (size_t i = 1; i < evs.size() && !found; i++)
34 {
35 uint16_t node_contained_id =
36 pldm_entity_node_get_remote_container_id(evs[i]);
37
38 pldm_entity parent_entity = pldm_entity_extract(*it);
39 pldm_entity node_entity = pldm_entity_extract(evs[i]);
40
41 if (node_entity.entity_type == parent_entity.entity_type &&
42 node_entity.entity_instance_num ==
43 parent_entity.entity_instance_num &&
44 node_contained_id == parent_contained_id)
45 {
46 found = true;
47 }
48 }
49 if (found)
50 {
51 break;
52 }
53 }
54 }
55
56 return parents;
57 }
58
addObjectPathEntityAssociations(const EntityAssociations & entityAssoc,pldm_entity_node * entity,const fs::path & path,ObjectPathMaps & objPathMap,EntityMaps entityMaps,pldm::responder::oem_platform::Handler * oemPlatformHandler)59 void addObjectPathEntityAssociations(
60 const EntityAssociations& entityAssoc, pldm_entity_node* entity,
61 const fs::path& path, ObjectPathMaps& objPathMap, EntityMaps entityMaps,
62 pldm::responder::oem_platform::Handler* oemPlatformHandler)
63 {
64 if (entity == nullptr)
65 {
66 return;
67 }
68
69 bool found = false;
70 pldm_entity node_entity = pldm_entity_extract(entity);
71 if (!entityMaps.contains(node_entity.entity_type))
72 {
73 // entityMaps doesn't contain entity type which are not required to
74 // build entity object path, so returning from here because this is a
75 // expected behaviour
76 return;
77 }
78
79 std::string entityName = entityMaps.at(node_entity.entity_type);
80 for (const auto& ev : entityAssoc)
81 {
82 pldm_entity ev_entity = pldm_entity_extract(ev[0]);
83 if (ev_entity.entity_instance_num == node_entity.entity_instance_num &&
84 ev_entity.entity_type == node_entity.entity_type)
85 {
86 uint16_t node_contained_id =
87 pldm_entity_node_get_remote_container_id(ev[0]);
88 uint16_t entity_contained_id =
89 pldm_entity_node_get_remote_container_id(entity);
90
91 if (node_contained_id != entity_contained_id)
92 {
93 continue;
94 }
95
96 fs::path p =
97 path /
98 fs::path{entityName +
99 std::to_string(node_entity.entity_instance_num)};
100 std::string entity_path = p.string();
101 if (oemPlatformHandler)
102 {
103 oemPlatformHandler->updateOemDbusPaths(entity_path);
104 }
105 try
106 {
107 pldm::utils::DBusHandler().getService(entity_path.c_str(),
108 nullptr);
109 // If the entity obtained from the remote PLDM terminal is not
110 // in the MAP, or there is no auxiliary name PDR, add it
111 // directly. Otherwise, check whether the DBus service of
112 // entity_path exists, and overwrite the entity if it does not
113 // exist.
114 if (objPathMap.contains(entity_path))
115 {
116 objPathMap[entity_path] = entity;
117 }
118 }
119 catch (const std::exception&)
120 {
121 objPathMap[entity_path] = entity;
122 }
123
124 for (size_t i = 1; i < ev.size(); i++)
125 {
126 addObjectPathEntityAssociations(entityAssoc, ev[i], p,
127 objPathMap, entityMaps,
128 oemPlatformHandler);
129 }
130 found = true;
131 }
132 }
133
134 if (!found)
135 {
136 std::string dbusPath =
137 path / fs::path{entityName +
138 std::to_string(node_entity.entity_instance_num)};
139 if (oemPlatformHandler)
140 {
141 oemPlatformHandler->updateOemDbusPaths(dbusPath);
142 }
143 try
144 {
145 pldm::utils::DBusHandler().getService(dbusPath.c_str(), nullptr);
146 if (objPathMap.contains(dbusPath))
147 {
148 objPathMap[dbusPath] = entity;
149 }
150 }
151 catch (const std::exception&)
152 {
153 objPathMap[dbusPath] = entity;
154 }
155 }
156 }
157
updateEntityAssociation(const EntityAssociations & entityAssoc,pldm_entity_association_tree * entityTree,ObjectPathMaps & objPathMap,EntityMaps entityMaps,pldm::responder::oem_platform::Handler * oemPlatformHandler)158 void updateEntityAssociation(
159 const EntityAssociations& entityAssoc,
160 pldm_entity_association_tree* entityTree, ObjectPathMaps& objPathMap,
161 EntityMaps entityMaps,
162 pldm::responder::oem_platform::Handler* oemPlatformHandler)
163 {
164 std::vector<pldm_entity_node*> parentsEntity =
165 getParentEntites(entityAssoc);
166 for (const auto& entity : parentsEntity)
167 {
168 fs::path path{"/xyz/openbmc_project/inventory"};
169 std::deque<std::string> paths{};
170 pldm_entity node_entity = pldm_entity_extract(entity);
171 auto node = pldm_entity_association_tree_find_with_locality(
172 entityTree, &node_entity, false);
173 if (!node)
174 {
175 continue;
176 }
177
178 bool found = true;
179 while (node)
180 {
181 if (!pldm_entity_is_exist_parent(node))
182 {
183 break;
184 }
185
186 pldm_entity parent = pldm_entity_get_parent(node);
187 try
188 {
189 paths.push_back(entityMaps.at(parent.entity_type) +
190 std::to_string(parent.entity_instance_num));
191 }
192 catch (const std::exception& e)
193 {
194 lg2::error(
195 "Parent entity not found in the entityMaps, type: {ENTITY_TYPE}, num: {NUM}, e: {ERROR}",
196 "ENTITY_TYPE", (int)parent.entity_type, "NUM",
197 (int)parent.entity_instance_num, "ERROR", e);
198 found = false;
199 break;
200 }
201
202 node = pldm_entity_association_tree_find_with_locality(
203 entityTree, &parent, false);
204 }
205
206 if (!found)
207 {
208 continue;
209 }
210
211 while (!paths.empty())
212 {
213 path = path / fs::path{paths.back()};
214 paths.pop_back();
215 }
216
217 addObjectPathEntityAssociations(entityAssoc, entity, path, objPathMap,
218 entityMaps, oemPlatformHandler);
219 }
220 }
221
parseEntityMap(const fs::path & filePath)222 EntityMaps parseEntityMap(const fs::path& filePath)
223 {
224 const Json emptyJson{};
225 EntityMaps entityMaps{};
226 std::ifstream jsonFile(filePath);
227 auto data = Json::parse(jsonFile);
228 if (data.is_discarded())
229 {
230 error("Failed parsing of EntityMap data from json file: '{JSON_PATH}'",
231 "JSON_PATH", filePath);
232 return entityMaps;
233 }
234 auto entities = data.value("EntityTypeToDbusStringMap", emptyJson);
235 char* err;
236 try
237 {
238 std::ranges::transform(
239 entities.items(), std::inserter(entityMaps, entityMaps.begin()),
240 [&err](const auto& element) {
241 std::string key = static_cast<EntityName>(element.key());
242 return std::make_pair(strtol(key.c_str(), &err, 10),
243 static_cast<EntityName>(element.value()));
244 });
245 }
246 catch (const std::exception& e)
247 {
248 error(
249 "Failed to create entity to DBus string mapping {ERROR} and Conversion failure is '{ERR}'",
250 "ERROR", e, "ERR", err);
251 }
252
253 return entityMaps;
254 }
255
256 } // namespace utils
257 } // namespace hostbmc
258 } // namespace pldm
259