blob: 3aa7c0f5af026aa8345efc7c3eb21c3b1dc22089 [file] [log] [blame]
Adedeji Adebisi684ec912021-07-22 18:07:52 +00001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include "main.hpp"
18// This is the form a sensor assumes on DBus.
19// Aggregates their view from all other daemons.
20#include <bitset>
21#include <optional>
22#include <set>
23#include <string>
24#include <unordered_map>
25#include <unordered_set>
26#include <vector>
27// Where is this sensor seen?
28constexpr int VISIBILITY_OBJECT_MAPPER = 0;
29constexpr int VISIBILITY_HWMON = 1;
30constexpr int VISIBILITY_IPMITOOL_SDR = 2;
31class DBusConnection
32{
33 public:
34 std::string service; // example: "systemd-resolved"
35 std::string connection; // example: ":1.1"
36 std::string cmd; // the comm line
37 std::string unit; // example: "systemd-resolved.service"
38 int pid;
39 // For actual DBus capture: service name, connection name, command line,
40 // systmed unit and PID are all known
41 DBusConnection(const std::string& _s, const std::string& _c,
42 const std::string& _cmd, const std::string& _u, int _pid)
43 {
44 service = _s;
45 connection = _c;
46 cmd = _cmd;
47 unit = _u;
48 pid = _pid;
49 }
50
51 // During PCap replay: only service name, connection name, and PID are known
52 // cmd and unit are not known since they are not
53 // stored in the PCap file
54 DBusConnection(const std::string& _s, const std::string& _c, int _pid)
55 {
56 service = _s;
57 connection = _c;
58 pid = _pid;
59 }
60};
61
62class DBusConnectionSnapshot
63{
64 public:
65 std::vector<DBusConnection*> connections_;
66 std::unordered_map<std::string, DBusConnection*> unique_name_to_cxn;
67 DBusConnection* FindDBusConnectionByService(const std::string& service)
68 {
69 for (DBusConnection* cxn : connections_)
70 {
71 if (cxn->service == service)
72 return cxn;
73 }
74 return nullptr;
75 }
76
77 void SetConnectionPID(const std::string& connection, int pid)
78 {
79 DBusConnection* cxn = FindDBusConnectionByService(connection);
80 if (cxn != nullptr)
81 {
82 cxn->pid = pid;
83 unique_name_to_cxn[connection] = cxn; // Just to make sure
84 }
85 }
86
87 void SetConnectionUniqueName(const std::string& service,
88 const std::string& unique_name)
89 {
90 DBusConnection* cxn = FindDBusConnectionByService(service);
91 if (cxn != nullptr)
92 {
93 cxn->connection = unique_name;
94 unique_name_to_cxn[unique_name] = cxn;
95 }
96 }
97
98 DBusConnection* FindDBusConnectionByConnection(const std::string& conn)
99 {
100 for (DBusConnection* cxn : connections_)
101 {
102 if (cxn->connection == conn)
103 return cxn;
104 }
105 return nullptr;
106 }
107
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000108 // Only when service is known (during playback)
109 void AddConnection(const std::string& _s)
110 {
111 connections_.push_back(new DBusConnection(_s, "", "", "", INVALID));
112 }
113
114 // When all 5 pieces of details are known (during actual capture)
115 void AddConnection(const std::string& _s, const std::string& _connection,
116 const std::string& _cmd, const std::string& _unit,
117 int _pid)
118 {
Patrick Williamsf5c0b9d2023-03-14 09:31:01 -0500119 DBusConnection* cxn = new DBusConnection(_s, _connection, _cmd, _unit,
120 _pid);
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000121 connections_.push_back(cxn);
122 unique_name_to_cxn[_connection] = cxn;
123 }
124
125 int GetConnectionPIDFromNameOrUniqueName(const std::string& key)
126 {
127 if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
128 {
129 return INVALID;
130 }
131 else
132 {
133 return unique_name_to_cxn[key]->pid;
134 }
135 }
136
137 std::string GetConnectionCMDFromNameOrUniqueName(const std::string& key)
138 {
139 if (unique_name_to_cxn.find(key) == unique_name_to_cxn.end())
140 {
141 return "(unknown)";
142 }
143 else
144 {
145 return unique_name_to_cxn[key]->cmd;
146 }
147 }
148
149 std::string GetUniqueNameIfExists(const std::string service)
150 {
151 for (DBusConnection* cxn : connections_)
152 {
153 if (cxn->service == service)
154 return cxn->connection;
155 }
156 return service;
157 }
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000158};
159
160// Each sensor might have different units, for example current and voltage
161class Sensor
162{
163 public:
164 DBusConnection* connection_;
165 // Example: "/xyz/openbmc_project/sensors/temperature/powerseq_temp"
166 std::string object_path_;
167 std::string SensorID()
168 {
169 const size_t idx = object_path_.rfind('/');
170 if (idx != std::string::npos)
171 {
172 return object_path_.substr(idx + 1);
173 }
174 else
175 return ("unknown sensor");
176 }
177
178 std::string ServiceName()
179 {
180 if (connection_ == nullptr)
181 return "";
182 else
183 return connection_->service;
184 }
185
186 std::string ConnectionName()
187 {
188 if (connection_ == nullptr)
189 return "";
190 else
191 return connection_->connection;
192 }
193
194 std::string ObjectPath()
195 {
196 return object_path_;
197 }
198
199 // Should contain the following:
200 // 1. "org.freedesktop.DBus.Introspectable"
201 // 2. "org.freedesktop.DBus.Peer"
202 // 3. "org.freedesktop.DBus.Properties"
203 // 4. "xyz.openbmc_project.Sensor.Value"
204 // 5. "xyz.openbmc_project.State.Decorator.OperationalStatus"
205 std::set<std::string> interfaces_;
206 std::bitset<4> visibility_flags_;
207 std::set<std::string> associations_;
208};
209
210class SensorSnapshot
211{
212 public:
213 std::vector<std::string> GetDistinctSensorNames()
214 {
215 std::unordered_set<std::string> seen;
216 std::vector<std::string> ret;
217 for (Sensor* s : sensors_)
218 {
219 std::string sn = s->SensorID();
220 if (seen.find(sn) == seen.end())
221 {
222 ret.push_back(sn);
223 seen.insert(sn);
224 }
225 }
226 return ret;
227 }
228
229 explicit SensorSnapshot(DBusConnectionSnapshot* cs)
230 {
231 connection_snapshot_ = cs;
232 }
233
234 ~SensorSnapshot()
235 {
236 for (Sensor* s : sensors_)
237 {
238 delete s;
239 }
240 }
241
242 int SensorCount()
243 {
244 return int(sensors_.size());
245 }
246
247 Sensor* FindOrCreateSensorByServiceAndObject(const std::string& service,
248 const std::string& object)
249 {
250 Sensor* ret = nullptr;
251 for (Sensor* s : sensors_)
252 {
253 if (s->ServiceName() == service && s->object_path_ == object)
254 {
255 ret = s;
256 break;
257 }
258 }
259 if (ret == nullptr)
260 {
261 DBusConnection* cxn =
262 connection_snapshot_->FindDBusConnectionByService(service);
263 ret = new Sensor();
264 ret->connection_ = cxn;
265 ret->object_path_ = object;
266 sensors_.push_back(ret);
267 }
268 return ret;
269 }
270
271 // Note: one sensor_id might correspond to multiple sensors.
272 // Example: "VDD" can have all 3 of power, current and voltage.
273 std::vector<Sensor*> FindSensorsBySensorID(const std::string& sensor_id)
274 {
275 std::vector<Sensor*> ret;
276 for (Sensor* s : sensors_)
277 {
278 const std::string& p = s->object_path_;
279 if (p.find(sensor_id) == p.size() - sensor_id.size())
280 {
281 ret.push_back(s);
282 }
283 }
284 return ret;
285 }
286
287 // This sensor is visible from Object Mapper
288 void SerSensorVisibleFromObjectMapper(const std::string& service,
289 const std::string& object)
290 {
291 Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
292 s->visibility_flags_.set(VISIBILITY_OBJECT_MAPPER);
293 }
kuiyingdfb0cd92023-03-14 11:43:23 +0800294
Adedeji Adebisi684ec912021-07-22 18:07:52 +0000295 // This sensor is visible from Hwmon
296 void SetSensorVisibleFromHwmon(const std::string& service,
297 const std::string& object)
298 {
299 Sensor* s = FindOrCreateSensorByServiceAndObject(service, object);
300 s->visibility_flags_.set(VISIBILITY_HWMON);
301 }
302
303 // This sensor is visible from `ipmitool sdr`
304 // The first column is referred to as "sensorid".
305 void SetSensorVisibleFromIpmitoolSdr(const std::string& sensor_id)
306 {
307 std::vector<Sensor*> sensors = FindSensorsBySensorID(sensor_id);
308 for (Sensor* s : sensors)
309 s->visibility_flags_.set(VISIBILITY_IPMITOOL_SDR);
310 }
311
312 void PrintSummary()
313 {
314 for (Sensor* s : sensors_)
315 {
316 printf("%50s %50s %9s\n", s->ServiceName().c_str(),
317 s->object_path_.c_str(),
318 s->visibility_flags_.to_string().c_str());
319 }
320 }
321
322 Sensor* FindSensorByDBusUniqueNameOrServiceName(const std::string& key)
323 {
324 for (Sensor* s : sensors_)
325 {
326 if (s->ConnectionName() == key || s->ServiceName() == key)
327 return s;
328 }
329 return nullptr;
330 }
331
332 private:
333 std::vector<Sensor*> sensors_;
334 std::unordered_map<std::string, int> conn2pid_;
335 DBusConnectionSnapshot* connection_snapshot_;
336};
337
338bool IsSensorObjectPath(const std::string& s);
339bool IsUniqueName(const std::string& x);
340std::string Trim(const std::string& s);