xref: /openbmc/phosphor-host-ipmid/include/ipmid/utils.hpp (revision 69b4c2811a262094addab680c925e63dd3468440)
1 #pragma once
2 
3 #include <boost/system/error_code.hpp>
4 #include <ipmid/api-types.hpp>
5 #include <ipmid/message.hpp>
6 #include <ipmid/types.hpp>
7 #include <sdbusplus/server.hpp>
8 
9 #include <chrono>
10 #include <optional>
11 
12 namespace ipmi
13 {
14 
15 using namespace std::literals::chrono_literals;
16 
17 constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper";
18 constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper";
19 constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper";
20 
21 constexpr auto ROOT = "/";
22 constexpr auto HOST_MATCH = "host0";
23 
24 constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties";
25 constexpr auto DELETE_INTERFACE = "xyz.openbmc_project.Object.Delete";
26 
27 constexpr auto METHOD_GET = "Get";
28 constexpr auto METHOD_GET_ALL = "GetAll";
29 constexpr auto METHOD_SET = "Set";
30 
31 /* Use a value of 5s which aligns with BT/KCS bridged timeouts, rather
32  * than the default 25s D-Bus timeout. */
33 constexpr std::chrono::microseconds IPMI_DBUS_TIMEOUT = 5s;
34 
35 /** @class ServiceCache
36  *  @brief Caches lookups of service names from the object mapper.
37  *  @details Most ipmi commands need to talk to other dbus daemons to perform
38  *           their intended actions on the BMC. This usually means they will
39  *           first look up the service name providing the interface they
40  *           require. This class reduces the number of such calls by caching
41  *           the lookup for a specific service.
42  */
43 class ServiceCache
44 {
45   public:
46     /** @brief Creates a new service cache for the given interface
47      *         and path.
48      *
49      *  @param[in] intf - The interface used for each lookup
50      *  @param[in] path - The path used for each lookup
51      */
52     ServiceCache(const std::string& intf, const std::string& path);
53     ServiceCache(std::string&& intf, std::string&& path);
54 
55     /** @brief Gets the service name from the cache or does in a
56      *         lookup when invalid.
57      *
58      *  @param[in] bus - The bus associated with and used for looking
59      *                   up the service.
60      */
61     const std::string& getService(sdbusplus::bus_t& bus);
62 
63     /** @brief Invalidates the current service name */
64     void invalidate();
65 
66     /** @brief A wrapper around sdbusplus bus.new_method_call
67      *
68      *  @param[in] bus - The bus used for calling the method
69      *  @param[in] intf - The interface containing the method
70      *  @param[in] method - The method name
71      *  @return The message containing the method call.
72      */
73     sdbusplus::message_t newMethodCall(sdbusplus::bus_t& bus, const char* intf,
74                                        const char* method);
75 
76     /** @brief Check to see if the current cache is valid
77      *
78      * @param[in] bus - The bus used for the service lookup
79      * @return True if the cache is valid false otherwise.
80      */
81     bool isValid(sdbusplus::bus_t& bus) const;
82 
83   private:
84     /** @brief DBUS interface provided by the service */
85     const std::string intf;
86     /** @brief DBUS path provided by the service */
87     const std::string path;
88     /** @brief The name of the service if valid */
89     std::optional<std::string> cachedService;
90     /** @brief The name of the bus used in the service lookup */
91     std::optional<std::string> cachedBusName;
92 };
93 
94 /**
95  * @brief Get the DBUS Service name for the input dbus path
96  *
97  * @param[in] bus - DBUS Bus Object
98  * @param[in] intf - DBUS Interface
99  * @param[in] path - DBUS Object Path
100  *
101  */
102 std::string getService(sdbusplus::bus_t& bus, const std::string& intf,
103                        const std::string& path);
104 
105 /** @brief Gets the dbus sub tree implementing the given interface.
106  *  @param[in] bus - DBUS Bus Object.
107  *  @param[in] interfaces - Dbus interface.
108  *  @param[in] subtreePath - subtree from where the search should start.
109  *  @param[in] depth - Search depth
110  *  @return map of object path and service info.
111  */
112 ObjectTree getSubTree(sdbusplus::bus_t& bus, const InterfaceList& interface,
113                       const std::string& subtreePath = ROOT, int32_t depth = 0);
114 
115 /** @brief Gets the dbus object info implementing the given interface
116  *         from the given subtree.
117  *  @param[in] bus - DBUS Bus Object.
118  *  @param[in] interface - Dbus interface.
119  *  @param[in] subtreePath - subtree from where the search should start.
120  *  @param[in] match - identifier for object.
121  *  @return On success returns the object having objectpath and servicename.
122  */
123 DbusObjectInfo getDbusObject(
124     sdbusplus::bus_t& bus, const std::string& interface,
125     const std::string& subtreePath = ROOT, const std::string& match = {});
126 
127 /** @brief Gets the value associated with the given object
128  *         and the interface.
129  *  @param[in] bus - DBUS Bus Object.
130  *  @param[in] service - Dbus service name.
131  *  @param[in] objPath - Dbus object path.
132  *  @param[in] interface - Dbus interface.
133  *  @param[in] property - name of the property.
134  *  @return On success returns the value of the property.
135  */
136 Value getDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
137                       const std::string& objPath, const std::string& interface,
138                       const std::string& property,
139                       std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT);
140 
141 /** @brief Gets all the properties associated with the given object
142  *         and the interface.
143  *  @param[in] bus - DBUS Bus Object.
144  *  @param[in] service - Dbus service name.
145  *  @param[in] objPath - Dbus object path.
146  *  @param[in] interface - Dbus interface.
147  *  @return On success returns the map of name value pair.
148  */
149 PropertyMap getAllDbusProperties(
150     sdbusplus::bus_t& bus, const std::string& service,
151     const std::string& objPath, const std::string& interface,
152     std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT);
153 
154 /** @brief Gets all managed objects associated with the given object
155  *         path and service.
156  *  @param[in] bus - D-Bus Bus Object.
157  *  @param[in] service - D-Bus service name.
158  *  @param[in] objPath - D-Bus object path.
159  *  @return On success returns the map of name value pair.
160  */
161 ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus,
162                                   const std::string& service,
163                                   const std::string& objPath);
164 
165 /** @brief Sets the property value of the given object.
166  *  @param[in] bus - DBUS Bus Object.
167  *  @param[in] service - Dbus service name.
168  *  @param[in] objPath - Dbus object path.
169  *  @param[in] interface - Dbus interface.
170  *  @param[in] property - name of the property.
171  *  @param[in] value - value which needs to be set.
172  */
173 void setDbusProperty(sdbusplus::bus_t& bus, const std::string& service,
174                      const std::string& objPath, const std::string& interface,
175                      const std::string& property, const Value& value,
176                      std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT);
177 
178 /** @brief  Gets all the dbus objects from the given service root
179  *          which matches the object identifier.
180  *  @param[in] bus - DBUS Bus Object.
181  *  @param[in] serviceRoot - Service root path.
182  *  @param[in] interface - Dbus interface.
183  *  @param[in] match - Identifier for a path.
184  *  @returns map of object path and service info.
185  */
186 ObjectTree getAllDbusObjects(
187     sdbusplus::bus_t& bus, const std::string& serviceRoot,
188     const std::string& interface, const std::string& match = {});
189 
190 /** @brief Deletes all the dbus objects from the given service root
191            which matches the object identifier.
192  *  @param[in] bus - DBUS Bus Object.
193  *  @param[in] serviceRoot - Service root path.
194  *  @param[in] interface - Dbus interface.
195  *  @param[in] match - Identifier for object.
196  */
197 void deleteAllDbusObjects(sdbusplus::bus_t& bus, const std::string& serviceRoot,
198                           const std::string& interface,
199                           const std::string& match = {})
200     __attribute__((deprecated));
201 
202 /** @brief Gets the ancestor objects of the given object
203            which implements the given interface.
204  *  @param[in] bus - Dbus bus object.
205  *  @param[in] path - Child Dbus object path.
206  *  @param[in] interfaces - Dbus interface list.
207  *  @return map of object path and service info.
208  */
209 ObjectTree getAllAncestors(sdbusplus::bus_t& bus, const std::string& path,
210                            InterfaceList&& interfaces)
211     __attribute__((deprecated));
212 
213 /********* Begin co-routine yielding alternatives ***************/
214 
215 /** @brief Get the D-Bus Service name for the input D-Bus path
216  *
217  *  @param[in] ctx - ipmi::Context::ptr
218  *  @param[in] intf - D-Bus Interface
219  *  @param[in] path - D-Bus Object Path
220  *  @param[out] service - requested service name
221  *  @return boost error code
222  *
223  */
224 boost::system::error_code getService(Context::ptr ctx, const std::string& intf,
225                                      const std::string& path,
226                                      std::string& service);
227 
228 /** @brief Gets the dbus sub tree implementing the given interface.
229  *  @param[in] ctx - ipmi::Context::ptr
230  *  @param[in] bus - DBUS Bus Object.
231  *  @param[in] interfaces - Dbus interface.
232  *  @param[in] subtreePath - subtree from where the search should start.
233  *  @param[in] depth - Search depth
234  *  @param[out] objectTree - map of object path and service info.
235  *  @return map of object path and service info.
236  */
237 boost::system::error_code getSubTree(
238     Context::ptr ctx, const InterfaceList& interface,
239     const std::string& subtreePath, int32_t depth, ObjectTree& objectTree);
240 
241 /** @brief Gets the D-Bus object info implementing the given interface
242  *         from the given subtree.
243  *  @param[in] ctx - ipmi::Context::ptr
244  *  @param[in] interface - D-Bus interface.
245  *  @param[in][optional] subtreePath - subtree from where the search starts.
246  *  @param[in][optional] match - identifier for object.
247  *  @param[out] D-Bus object with path and service name
248  *  @return - boost error code object
249  */
250 boost::system::error_code getDbusObject(
251     Context::ptr ctx, const std::string& interface,
252     const std::string& subtreePath, const std::string& match,
253     DbusObjectInfo& dbusObject);
254 
255 // default for ROOT for subtreePath and std::string{} for match
getDbusObject(Context::ptr ctx,const std::string & interface,DbusObjectInfo & dbusObject)256 static inline boost::system::error_code getDbusObject(
257     Context::ptr ctx, const std::string& interface, DbusObjectInfo& dbusObject)
258 {
259     return getDbusObject(ctx, interface, ROOT, {}, dbusObject);
260 }
261 
262 // default std::string{} for match
getDbusObject(Context::ptr ctx,const std::string & interface,const std::string & subtreePath,DbusObjectInfo & dbusObject)263 static inline boost::system::error_code getDbusObject(
264     Context::ptr ctx, const std::string& interface,
265     const std::string& subtreePath, DbusObjectInfo& dbusObject)
266 {
267     return getDbusObject(ctx, interface, subtreePath, {}, dbusObject);
268 }
269 
270 /** @brief Gets the value associated with the given object
271  *         and the interface.
272  *  @param[in] ctx - ipmi::Context::ptr
273  *  @param[in] service - D-Bus service name.
274  *  @param[in] objPath - D-Bus object path.
275  *  @param[in] interface - D-Bus interface.
276  *  @param[in] property - name of the property.
277  *  @param[out] propertyValue - value of the D-Bus property.
278  *  @return - boost error code object
279  */
280 template <typename Type>
getDbusProperty(Context::ptr ctx,const std::string & service,const std::string & objPath,const std::string & interface,const std::string & property,Type & propertyValue)281 boost::system::error_code getDbusProperty(
282     Context::ptr ctx, const std::string& service, const std::string& objPath,
283     const std::string& interface, const std::string& property,
284     Type& propertyValue)
285 {
286     boost::system::error_code ec;
287     auto variant = ctx->bus->yield_method_call<std::variant<Type>>(
288         ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF, METHOD_GET,
289         interface, property);
290     if (!ec)
291     {
292         Type* tmp = std::get_if<Type>(&variant);
293         if (tmp)
294         {
295             propertyValue = *tmp;
296             return ec;
297         }
298         // user requested incorrect type; make an error code for them
299         ec = boost::system::errc::make_error_code(
300             boost::system::errc::invalid_argument);
301     }
302     return ec;
303 }
304 
305 /** @brief Gets all the properties associated with the given object
306  *         and the interface.
307  *  @param[in] ctx - ipmi::Context::ptr
308  *  @param[in] service - D-Bus service name.
309  *  @param[in] objPath - D-Bus object path.
310  *  @param[in] interface - D-Bus interface.
311  *  @param[out] properties - map of name value pair.
312  *  @return - boost error code object
313  */
314 boost::system::error_code getAllDbusProperties(
315     Context::ptr ctx, const std::string& service, const std::string& objPath,
316     const std::string& interface, PropertyMap& properties);
317 
318 /** @brief Sets the property value of the given object.
319  *  @param[in] ctx - ipmi::Context::ptr
320  *  @param[in] service - D-Bus service name.
321  *  @param[in] objPath - D-Bus object path.
322  *  @param[in] interface - D-Bus interface.
323  *  @param[in] property - name of the property.
324  *  @param[in] value - value which needs to be set.
325  *  @return - boost error code object
326  */
327 boost::system::error_code setDbusProperty(
328     Context::ptr ctx, const std::string& service, const std::string& objPath,
329     const std::string& interface, const std::string& property,
330     const Value& value);
331 
332 /** @brief  Gets all the D-Bus objects from the given service root
333  *          which matches the object identifier.
334  *  @param[in] ctx - ipmi::Context::ptr
335  *  @param[in] serviceRoot - Service root path.
336  *  @param[in] interface - D-Bus interface.
337  *  @param[in][optional] match - Identifier for a path.
338  *  @param[out] objectree - map of object path and service info.
339  *  @return - boost error code object
340  */
341 boost::system::error_code getAllDbusObjects(
342     Context::ptr ctx, const std::string& serviceRoot,
343     const std::string& interface, const std::string& match,
344     ObjectTree& objectTree);
345 
346 // default std::string{} for match
getAllDbusObjects(Context::ptr ctx,const std::string & serviceRoot,const std::string & interface,ObjectTree & objectTree)347 static inline boost::system::error_code getAllDbusObjects(
348     Context::ptr ctx, const std::string& serviceRoot,
349     const std::string& interface, ObjectTree& objectTree)
350 {
351     return getAllDbusObjects(ctx, serviceRoot, interface, {}, objectTree);
352 }
353 
354 /** @brief Deletes all the D-Bus objects from the given service root
355            which matches the object identifier.
356  *  @param[in] ctx - ipmi::Context::ptr
357  *  @param[out] ec - boost error code object
358  *  @param[in] serviceRoot - Service root path.
359  *  @param[in] interface - D-Bus interface.
360  *  @param[in] match - Identifier for object.
361  */
362 boost::system::error_code deleteAllDbusObjects(
363     Context::ptr ctx, const std::string& serviceRoot,
364     const std::string& interface, const std::string& match = {})
365     __attribute__((deprecated));
366 
367 /** @brief Gets all managed objects associated with the given object
368  *         path and service.
369  *  @param[in] ctx - ipmi::Context::ptr
370  *  @param[in] service - D-Bus service name.
371  *  @param[in] objPath - D-Bus object path.
372  *  @param[out] objects - map of name value pair.
373  *  @return - boost error code object
374  */
375 boost::system::error_code getManagedObjects(
376     Context::ptr ctx, const std::string& service, const std::string& objPath,
377     ObjectValueTree& objects);
378 
379 /** @brief Gets the ancestor objects of the given object
380            which implements the given interface.
381  *  @param[in] ctx - ipmi::Context::ptr
382  *  @param[in] path - Child D-Bus object path.
383  *  @param[in] interfaces - D-Bus interface list.
384  *  @param[out] ObjectTree - map of object path and service info.
385  *  @return - boost error code object
386  */
387 boost::system::error_code getAllAncestors(
388     Context::ptr ctx, const std::string& path, const InterfaceList& interfaces,
389     ObjectTree& objectTree) __attribute__((deprecated));
390 
391 /** @brief Gets the value associated with the given object
392  *         and the interface.
393  *  @param[in] ctx - ipmi::Context::ptr
394  *  @param[in] service - D-Bus service name.
395  *  @param[in] objPath - D-Bus object path.
396  *  @param[in] interface - D-Bus interface.
397  *  @param[in] method - name of the method.
398  *  @return - boost error code object
399  */
400 
401 boost::system::error_code callDbusMethod(
402     Context::ptr ctx, const std::string& service, const std::string& objPath,
403     const std::string& interface, const std::string& method);
404 
405 /********* End co-routine yielding alternatives ***************/
406 
407 /** @brief Retrieve the value from map of variants,
408  *         returning a default if the key does not exist or the
409  *         type of the value does not match the expected type
410  *
411  *  @tparam T - type of expected value to return
412  *  @param[in] props - D-Bus propery map (Map of variants)
413  *  @param[in] name - key name of property to fetch
414  *  @param[in] defaultValue - default value to return on error
415  *  @return - value from propery map at name, or defaultValue
416  */
417 template <typename T>
mappedVariant(const ipmi::PropertyMap & props,const std::string & name,const T & defaultValue)418 T mappedVariant(const ipmi::PropertyMap& props, const std::string& name,
419                 const T& defaultValue)
420 {
421     auto item = props.find(name);
422     if (item == props.end())
423     {
424         return defaultValue;
425     }
426     const T* prop = std::get_if<T>(&item->second);
427     if (!prop)
428     {
429         return defaultValue;
430     }
431     return *prop;
432 }
433 
434 /** @struct VariantToDoubleVisitor
435  *  @brief Visitor to convert variants to doubles
436  *  @details Performs a static cast on the underlying type
437  */
438 struct VariantToDoubleVisitor
439 {
440     template <typename T>
operator ()ipmi::VariantToDoubleVisitor441     std::enable_if_t<std::is_arithmetic<T>::value, double> operator()(
442         const T& t) const
443     {
444         return static_cast<double>(t);
445     }
446 
447     template <typename T>
operator ()ipmi::VariantToDoubleVisitor448     std::enable_if_t<!std::is_arithmetic<T>::value, double> operator()(
449         const T&) const
450     {
451         throw std::invalid_argument("Cannot translate type to double");
452     }
453 };
454 
455 namespace method_no_args
456 {
457 
458 /** @brief Calls the Dbus method which waits for response.
459  *  @param[in] bus - DBUS Bus Object.
460  *  @param[in] service - Dbus service name.
461  *  @param[in] objPath - Dbus object path.
462  *  @param[in] interface - Dbus interface.
463  *  @param[in] method - Dbus method.
464  */
465 void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service,
466                     const std::string& objPath, const std::string& interface,
467                     const std::string& method);
468 
469 } // namespace method_no_args
470 
471 /** @brief Perform the low-level i2c bus write-read.
472  *  @param[in] i2cBus - i2c bus device node name, such as /dev/i2c-2.
473  *  @param[in] targetAddr - i2c device target address.
474  *  @param[in] writeData - The data written to i2c device.
475  *  @param[out] readBuf - Data read from the i2c device.
476  */
477 ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr,
478                       std::vector<uint8_t> writeData,
479                       std::vector<uint8_t>& readBuf);
480 } // namespace ipmi
481