blob: 14eebb40f8d5b68d26e80787fcf0b107539796cd [file] [log] [blame]
Willy Tude54f482021-01-26 15:59:09 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "dbus-sdr/sdrutils.hpp"
18
George Liuc1c7eac2024-02-04 17:24:19 +080019#include <ipmid/utils.hpp>
Johnathan Mantey04b0b072023-10-10 12:30:35 -070020#include <nlohmann/json.hpp>
George Liude6694e2024-07-17 15:22:25 +080021#include <phosphor-logging/lg2.hpp>
Johnathan Mantey04b0b072023-10-10 12:30:35 -070022
23#include <fstream>
Willy Tu4eca2512022-06-20 21:14:51 -070024#include <optional>
25#include <unordered_set>
26
Scron Chang2703b022021-07-06 15:47:45 +080027#ifdef FEATURE_HYBRID_SENSORS
28
29#include <ipmid/utils.hpp>
30namespace ipmi
31{
32namespace sensor
33{
34extern const IdInfoMap sensors;
35} // namespace sensor
36} // namespace ipmi
37
38#endif
39
Johnathan Mantey34d19732024-07-17 07:59:54 -070040boost::container::flat_map<
41 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
42 sensorTypes{
43 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
44 SensorEventTypeCodes::threshold)},
45 {"voltage", std::make_pair(SensorTypeCodes::voltage,
46 SensorEventTypeCodes::threshold)},
47 {"current", std::make_pair(SensorTypeCodes::current,
48 SensorEventTypeCodes::threshold)},
49 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
50 SensorEventTypeCodes::threshold)},
51 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
52 SensorEventTypeCodes::threshold)},
53 {"intrusion", std::make_pair(SensorTypeCodes::physical_security,
54 SensorEventTypeCodes::sensorSpecified)},
55 {"processor", std::make_pair(SensorTypeCodes::processor,
56 SensorEventTypeCodes::sensorSpecified)},
57 {"power", std::make_pair(SensorTypeCodes::other,
58 SensorEventTypeCodes::threshold)},
59 {"memory", std::make_pair(SensorTypeCodes::memory,
60 SensorEventTypeCodes::sensorSpecified)},
61 {"state", std::make_pair(SensorTypeCodes::power_unit,
62 SensorEventTypeCodes::sensorSpecified)},
63 {"buttons", std::make_pair(SensorTypeCodes::buttons,
64 SensorEventTypeCodes::sensorSpecified)},
65 {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
66 SensorEventTypeCodes::sensorSpecified)},
67 {"entity", std::make_pair(SensorTypeCodes::entity,
68 SensorEventTypeCodes::sensorSpecified)},
69 {"energy", std::make_pair(SensorTypeCodes::other,
70 SensorEventTypeCodes::threshold)}}};
71
Willy Tude54f482021-01-26 15:59:09 -080072namespace details
73{
Johnathan Mantey04b0b072023-10-10 12:30:35 -070074
75// IPMI supports a smaller number of sensors than are available via Redfish.
76// Trim the list of sensors, via a configuration file.
77// Read the IPMI Sensor Filtering section in docs/configuration.md for
78// a more detailed description.
79static void filterSensors(SensorSubTree& subtree)
80{
81 constexpr const char* filterFilename =
82 "/usr/share/ipmi-providers/sensor_filter.json";
83 std::ifstream filterFile(filterFilename);
84 if (!filterFile.good())
85 {
86 return;
87 }
88 nlohmann::json sensorFilterJSON = nlohmann::json::parse(filterFile, nullptr,
89 false);
90 nlohmann::json::iterator svcFilterit =
91 sensorFilterJSON.find("ServiceFilter");
92 if (svcFilterit == sensorFilterJSON.end())
93 {
94 return;
95 }
96
97 subtree.erase(std::remove_if(subtree.begin(), subtree.end(),
98 [svcFilterit](SensorSubTree::value_type& kv) {
99 auto& [_, serviceToIfaces] = kv;
100
101 for (auto service = svcFilterit->begin(); service != svcFilterit->end();
102 ++service)
103 {
104 serviceToIfaces.erase(*service);
105 }
106 return serviceToIfaces.empty();
107 }),
108 subtree.end());
109}
110
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800111uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
Willy Tude54f482021-01-26 15:59:09 -0800112{
113 static std::shared_ptr<SensorSubTree> sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800114 static uint16_t sensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -0800115 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams5d82f472022-07-22 19:26:53 -0500116 static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800117 *dbus,
118 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
119 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500120 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -0800121
Patrick Williams5d82f472022-07-22 19:26:53 -0500122 static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800123 *dbus,
124 "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
125 "openbmc_project/sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500126 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -0800127
Willy Tude54f482021-01-26 15:59:09 -0800128 if (sensorTreePtr)
129 {
130 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800131 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800132 }
133
134 sensorTreePtr = std::make_shared<SensorSubTree>();
135
Willy Tude54f482021-01-26 15:59:09 -0800136 static constexpr const int32_t depth = 2;
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800137
Patrick Williams369824e2023-10-20 11:18:23 -0500138 auto lbdUpdateSensorTree = [&dbus](const char* path,
139 const auto& interfaces) {
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800140 auto mapperCall = dbus->new_method_call(
141 "xyz.openbmc_project.ObjectMapper",
142 "/xyz/openbmc_project/object_mapper",
143 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
144 SensorSubTree sensorTreePartial;
145
146 mapperCall.append(path, depth, interfaces);
147
148 try
149 {
150 auto mapperReply = dbus->call(mapperCall);
151 mapperReply.read(sensorTreePartial);
152 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500153 catch (const sdbusplus::exception_t& e)
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800154 {
George Liude6694e2024-07-17 15:22:25 +0800155 lg2::error("Failed to update subtree, path: {PATH}, error: {ERROR}",
156 "PATH", path, "ERROR", e);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800157 return false;
158 }
159 if constexpr (debug)
160 {
161 std::fprintf(stderr, "IPMI updated: %zu sensors under %s\n",
162 sensorTreePartial.size(), path);
163 }
164 sensorTreePtr->merge(std::move(sensorTreePartial));
165 return true;
166 };
167
168 // Add sensors to SensorTree
169 static constexpr const std::array sensorInterfaces = {
Willy Tude54f482021-01-26 15:59:09 -0800170 "xyz.openbmc_project.Sensor.Value",
Jie Yangf0a89942021-07-29 15:30:25 -0700171 "xyz.openbmc_project.Sensor.ValueMutability",
Willy Tude54f482021-01-26 15:59:09 -0800172 "xyz.openbmc_project.Sensor.Threshold.Warning",
173 "xyz.openbmc_project.Sensor.Threshold.Critical"};
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800174 static constexpr const std::array vrInterfaces = {
175 "xyz.openbmc_project.Control.VoltageRegulatorMode"};
Willy Tude54f482021-01-26 15:59:09 -0800176
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500177 bool sensorRez = lbdUpdateSensorTree("/xyz/openbmc_project/sensors",
178 sensorInterfaces);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800179
Scron Chang2703b022021-07-06 15:47:45 +0800180#ifdef FEATURE_HYBRID_SENSORS
181
182 if (!ipmi::sensor::sensors.empty())
183 {
184 for (const auto& sensor : ipmi::sensor::sensors)
185 {
186 // Threshold sensors should not be emplaced in here.
187 if (boost::starts_with(sensor.second.sensorPath,
188 "/xyz/openbmc_project/sensors/"))
189 {
190 continue;
191 }
192
193 // The bus service name is not listed in ipmi::sensor::Info. Give it
194 // an empty string. For those function using non-threshold sensors,
195 // the bus service name will be retrieved in an alternative way.
196 boost::container::flat_map<std::string, std::vector<std::string>>
197 connectionMap{
198 {"", {sensor.second.propertyInterfaces.begin()->first}}};
199 sensorTreePtr->emplace(sensor.second.sensorPath, connectionMap);
200 }
201 }
202
203#endif
204
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800205 // Error if searching for sensors failed.
206 if (!sensorRez)
Willy Tude54f482021-01-26 15:59:09 -0800207 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800208 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800209 }
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800210
Johnathan Mantey04b0b072023-10-10 12:30:35 -0700211 filterSensors(*sensorTreePtr);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800212 // Add VR control as optional search path.
213 (void)lbdUpdateSensorTree("/xyz/openbmc_project/vr", vrInterfaces);
214
Willy Tude54f482021-01-26 15:59:09 -0800215 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800216 sensorUpdatedIndex++;
Josh Lehana55c9532020-10-28 21:59:06 -0700217 // The SDR is being regenerated, wipe the old stats
218 sdrStatsTable.wipeTable();
Jie Yangf0a89942021-07-29 15:30:25 -0700219 sdrWriteTable.wipeTable();
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800220 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800221}
222
223bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
224{
225 static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
226 bool sensorNumMapUpated = false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800227 static uint16_t prevSensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -0800228 std::shared_ptr<SensorSubTree> sensorTree;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800229 uint16_t curSensorUpdatedIndex = details::getSensorSubtree(sensorTree);
Willy Tude54f482021-01-26 15:59:09 -0800230 if (!sensorTree)
231 {
232 return sensorNumMapUpated;
233 }
234
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800235 if ((curSensorUpdatedIndex == prevSensorUpdatedIndex) && sensorNumMapPtr)
Willy Tude54f482021-01-26 15:59:09 -0800236 {
237 sensorNumMap = sensorNumMapPtr;
238 return sensorNumMapUpated;
239 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800240 prevSensorUpdatedIndex = curSensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800241
242 sensorNumMapPtr = std::make_shared<SensorNumMap>();
243
244 uint16_t sensorNum = 0;
245 uint16_t sensorIndex = 0;
246 for (const auto& sensor : *sensorTree)
247 {
248 sensorNumMapPtr->insert(
249 SensorNumMap::value_type(sensorNum, sensor.first));
250 sensorIndex++;
251 if (sensorIndex == maxSensorsPerLUN)
252 {
253 sensorIndex = lun1Sensor0;
254 }
255 else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN))
256 {
257 // Skip assigning LUN 0x2 any sensors
258 sensorIndex = lun3Sensor0;
259 }
260 else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN))
261 {
262 // this is an error, too many IPMI sensors
263 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
264 }
265 sensorNum = sensorIndex;
266 }
267 sensorNumMap = sensorNumMapPtr;
268 sensorNumMapUpated = true;
269 return sensorNumMapUpated;
270}
271} // namespace details
272
273bool getSensorSubtree(SensorSubTree& subtree)
274{
275 std::shared_ptr<SensorSubTree> sensorTree;
276 details::getSensorSubtree(sensorTree);
277 if (!sensorTree)
278 {
279 return false;
280 }
281
282 subtree = *sensorTree;
283 return true;
284}
285
Scron Chang2703b022021-07-06 15:47:45 +0800286#ifdef FEATURE_HYBRID_SENSORS
287// Static sensors are listed in sensor-gen.cpp.
288ipmi::sensor::IdInfoMap::const_iterator
289 findStaticSensor(const std::string& path)
290{
291 return std::find_if(
292 ipmi::sensor::sensors.begin(), ipmi::sensor::sensors.end(),
293 [&path](const ipmi::sensor::IdInfoMap::value_type& findSensor) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500294 return findSensor.second.sensorPath == path;
Patrick Williams369824e2023-10-20 11:18:23 -0500295 });
Scron Chang2703b022021-07-06 15:47:45 +0800296}
297#endif
298
Willy Tude54f482021-01-26 15:59:09 -0800299std::string getSensorTypeStringFromPath(const std::string& path)
300{
301 // get sensor type string from path, path is defined as
302 // /xyz/openbmc_project/sensors/<type>/label
303 size_t typeEnd = path.rfind("/");
304 if (typeEnd == std::string::npos)
305 {
306 return path;
307 }
308 size_t typeStart = path.rfind("/", typeEnd - 1);
309 if (typeStart == std::string::npos)
310 {
311 return path;
312 }
313 // Start at the character after the '/'
314 typeStart++;
315 return path.substr(typeStart, typeEnd - typeStart);
316}
317
318uint8_t getSensorTypeFromPath(const std::string& path)
319{
320 uint8_t sensorType = 0;
321 std::string type = getSensorTypeStringFromPath(path);
322 auto findSensor = sensorTypes.find(type.c_str());
323 if (findSensor != sensorTypes.end())
324 {
Scron Chang2b42d7e2021-07-06 15:45:47 +0800325 sensorType =
326 static_cast<uint8_t>(std::get<sensorTypeCodes>(findSensor->second));
Willy Tude54f482021-01-26 15:59:09 -0800327 } // else default 0x0 RESERVED
328
329 return sensorType;
330}
331
332uint16_t getSensorNumberFromPath(const std::string& path)
333{
334 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
335 details::getSensorNumMap(sensorNumMapPtr);
336 if (!sensorNumMapPtr)
337 {
338 return invalidSensorNumber;
339 }
340
341 try
342 {
343 return sensorNumMapPtr->right.at(path);
344 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500345 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800346 {
Willy Tude54f482021-01-26 15:59:09 -0800347 return invalidSensorNumber;
348 }
349}
350
351uint8_t getSensorEventTypeFromPath(const std::string& path)
352{
Scron Chang2b42d7e2021-07-06 15:45:47 +0800353 uint8_t sensorEventType = 0;
354 std::string type = getSensorTypeStringFromPath(path);
355 auto findSensor = sensorTypes.find(type.c_str());
356 if (findSensor != sensorTypes.end())
357 {
358 sensorEventType = static_cast<uint8_t>(
359 std::get<sensorEventTypeCodes>(findSensor->second));
360 }
361
362 return sensorEventType;
Willy Tude54f482021-01-26 15:59:09 -0800363}
364
365std::string getPathFromSensorNumber(uint16_t sensorNum)
366{
367 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
368 details::getSensorNumMap(sensorNumMapPtr);
369 if (!sensorNumMapPtr)
370 {
371 return std::string();
372 }
373
374 try
375 {
376 return sensorNumMapPtr->left.at(sensorNum);
377 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500378 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800379 {
Willy Tude54f482021-01-26 15:59:09 -0800380 return std::string();
381 }
382}
383
384namespace ipmi
385{
386
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100387std::optional<std::map<std::string, std::vector<std::string>>>
Willy Tude54f482021-01-26 15:59:09 -0800388 getObjectInterfaces(const char* path)
389{
390 std::map<std::string, std::vector<std::string>> interfacesResponse;
391 std::vector<std::string> interfaces;
392 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
393
Patrick Williams5d82f472022-07-22 19:26:53 -0500394 sdbusplus::message_t getObjectMessage =
Willy Tude54f482021-01-26 15:59:09 -0800395 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
396 "/xyz/openbmc_project/object_mapper",
397 "xyz.openbmc_project.ObjectMapper", "GetObject");
398 getObjectMessage.append(path, interfaces);
399
400 try
401 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500402 sdbusplus::message_t response = dbus->call(getObjectMessage);
Willy Tude54f482021-01-26 15:59:09 -0800403 response.read(interfacesResponse);
404 }
405 catch (const std::exception& e)
406 {
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100407 return std::nullopt;
Willy Tude54f482021-01-26 15:59:09 -0800408 }
409
410 return interfacesResponse;
411}
412
413std::map<std::string, Value> getEntityManagerProperties(const char* path,
414 const char* interface)
415{
416 std::map<std::string, Value> properties;
417 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
418
Patrick Williams5d82f472022-07-22 19:26:53 -0500419 sdbusplus::message_t getProperties =
Willy Tude54f482021-01-26 15:59:09 -0800420 dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
421 "org.freedesktop.DBus.Properties", "GetAll");
422 getProperties.append(interface);
423
424 try
425 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500426 sdbusplus::message_t response = dbus->call(getProperties);
Willy Tude54f482021-01-26 15:59:09 -0800427 response.read(properties);
428 }
429 catch (const std::exception& e)
430 {
George Liude6694e2024-07-17 15:22:25 +0800431 lg2::error("Failed to GetAll, path: {PATH}, interface: {INTERFACE}, "
432 "error: {ERROR}",
433 "PATH", path, "INTERFACE", interface, "ERROR", e);
Willy Tude54f482021-01-26 15:59:09 -0800434 }
435
436 return properties;
437}
438
Willy Tu4eca2512022-06-20 21:14:51 -0700439// Fetch the ipmiDecoratorPaths to get the list of dbus objects that
440// have ipmi decorator to prevent unnessary dbus call to fetch the info
441std::optional<std::unordered_set<std::string>>&
442 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx)
443{
444 static std::optional<std::unordered_set<std::string>> ipmiDecoratorPaths;
445
446 if (!ctx.has_value() || ipmiDecoratorPaths != std::nullopt)
447 {
448 return ipmiDecoratorPaths;
449 }
450
451 boost::system::error_code ec;
452 std::vector<std::string> paths =
453 (*ctx)->bus->yield_method_call<std::vector<std::string>>(
454 (*ctx)->yield, ec, "xyz.openbmc_project.ObjectMapper",
455 "/xyz/openbmc_project/object_mapper",
456 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
457 int32_t(0),
458 std::array<const char*, 1>{
459 "xyz.openbmc_project.Inventory.Decorator.Ipmi"});
460 if (ec)
461 {
462 return ipmiDecoratorPaths;
463 }
464
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500465 ipmiDecoratorPaths = std::unordered_set<std::string>(paths.begin(),
466 paths.end());
Willy Tu4eca2512022-06-20 21:14:51 -0700467 return ipmiDecoratorPaths;
468}
469
Willy Tude54f482021-01-26 15:59:09 -0800470const std::string* getSensorConfigurationInterface(
471 const std::map<std::string, std::vector<std::string>>&
472 sensorInterfacesResponse)
473{
474 auto entityManagerService =
475 sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
476 if (entityManagerService == sensorInterfacesResponse.end())
477 {
478 return nullptr;
479 }
480
481 // Find the fan configuration first (fans can have multiple configuration
482 // interfaces).
483 for (const auto& entry : entityManagerService->second)
484 {
485 if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
486 entry == "xyz.openbmc_project.Configuration.I2CFan" ||
487 entry == "xyz.openbmc_project.Configuration.NuvotonFan")
488 {
489 return &entry;
490 }
491 }
492
493 for (const auto& entry : entityManagerService->second)
494 {
495 if (boost::algorithm::starts_with(entry,
496 "xyz.openbmc_project.Configuration."))
497 {
498 return &entry;
499 }
500 }
501
502 return nullptr;
503}
504
505// Follow Association properties for Sensor back to the Board dbus object to
506// check for an EntityId and EntityInstance property.
Willy Tu4eca2512022-06-20 21:14:51 -0700507void updateIpmiFromAssociation(
508 const std::string& path,
509 const std::unordered_set<std::string>& ipmiDecoratorPaths,
510 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
511 uint8_t& entityInstance)
Willy Tude54f482021-01-26 15:59:09 -0800512{
513 namespace fs = std::filesystem;
514
515 auto sensorAssociationObject =
516 sensorMap.find("xyz.openbmc_project.Association.Definitions");
517 if (sensorAssociationObject == sensorMap.end())
518 {
519 if constexpr (debug)
520 {
521 std::fprintf(stderr, "path=%s, no association interface found\n",
522 path.c_str());
523 }
524
525 return;
526 }
527
528 auto associationObject =
529 sensorAssociationObject->second.find("Associations");
530 if (associationObject == sensorAssociationObject->second.end())
531 {
532 if constexpr (debug)
533 {
534 std::fprintf(stderr, "path=%s, no association records found\n",
535 path.c_str());
536 }
537
538 return;
539 }
540
541 std::vector<Association> associationValues =
542 std::get<std::vector<Association>>(associationObject->second);
543
544 // loop through the Associations looking for the right one:
545 for (const auto& entry : associationValues)
546 {
547 // forward, reverse, endpoint
548 const std::string& forward = std::get<0>(entry);
549 const std::string& reverse = std::get<1>(entry);
550 const std::string& endpoint = std::get<2>(entry);
551
552 // We only currently concern ourselves with chassis+all_sensors.
553 if (!(forward == "chassis" && reverse == "all_sensors"))
554 {
555 continue;
556 }
557
558 // the endpoint is the board entry provided by
559 // Entity-Manager. so let's grab its properties if it has
560 // the right interface.
561
562 // just try grabbing the properties first.
Willy Tu4eca2512022-06-20 21:14:51 -0700563 ipmi::PropertyMap::iterator entityIdProp;
564 ipmi::PropertyMap::iterator entityInstanceProp;
565 if (ipmiDecoratorPaths.contains(endpoint))
566 {
567 std::map<std::string, Value> ipmiProperties =
568 getEntityManagerProperties(
569 endpoint.c_str(),
570 "xyz.openbmc_project.Inventory.Decorator.Ipmi");
Willy Tude54f482021-01-26 15:59:09 -0800571
Willy Tu4eca2512022-06-20 21:14:51 -0700572 entityIdProp = ipmiProperties.find("EntityId");
573 entityInstanceProp = ipmiProperties.find("EntityInstance");
574 if (entityIdProp != ipmiProperties.end())
575 {
576 entityId = static_cast<uint8_t>(
577 std::get<uint64_t>(entityIdProp->second));
578 }
579 if (entityInstanceProp != ipmiProperties.end())
580 {
581 entityInstance = static_cast<uint8_t>(
582 std::get<uint64_t>(entityInstanceProp->second));
583 }
Willy Tude54f482021-01-26 15:59:09 -0800584 }
585
586 // Now check the entity-manager entry for this sensor to see
587 // if it has its own value and use that instead.
588 //
589 // In theory, checking this first saves us from checking
590 // both, except in most use-cases identified, there won't be
591 // a per sensor override, so we need to always check both.
592 std::string sensorNameFromPath = fs::path(path).filename();
593
594 std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
595
596 // Download the interfaces for the sensor from
597 // Entity-Manager to find the name of the configuration
598 // interface.
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100599 std::optional<std::map<std::string, std::vector<std::string>>>
600 sensorInterfacesResponseOpt =
Willy Tude54f482021-01-26 15:59:09 -0800601 getObjectInterfaces(sensorConfigPath.c_str());
602
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100603 if (!sensorInterfacesResponseOpt.has_value())
604 {
George Liude6694e2024-07-17 15:22:25 +0800605 lg2::debug("Failed to GetObject, path: {PATH}", "PATH",
606 sensorConfigPath);
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100607 continue;
608 }
609
Willy Tude54f482021-01-26 15:59:09 -0800610 const std::string* configurationInterface =
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100611 getSensorConfigurationInterface(
612 sensorInterfacesResponseOpt.value());
Willy Tude54f482021-01-26 15:59:09 -0800613
Harvey Wu7bb84db2023-06-26 10:02:08 +0800614 // If there are multi association path settings and only one path exist,
615 // we need to continue if cannot find configuration interface for this
616 // sensor.
Willy Tude54f482021-01-26 15:59:09 -0800617 if (!configurationInterface)
618 {
Harvey Wu7bb84db2023-06-26 10:02:08 +0800619 continue;
Willy Tude54f482021-01-26 15:59:09 -0800620 }
621
622 // We found a configuration interface.
623 std::map<std::string, Value> configurationProperties =
624 getEntityManagerProperties(sensorConfigPath.c_str(),
625 configurationInterface->c_str());
626
627 entityIdProp = configurationProperties.find("EntityId");
628 entityInstanceProp = configurationProperties.find("EntityInstance");
629 if (entityIdProp != configurationProperties.end())
630 {
631 entityId =
632 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
633 }
634 if (entityInstanceProp != configurationProperties.end())
635 {
636 entityInstance = static_cast<uint8_t>(
637 std::get<uint64_t>(entityInstanceProp->second));
638 }
639
640 // stop searching Association records.
641 break;
642 } // end for Association vectors.
643
644 if constexpr (debug)
645 {
646 std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
647 path.c_str(), entityId, entityInstance);
648 }
649}
650
651} // namespace ipmi