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