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(sdbusplus::bus_t& bus, 124 const std::string& interface, 125 const std::string& subtreePath = ROOT, 126 const std::string& match = {}); 127 128 /** @brief Gets the value associated with the given object 129 * and the interface. 130 * @param[in] bus - DBUS Bus Object. 131 * @param[in] service - Dbus service name. 132 * @param[in] objPath - Dbus object path. 133 * @param[in] interface - Dbus interface. 134 * @param[in] property - name of the property. 135 * @return On success returns the value of the property. 136 */ 137 Value getDbusProperty(sdbusplus::bus_t& bus, const std::string& service, 138 const std::string& objPath, const std::string& interface, 139 const std::string& property, 140 std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); 141 142 /** @brief Gets all the properties associated with the given object 143 * and the interface. 144 * @param[in] bus - DBUS Bus Object. 145 * @param[in] service - Dbus service name. 146 * @param[in] objPath - Dbus object path. 147 * @param[in] interface - Dbus interface. 148 * @return On success returns the map of name value pair. 149 */ 150 PropertyMap 151 getAllDbusProperties(sdbusplus::bus_t& bus, const std::string& service, 152 const std::string& objPath, 153 const std::string& interface, 154 std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); 155 156 /** @brief Gets all managed objects associated with the given object 157 * path and service. 158 * @param[in] bus - D-Bus Bus Object. 159 * @param[in] service - D-Bus service name. 160 * @param[in] objPath - D-Bus object path. 161 * @return On success returns the map of name value pair. 162 */ 163 ObjectValueTree getManagedObjects(sdbusplus::bus_t& bus, 164 const std::string& service, 165 const std::string& objPath); 166 167 /** @brief Sets the property value of the given object. 168 * @param[in] bus - DBUS Bus Object. 169 * @param[in] service - Dbus service name. 170 * @param[in] objPath - Dbus object path. 171 * @param[in] interface - Dbus interface. 172 * @param[in] property - name of the property. 173 * @param[in] value - value which needs to be set. 174 */ 175 void setDbusProperty(sdbusplus::bus_t& bus, const std::string& service, 176 const std::string& objPath, const std::string& interface, 177 const std::string& property, const Value& value, 178 std::chrono::microseconds timeout = IPMI_DBUS_TIMEOUT); 179 180 /** @brief Gets all the dbus objects from the given service root 181 * which matches the object identifier. 182 * @param[in] bus - DBUS Bus Object. 183 * @param[in] serviceRoot - Service root path. 184 * @param[in] interface - Dbus interface. 185 * @param[in] match - Identifier for a path. 186 * @returns map of object path and service info. 187 */ 188 ObjectTree getAllDbusObjects(sdbusplus::bus_t& bus, 189 const std::string& serviceRoot, 190 const std::string& interface, 191 const std::string& match = {}); 192 193 /** @brief Deletes all the dbus objects from the given service root 194 which matches the object identifier. 195 * @param[in] bus - DBUS Bus Object. 196 * @param[in] serviceRoot - Service root path. 197 * @param[in] interface - Dbus interface. 198 * @param[in] match - Identifier for object. 199 */ 200 void deleteAllDbusObjects(sdbusplus::bus_t& bus, const std::string& serviceRoot, 201 const std::string& interface, 202 const std::string& match = {}) 203 __attribute__((deprecated)); 204 205 /** @brief Gets the ancestor objects of the given object 206 which implements the given interface. 207 * @param[in] bus - Dbus bus object. 208 * @param[in] path - Child Dbus object path. 209 * @param[in] interfaces - Dbus interface list. 210 * @return map of object path and service info. 211 */ 212 ObjectTree getAllAncestors(sdbusplus::bus_t& bus, const std::string& path, 213 InterfaceList&& interfaces) 214 __attribute__((deprecated)); 215 216 /********* Begin co-routine yielding alternatives ***************/ 217 218 /** @brief Get the D-Bus Service name for the input D-Bus path 219 * 220 * @param[in] ctx - ipmi::Context::ptr 221 * @param[in] intf - D-Bus Interface 222 * @param[in] path - D-Bus Object Path 223 * @param[out] service - requested service name 224 * @return boost error code 225 * 226 */ 227 boost::system::error_code getService(Context::ptr ctx, const std::string& intf, 228 const std::string& path, 229 std::string& service); 230 231 /** @brief Gets the dbus sub tree implementing the given interface. 232 * @param[in] ctx - ipmi::Context::ptr 233 * @param[in] bus - DBUS Bus Object. 234 * @param[in] interfaces - Dbus interface. 235 * @param[in] subtreePath - subtree from where the search should start. 236 * @param[in] depth - Search depth 237 * @param[out] objectTree - map of object path and service info. 238 * @return map of object path and service info. 239 */ 240 boost::system::error_code getSubTree(Context::ptr ctx, 241 const InterfaceList& interface, 242 const std::string& subtreePath, 243 int32_t depth, ObjectTree& objectTree); 244 245 /** @brief Gets the D-Bus object info implementing the given interface 246 * from the given subtree. 247 * @param[in] ctx - ipmi::Context::ptr 248 * @param[in] interface - D-Bus interface. 249 * @param[in][optional] subtreePath - subtree from where the search starts. 250 * @param[in][optional] match - identifier for object. 251 * @param[out] D-Bus object with path and service name 252 * @return - boost error code object 253 */ 254 boost::system::error_code getDbusObject(Context::ptr ctx, 255 const std::string& interface, 256 const std::string& subtreePath, 257 const std::string& match, 258 DbusObjectInfo& dbusObject); 259 260 // default for ROOT for subtreePath and std::string{} for match 261 static inline boost::system::error_code 262 getDbusObject(Context::ptr ctx, const std::string& interface, 263 DbusObjectInfo& dbusObject) 264 { 265 return getDbusObject(ctx, interface, ROOT, {}, dbusObject); 266 } 267 268 // default std::string{} for match 269 static inline boost::system::error_code 270 getDbusObject(Context::ptr ctx, const std::string& interface, 271 const std::string& subtreePath, DbusObjectInfo& dbusObject) 272 { 273 return getDbusObject(ctx, interface, subtreePath, {}, dbusObject); 274 } 275 276 /** @brief Gets the value associated with the given object 277 * and the interface. 278 * @param[in] ctx - ipmi::Context::ptr 279 * @param[in] service - D-Bus service name. 280 * @param[in] objPath - D-Bus object path. 281 * @param[in] interface - D-Bus interface. 282 * @param[in] property - name of the property. 283 * @param[out] propertyValue - value of the D-Bus property. 284 * @return - boost error code object 285 */ 286 template <typename Type> 287 boost::system::error_code 288 getDbusProperty(Context::ptr ctx, const std::string& service, 289 const std::string& objPath, const std::string& interface, 290 const std::string& property, Type& propertyValue) 291 { 292 boost::system::error_code ec; 293 auto variant = ctx->bus->yield_method_call<std::variant<Type>>( 294 ctx->yield, ec, service.c_str(), objPath.c_str(), PROP_INTF, METHOD_GET, 295 interface, property); 296 if (!ec) 297 { 298 Type* tmp = std::get_if<Type>(&variant); 299 if (tmp) 300 { 301 propertyValue = *tmp; 302 return ec; 303 } 304 // user requested incorrect type; make an error code for them 305 ec = boost::system::errc::make_error_code( 306 boost::system::errc::invalid_argument); 307 } 308 return ec; 309 } 310 311 /** @brief Gets all the properties associated with the given object 312 * and the interface. 313 * @param[in] ctx - ipmi::Context::ptr 314 * @param[in] service - D-Bus service name. 315 * @param[in] objPath - D-Bus object path. 316 * @param[in] interface - D-Bus interface. 317 * @param[out] properties - map of name value pair. 318 * @return - boost error code object 319 */ 320 boost::system::error_code getAllDbusProperties(Context::ptr ctx, 321 const std::string& service, 322 const std::string& objPath, 323 const std::string& interface, 324 PropertyMap& properties); 325 326 /** @brief Sets the property value of the given object. 327 * @param[in] ctx - ipmi::Context::ptr 328 * @param[in] service - D-Bus service name. 329 * @param[in] objPath - D-Bus object path. 330 * @param[in] interface - D-Bus interface. 331 * @param[in] property - name of the property. 332 * @param[in] value - value which needs to be set. 333 * @return - boost error code object 334 */ 335 boost::system::error_code 336 setDbusProperty(Context::ptr ctx, const std::string& service, 337 const std::string& objPath, const std::string& interface, 338 const std::string& property, const Value& value); 339 340 /** @brief Gets all the D-Bus objects from the given service root 341 * which matches the object identifier. 342 * @param[in] ctx - ipmi::Context::ptr 343 * @param[in] serviceRoot - Service root path. 344 * @param[in] interface - D-Bus interface. 345 * @param[in][optional] match - Identifier for a path. 346 * @param[out] objectree - map of object path and service info. 347 * @return - boost error code object 348 */ 349 boost::system::error_code getAllDbusObjects(Context::ptr ctx, 350 const std::string& serviceRoot, 351 const std::string& interface, 352 const std::string& match, 353 ObjectTree& objectTree); 354 355 // default std::string{} for match 356 static inline boost::system::error_code 357 getAllDbusObjects(Context::ptr ctx, const std::string& serviceRoot, 358 const std::string& interface, ObjectTree& objectTree) 359 { 360 return getAllDbusObjects(ctx, serviceRoot, interface, {}, objectTree); 361 } 362 363 /** @brief Deletes all the D-Bus objects from the given service root 364 which matches the object identifier. 365 * @param[in] ctx - ipmi::Context::ptr 366 * @param[out] ec - boost error code object 367 * @param[in] serviceRoot - Service root path. 368 * @param[in] interface - D-Bus interface. 369 * @param[in] match - Identifier for object. 370 */ 371 boost::system::error_code deleteAllDbusObjects(Context::ptr ctx, 372 const std::string& serviceRoot, 373 const std::string& interface, 374 const std::string& match = {}) 375 __attribute__((deprecated)); 376 377 /** @brief Gets all managed objects associated with the given object 378 * path and service. 379 * @param[in] ctx - ipmi::Context::ptr 380 * @param[in] service - D-Bus service name. 381 * @param[in] objPath - D-Bus object path. 382 * @param[out] objects - map of name value pair. 383 * @return - boost error code object 384 */ 385 boost::system::error_code getManagedObjects(Context::ptr ctx, 386 const std::string& service, 387 const std::string& objPath, 388 ObjectValueTree& objects); 389 390 /** @brief Gets the ancestor objects of the given object 391 which implements the given interface. 392 * @param[in] ctx - ipmi::Context::ptr 393 * @param[in] path - Child D-Bus object path. 394 * @param[in] interfaces - D-Bus interface list. 395 * @param[out] ObjectTree - map of object path and service info. 396 * @return - boost error code object 397 */ 398 boost::system::error_code 399 getAllAncestors(Context::ptr ctx, const std::string& path, 400 const InterfaceList& interfaces, ObjectTree& objectTree) 401 __attribute__((deprecated)); 402 403 /** @brief Gets the value associated with the given object 404 * and the interface. 405 * @param[in] ctx - ipmi::Context::ptr 406 * @param[in] service - D-Bus service name. 407 * @param[in] objPath - D-Bus object path. 408 * @param[in] interface - D-Bus interface. 409 * @param[in] method - name of the method. 410 * @return - boost error code object 411 */ 412 413 boost::system::error_code callDbusMethod(Context::ptr ctx, 414 const std::string& service, 415 const std::string& objPath, 416 const std::string& interface, 417 const std::string& method); 418 419 /********* End co-routine yielding alternatives ***************/ 420 421 /** @brief Retrieve the value from map of variants, 422 * returning a default if the key does not exist or the 423 * type of the value does not match the expected type 424 * 425 * @tparam T - type of expected value to return 426 * @param[in] props - D-Bus propery map (Map of variants) 427 * @param[in] name - key name of property to fetch 428 * @param[in] defaultValue - default value to return on error 429 * @return - value from propery map at name, or defaultValue 430 */ 431 template <typename T> 432 T mappedVariant(const ipmi::PropertyMap& props, const std::string& name, 433 const T& defaultValue) 434 { 435 auto item = props.find(name); 436 if (item == props.end()) 437 { 438 return defaultValue; 439 } 440 const T* prop = std::get_if<T>(&item->second); 441 if (!prop) 442 { 443 return defaultValue; 444 } 445 return *prop; 446 } 447 448 /** @struct VariantToDoubleVisitor 449 * @brief Visitor to convert variants to doubles 450 * @details Performs a static cast on the underlying type 451 */ 452 struct VariantToDoubleVisitor 453 { 454 template <typename T> 455 std::enable_if_t<std::is_arithmetic<T>::value, double> 456 operator()(const T& t) const 457 { 458 return static_cast<double>(t); 459 } 460 461 template <typename T> 462 std::enable_if_t<!std::is_arithmetic<T>::value, double> 463 operator()(const T&) const 464 { 465 throw std::invalid_argument("Cannot translate type to double"); 466 } 467 }; 468 469 namespace method_no_args 470 { 471 472 /** @brief Calls the Dbus method which waits for response. 473 * @param[in] bus - DBUS Bus Object. 474 * @param[in] service - Dbus service name. 475 * @param[in] objPath - Dbus object path. 476 * @param[in] interface - Dbus interface. 477 * @param[in] method - Dbus method. 478 */ 479 void callDbusMethod(sdbusplus::bus_t& bus, const std::string& service, 480 const std::string& objPath, const std::string& interface, 481 const std::string& method); 482 483 } // namespace method_no_args 484 485 /** @brief Perform the low-level i2c bus write-read. 486 * @param[in] i2cBus - i2c bus device node name, such as /dev/i2c-2. 487 * @param[in] targetAddr - i2c device target address. 488 * @param[in] writeData - The data written to i2c device. 489 * @param[out] readBuf - Data read from the i2c device. 490 */ 491 ipmi::Cc i2cWriteRead(std::string i2cBus, const uint8_t targetAddr, 492 std::vector<uint8_t> writeData, 493 std::vector<uint8_t>& readBuf); 494 } // namespace ipmi 495