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 225 getService(Context::ptr ctx, const std::string& intf, 226 const std::string& path, 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 251 getDbusObject(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 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 263 static inline boost::system::error_code 264 getDbusObject(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> 281 boost::system::error_code 282 getDbusProperty(Context::ptr ctx, const std::string& service, 283 const std::string& objPath, const std::string& interface, 284 const std::string& property, 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 328 setDbusProperty(Context::ptr ctx, const std::string& service, 329 const std::string& objPath, const std::string& interface, 330 const std::string& property, 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 342 getAllDbusObjects(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 347 static inline boost::system::error_code 348 getAllDbusObjects(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 376 getManagedObjects(Context::ptr ctx, const std::string& service, 377 const std::string& objPath, 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 388 getAllAncestors(Context::ptr ctx, const std::string& path, 389 const InterfaceList& interfaces, ObjectTree& objectTree) 390 __attribute__((deprecated)); 391 392 /** @brief Gets the value associated with the given object 393 * and the interface. 394 * @param[in] ctx - ipmi::Context::ptr 395 * @param[in] service - D-Bus service name. 396 * @param[in] objPath - D-Bus object path. 397 * @param[in] interface - D-Bus interface. 398 * @param[in] method - name of the method. 399 * @return - boost error code object 400 */ 401 402 boost::system::error_code callDbusMethod( 403 Context::ptr ctx, const std::string& service, const std::string& objPath, 404 const std::string& interface, const std::string& method); 405 406 /********* End co-routine yielding alternatives ***************/ 407 408 /** @brief Retrieve the value from map of variants, 409 * returning a default if the key does not exist or the 410 * type of the value does not match the expected type 411 * 412 * @tparam T - type of expected value to return 413 * @param[in] props - D-Bus propery map (Map of variants) 414 * @param[in] name - key name of property to fetch 415 * @param[in] defaultValue - default value to return on error 416 * @return - value from propery map at name, or defaultValue 417 */ 418 template <typename T> 419 T mappedVariant(const ipmi::PropertyMap& props, const std::string& name, 420 const T& defaultValue) 421 { 422 auto item = props.find(name); 423 if (item == props.end()) 424 { 425 return defaultValue; 426 } 427 const T* prop = std::get_if<T>(&item->second); 428 if (!prop) 429 { 430 return defaultValue; 431 } 432 return *prop; 433 } 434 435 /** @struct VariantToDoubleVisitor 436 * @brief Visitor to convert variants to doubles 437 * @details Performs a static cast on the underlying type 438 */ 439 struct VariantToDoubleVisitor 440 { 441 template <typename T> 442 std::enable_if_t<std::is_arithmetic<T>::value, double> 443 operator()(const T& t) const 444 { 445 return static_cast<double>(t); 446 } 447 448 template <typename T> 449 std::enable_if_t<!std::is_arithmetic<T>::value, double> 450 operator()(const T&) const 451 { 452 throw std::invalid_argument("Cannot translate type to double"); 453 } 454 }; 455 456 namespace method_no_args 457 { 458 459 /** @brief Calls the Dbus method which waits for response. 460 * @param[in] bus - DBUS Bus Object. 461 * @param[in] service - Dbus service name. 462 * @param[in] objPath - Dbus object path. 463 * @param[in] interface - Dbus interface. 464 * @param[in] method - Dbus method. 465 */ 466 void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service, 467 const std::string& objPath, const std::string& interface, 468 const std::string& method); 469 470 } // namespace method_no_args 471 472 /** @brief Perform the low-level i2c bus write-read. 473 * @param[in] i2cBus - i2c bus device node name, such as /dev/i2c-2. 474 * @param[in] targetAddr - i2c device target address. 475 * @param[in] writeData - The data written to i2c device. 476 * @param[out] readBuf - Data read from the i2c device. 477 */ 478 ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr, 479 std::vector<uint8_t> writeData, 480 std::vector<uint8_t>& readBuf); 481 } // namespace ipmi 482