xref: /openbmc/pldm/host-bmc/utils.cpp (revision 9e4aedb7)
1 #include "common/utils.hpp"
2 
3 #include "libpldm/entity.h"
4 
5 #include "utils.hpp"
6 
7 #include <cstdlib>
8 #include <iostream>
9 
10 namespace pldm
11 {
12 namespace hostbmc
13 {
14 namespace utils
15 {
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 
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 = path / fs::path{entityName +
97                                          std::to_string(
98                                              node_entity.entity_instance_num)};
99             std::string entity_path = p.string();
100             if (oemPlatformHandler)
101             {
102                 oemPlatformHandler->updateOemDbusPaths(entity_path);
103             }
104             // If the entity obtained from the remote PLDM terminal is not in
105             // the MAP, or there is no auxiliary name PDR, add it directly.
106             // Otherwise, check whether the DBus service of entity_path exists,
107             // and overwrite the entity if it does not exist.
108             if (!objPathMap.contains(entity_path))
109             {
110                 objPathMap[entity_path] = entity;
111             }
112             else
113             {
114                 try
115                 {
116                     pldm::utils::DBusHandler().getService(entity_path.c_str(),
117                                                           nullptr);
118                 }
119                 catch (const std::exception& e)
120                 {
121                     objPathMap[entity_path] = entity;
122                 }
123             }
124 
125             for (size_t i = 1; i < ev.size(); i++)
126             {
127                 addObjectPathEntityAssociations(entityAssoc, ev[i], p,
128                                                 objPathMap, entityMaps,
129                                                 oemPlatformHandler);
130             }
131             found = true;
132         }
133     }
134 
135     if (!found)
136     {
137         std::string dbusPath =
138             path / fs::path{entityName +
139                             std::to_string(node_entity.entity_instance_num)};
140         if (oemPlatformHandler)
141         {
142             oemPlatformHandler->updateOemDbusPaths(dbusPath);
143         }
144         try
145         {
146             pldm::utils::DBusHandler().getService(dbusPath.c_str(), nullptr);
147         }
148         catch (const std::exception& e)
149         {
150             objPathMap[dbusPath] = entity;
151         }
152     }
153 }
154 
155 void updateEntityAssociation(
156     const EntityAssociations& entityAssoc,
157     pldm_entity_association_tree* entityTree, ObjectPathMaps& objPathMap,
158     EntityMaps entityMaps,
159     pldm::responder::oem_platform::Handler* oemPlatformHandler)
160 {
161     std::vector<pldm_entity_node*> parentsEntity =
162         getParentEntites(entityAssoc);
163     for (const auto& entity : parentsEntity)
164     {
165         fs::path path{"/xyz/openbmc_project/inventory"};
166         std::deque<std::string> paths{};
167         pldm_entity node_entity = pldm_entity_extract(entity);
168         auto node = pldm_entity_association_tree_find_with_locality(
169             entityTree, &node_entity, false);
170         if (!node)
171         {
172             continue;
173         }
174 
175         bool found = true;
176         while (node)
177         {
178             if (!pldm_entity_is_exist_parent(node))
179             {
180                 break;
181             }
182 
183             pldm_entity parent = pldm_entity_get_parent(node);
184             try
185             {
186                 paths.push_back(entityMaps.at(parent.entity_type) +
187                                 std::to_string(parent.entity_instance_num));
188             }
189             catch (const std::exception& e)
190             {
191                 lg2::error(
192                     "Parent entity not found in the entityMaps, type: {ENTITY_TYPE}, num: {NUM}, e: {ERROR}",
193                     "ENTITY_TYPE", (int)parent.entity_type, "NUM",
194                     (int)parent.entity_instance_num, "ERROR", e);
195                 found = false;
196                 break;
197             }
198 
199             node = pldm_entity_association_tree_find_with_locality(
200                 entityTree, &parent, false);
201         }
202 
203         if (!found)
204         {
205             continue;
206         }
207 
208         while (!paths.empty())
209         {
210             path = path / fs::path{paths.back()};
211             paths.pop_back();
212         }
213 
214         addObjectPathEntityAssociations(entityAssoc, entity, path, objPathMap,
215                                         entityMaps, oemPlatformHandler);
216     }
217 }
218 
219 EntityMaps parseEntityMap(const fs::path& filePath)
220 {
221     const Json emptyJson{};
222     EntityMaps entityMaps{};
223     std::ifstream jsonFile(filePath);
224     auto data = Json::parse(jsonFile);
225     if (data.is_discarded())
226     {
227         error("Failed parsing of EntityMap data from json file: '{JSON_PATH}'",
228               "JSON_PATH", filePath);
229         return entityMaps;
230     }
231     auto entities = data.value("EntityTypeToDbusStringMap", emptyJson);
232     char* err;
233     try
234     {
235         std::ranges::transform(entities.items(),
236                                std::inserter(entityMaps, entityMaps.begin()),
237                                [&err](const auto& element) {
238             std::string key = static_cast<EntityName>(element.key());
239             return std::make_pair(strtol(key.c_str(), &err, 10),
240                                   static_cast<EntityName>(element.value()));
241         });
242     }
243     catch (const std::exception& e)
244     {
245         error(
246             "Failed to create entity to DBus string mapping {ERROR} and Conversion failure is '{ERR}'",
247             "ERROR", e, "ERR", err);
248     }
249 
250     return entityMaps;
251 }
252 
253 } // namespace utils
254 } // namespace hostbmc
255 } // namespace pldm
256