blob: 770fcb63fc49803f4ef53b7a08ce85c559b2f83b [file] [log] [blame]
#pragma once
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/bus/match.hpp>
#include <sdbusplus/message.hpp>
#include <sdbusplus/message/native_types.hpp>
#include <cstdint>
/**
* @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 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)>;
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 Configures the Maximum Transmission Unit (MTU) for the route to
* the endpoint
*
* @param mtu The route MTU to be used for the endpoint. Note that MTU
* value refers to the size of the entire MCTP packet. The value
* provided is interpreted as accounting for the MCTP header.
*
* @param completed The callback to invoke once the MTU configuration has
* completed. The provided error code must be checked as
* the request may not have succeeded.
*/
virtual void
setMtu(uint32_t mtu,
std::function<void(const std::error_code& ec)>&& completed) = 0;
/**
* @brief Remove the endpoint from its associated network
*/
virtual void remove() = 0;
/**
* @brief Request that the MCTP layer attempt to recover communication with
* an unresponsive endpoint.
*
* Recovery progress is indicated by invocation of the @c degraded,
* @c available and @c removed handlers registered using the @c events()
* API.
*/
virtual void recover() = 0;
/**
* @return A formatted string representing the endpoint in terms of its
* address properties
*/
virtual std::string describe() 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 action 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)>&&
action) = 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;
};
/**
* @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:
MctpdEndpoint() = delete;
MctpdEndpoint(
const std::shared_ptr<MctpDevice>& device,
const std::shared_ptr<sdbusplus::asio::connection>& connection,
sdbusplus::message::object_path objpath, int network, uint8_t 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 setMtu(
uint32_t mtu,
std::function<void(const std::error_code& ec)>&& completed) override;
void recover() override;
void remove() override;
std::string describe() 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<MctpDevice> device;
std::shared_ptr<sdbusplus::asio::connection> connection;
sdbusplus::message::object_path objpath;
struct
{
int network;
uint8_t eid;
} mctp;
Event notifyAvailable;
Event notifyDegraded;
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)>&&
action) override;
void remove() override;
std::string describe() const override = 0;
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;
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)>&& action);
void endpointRemoved();
};
/**
* @brief A specialisation of MctpdDevice for SMBus devices
*
* Abstracts over the implementation details of specifying SMBus device address
* parameters to @c mctpd.
*/
class SmbusMctpdDevice : public MctpdDevice
{
public:
SmbusMctpdDevice() = delete;
SmbusMctpdDevice(
const std::shared_ptr<sdbusplus::asio::connection>& connection,
int smbus, uint8_t smdev);
SmbusMctpdDevice(const SmbusMctpdDevice& other) = delete;
SmbusMctpdDevice(SmbusMctpdDevice&& other) = delete;
~SmbusMctpdDevice() override = default;
std::string describe() const override;
private:
const int smbus;
const uint8_t smdev;
};