xref: /openbmc/pldm/host-bmc/utils.cpp (revision a34a64bb)
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 {
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 =
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 
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 
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