| #pragma once |
| |
| #include "Utils.hpp" |
| |
| #include <boost/asio/steady_timer.hpp> |
| #include <sdbusplus/asio/connection.hpp> |
| #include <sdbusplus/bus/match.hpp> |
| #include <sdbusplus/message.hpp> |
| #include <sdbusplus/message/native_types.hpp> |
| |
| #include <cstdint> |
| #include <iostream> |
| |
| /** |
| * @file |
| * @brief Abstract and concrete classes representing MCTP concepts and |
| * behaviours. |
| */ |
| |
| /** |
| * @brief An exception type that may be thrown by implementations of the MCTP |
| * abstract classes. |
| * |
| * This exception should be the basis for all exceptions thrown out of the MCTP |
| * APIs, and should capture any other exceptions that occur. |
| */ |
| class MCTPException : public std::exception |
| { |
| public: |
| MCTPException() = delete; |
| explicit MCTPException(const char* desc) : desc(desc) {} |
| const char* what() const noexcept override |
| { |
| return desc; |
| } |
| |
| private: |
| const char* desc; |
| }; |
| |
| /** |
| * @brief An enum of the MCTP transports described in DSP0239 v1.10.0 Section 7. |
| * |
| * https://www.dmtf.org/sites/default/files/standards/documents/DSP0239_1.10.0.pdf |
| */ |
| enum class MCTPTransport |
| { |
| Reserved = 0x00, |
| SMBus = 0x01, |
| }; |
| |
| /** |
| * @brief Captures properties of MCTP interfaces. |
| * |
| * https://github.com/CodeConstruct/mctp/blob/v1.1/src/mctp.c#L672-L703 |
| */ |
| struct MCTPInterface |
| { |
| std::string name; |
| MCTPTransport transport; |
| |
| auto operator<=>(const MCTPInterface& r) const = default; |
| }; |
| |
| class MCTPDevice; |
| |
| /** |
| * @brief Captures the behaviour of an endpoint at the MCTP layer |
| * |
| * The lifetime of an instance of MctpEndpoint is proportional to the lifetime |
| * of the endpoint configuration. If an endpoint is deconfigured such that its |
| * device has no assigned EID, then any related MctpEndpoint instance must be |
| * destructed as a consequence. |
| */ |
| class MCTPEndpoint |
| { |
| public: |
| using Event = std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)>; |
| using Result = std::function<void(const std::error_code& ec)>; |
| |
| virtual ~MCTPEndpoint() = default; |
| |
| /** |
| * @return The Linux network ID of the network in which the endpoint |
| participates |
| */ |
| virtual int network() const = 0; |
| |
| /** |
| * @return The MCTP endpoint ID of the endpoint in its network |
| */ |
| virtual uint8_t eid() const = 0; |
| |
| /** |
| * @brief Subscribe to events produced by an endpoint object across its |
| * lifecycle |
| * |
| * @param degraded The callback to execute when the MCTP layer indicates the |
| * endpoint is unresponsive |
| * |
| * @param available The callback to execute when the MCTP layer indicates |
| * that communication with the degraded endpoint has been |
| * recovered |
| * |
| * @param removed The callback to execute when the MCTP layer indicates the |
| * endpoint has been removed. |
| */ |
| virtual void subscribe(Event&& degraded, Event&& available, |
| Event&& removed) = 0; |
| |
| /** |
| * @brief Remove the endpoint from its associated network |
| */ |
| virtual void remove() = 0; |
| |
| /** |
| * @return A formatted string representing the endpoint in terms of its |
| * address properties |
| */ |
| virtual std::string describe() const = 0; |
| |
| /** |
| * @return A shared pointer to the device instance associated with the |
| * endpoint. |
| */ |
| virtual std::shared_ptr<MCTPDevice> device() const = 0; |
| }; |
| |
| /** |
| * @brief Represents an MCTP-capable device on a bus. |
| * |
| * It is often known that an MCTP-capable device exists on a bus prior to the |
| * MCTP stack configuring the device for communication. MctpDevice exposes the |
| * ability to set-up the endpoint device for communication. |
| * |
| * The lifetime of an MctpDevice instance is proportional to the existence of an |
| * MCTP-capable device in the system. If a device represented by an MctpDevice |
| * instance is removed from the system then any related MctpDevice instance must |
| * be destructed a consequence. |
| * |
| * Successful set-up of the device as an endpoint yields an MctpEndpoint |
| * instance. The lifetime of the MctpEndpoint instance produced must not exceed |
| * the lifetime of its parent MctpDevice. |
| */ |
| class MCTPDevice |
| { |
| public: |
| virtual ~MCTPDevice() = default; |
| |
| /** |
| * @brief Configure the device for MCTP communication |
| * |
| * @param added The callback to invoke once the setup process has |
| * completed. The provided error code @p ec must be |
| * checked as the request may not have succeeded. If |
| * the request was successful then @p ep contains a |
| * valid MctpEndpoint instance. |
| */ |
| virtual void |
| setup(std::function<void(const std::error_code& ec, |
| const std::shared_ptr<MCTPEndpoint>& ep)>&& |
| added) = 0; |
| |
| /** |
| * @brief Remove the device and any associated endpoint from the MCTP stack. |
| */ |
| virtual void remove() = 0; |
| |
| /** |
| * @return A formatted string representing the device in terms of its |
| * address properties. |
| */ |
| virtual std::string describe() const = 0; |
| }; |
| |
| class MCTPDDevice; |
| |
| /** |
| * @brief An implementation of MctpEndpoint in terms of the D-Bus interfaces |
| * exposed by @c mctpd. |
| * |
| * The lifetime of an MctpdEndpoint is proportional to the lifetime of the |
| * endpoint object exposed by @c mctpd. The lifecycle of @c mctpd endpoint |
| * objects is discussed here: |
| * |
| * https://github.com/CodeConstruct/mctp/pull/23/files#diff-00234f5f2543b8b9b8a419597e55121fe1cc57cf1c7e4ff9472bed83096bd28e |
| */ |
| class MCTPDEndpoint : |
| public MCTPEndpoint, |
| public std::enable_shared_from_this<MCTPDEndpoint> |
| { |
| public: |
| static std::string path(const std::shared_ptr<MCTPEndpoint>& ep); |
| |
| MCTPDEndpoint() = delete; |
| MCTPDEndpoint( |
| const std::shared_ptr<MCTPDDevice>& dev, |
| const std::shared_ptr<sdbusplus::asio::connection>& connection, |
| sdbusplus::message::object_path objpath, int network, uint8_t eid) : |
| dev(dev), connection(connection), objpath(std::move(objpath)), |
| mctp{network, eid} |
| {} |
| MCTPDEndpoint& McptdEndpoint(const MCTPDEndpoint& other) = delete; |
| MCTPDEndpoint(MCTPDEndpoint&& other) noexcept = default; |
| ~MCTPDEndpoint() override = default; |
| |
| int network() const override; |
| uint8_t eid() const override; |
| void subscribe(Event&& degraded, Event&& available, |
| Event&& removed) override; |
| void remove() override; |
| |
| std::string describe() const override; |
| |
| std::shared_ptr<MCTPDevice> device() const override; |
| |
| /** |
| * @brief Indicate the endpoint has been removed |
| * |
| * Called from the implementation of MctpdDevice for resource cleanup |
| * prior to destruction. Resource cleanup is delegated by invoking the |
| * notifyRemoved() callback. As the actions may be abitrary we avoid |
| * invoking notifyRemoved() in the destructor. |
| */ |
| void removed(); |
| |
| private: |
| std::shared_ptr<MCTPDDevice> dev; |
| std::shared_ptr<sdbusplus::asio::connection> connection; |
| sdbusplus::message::object_path objpath; |
| struct |
| { |
| int network; |
| uint8_t eid; |
| } mctp; |
| MCTPEndpoint::Event notifyAvailable; |
| MCTPEndpoint::Event notifyDegraded; |
| MCTPEndpoint::Event notifyRemoved; |
| std::optional<sdbusplus::bus::match_t> connectivityMatch; |
| |
| void onMctpEndpointChange(sdbusplus::message_t& msg); |
| void updateEndpointConnectivity(const std::string& connectivity); |
| }; |
| |
| /** |
| * @brief An implementation of MctpDevice in terms of D-Bus interfaces exposed |
| * by @c mctpd. |
| * |
| * The construction or destruction of an MctpdDevice is not required to be |
| * correlated with signals from @c mctpd. For instance, EntityManager may expose |
| * the existance of an MCTP-capable device through its usual configuration |
| * mechanisms. |
| */ |
| class MCTPDDevice : |
| public MCTPDevice, |
| public std::enable_shared_from_this<MCTPDDevice> |
| { |
| public: |
| MCTPDDevice() = delete; |
| MCTPDDevice(const std::shared_ptr<sdbusplus::asio::connection>& connection, |
| const std::string& interface, |
| const std::vector<uint8_t>& physaddr); |
| MCTPDDevice(const MCTPDDevice& other) = delete; |
| MCTPDDevice(MCTPDDevice&& other) = delete; |
| ~MCTPDDevice() override = default; |
| |
| void setup(std::function<void(const std::error_code& ec, |
| const std::shared_ptr<MCTPEndpoint>& ep)>&& |
| added) override; |
| void remove() override; |
| std::string describe() const override; |
| |
| private: |
| static void onEndpointInterfacesRemoved( |
| const std::weak_ptr<MCTPDDevice>& weak, const std::string& objpath, |
| sdbusplus::message_t& msg); |
| |
| std::shared_ptr<sdbusplus::asio::connection> connection; |
| const std::string interface; |
| const std::vector<uint8_t> physaddr; |
| std::shared_ptr<MCTPDEndpoint> endpoint; |
| std::unique_ptr<sdbusplus::bus::match_t> removeMatch; |
| |
| /** |
| * @brief Actions to perform once endpoint setup has succeeded |
| * |
| * Now that the endpoint exists two tasks remain: |
| * |
| * 1. Setup the match capturing removal of the endpoint object by mctpd |
| * 2. Invoke the callback to notify the requester that setup has completed, |
| * providing the MctpEndpoint instance associated with the MctpDevice. |
| */ |
| void finaliseEndpoint( |
| const std::string& objpath, uint8_t eid, int network, |
| std::function<void(const std::error_code& ec, |
| const std::shared_ptr<MCTPEndpoint>& ep)>& added); |
| void endpointRemoved(); |
| }; |
| |
| class I2CMCTPDDevice : public MCTPDDevice |
| { |
| public: |
| static std::optional<SensorBaseConfigMap> match(const SensorData& config); |
| static bool match(const std::set<std::string>& interfaces); |
| static std::shared_ptr<I2CMCTPDDevice> |
| from(const std::shared_ptr<sdbusplus::asio::connection>& connection, |
| const SensorBaseConfigMap& iface); |
| |
| I2CMCTPDDevice() = delete; |
| I2CMCTPDDevice( |
| const std::shared_ptr<sdbusplus::asio::connection>& connection, int bus, |
| uint8_t physaddr) : |
| MCTPDDevice(connection, interfaceFromBus(bus), {physaddr}) |
| {} |
| ~I2CMCTPDDevice() override = default; |
| |
| private: |
| static constexpr const char* configType = "MCTPI2CTarget"; |
| |
| static std::string interfaceFromBus(int bus); |
| }; |