D-Bus interfaces can be defined by creating a YAML file to describe the methods, properties, and signals they contain. From this YAML file, both documentation and binding code may be generated.
An interface YAML may have the following sections:
- description
- A small documentation section describing the purpose of the interface.
- methods
- A list of methods provided by this D-Bus interface.
- properties
- A list of properties provided by this D-Bus interface.
- signals
- A list of signals generated by this D-Bus interface.
- enumerations
- A list of enumerations defined by this D-Bus interface.
- paths
- A list of D-Bus paths where this D-Bus interface will be implemented.
- service_names
- A default service name or a list of service names which can host this D-Bus interface.
A common problem we have found with D-Bus interfaces is having a consistent way to define enumerations. Two common practices are to either assign special meaning to integers, as a C compiler might do, or to have specific strings representing the enumeration name. The D-Bus API design guidelines specify both of these options:
For APIs being used in constrained situations, enumerated values should be transmitted as unsigned integers. For APIs which need to be extended by third parties or which are used in more loosely coupled systems, enumerated values should be strings in some defined format.
What we have done in sdbus++
is to consider enumerations as a first-class
type. Within an interface you can define an enumeration and the bindings will
have a C++ enumeration defined for it. At a D-Bus level any property or method
parameter will be a string, but the string will contain a fully-qualified name
"interface.enum-name.enum-value" like "org.freedesktop.Example.Color.Red".
Within the generated bindings, an automatic conversion is done between strings
and C++ enumeration values and clients will get an
"xyz.openbmc_project.sdbusplus.Error.InvalidEnumString" error response if they
attempt to use an invalid string value.
An enumeration must have the YAML properties name
and values
and may
optionally contain a description
. The name
is a word corresponding to the
desired "enum-name" portion of the fully-qualified name and the resulting C++
enum type. The values
are a list of enumeration values each containing their
own name
and optional description
.
Example:
enumerations:
- name: Suits
description: >
The suits found in a deck of cards.
values:
- name: Diamonds
- name: Hearts
- name: Clubs
description: >
This is the suit that looks like a clover.
- name: Spades
Types are identified in YAML using their typename found in the D-Bus
specification, but listed using lowercases: int64
instead of
INT64
or C++ int64_t
.
byte
boolean
int16
uint16
- ...
uint64
size
- maps to the Csize_t
for the architecture.ssize
- maps to the Cssize_t
for the architecture.double
unixfd
string
object_path
signature
Note: The special value identifiers are all case-insensitive.
For floating-point types it is possible to express one of the special values:
NaN
- A quiet-type not-a-number value.Infinity
: A positive infinity value.-Infinity
: A negative infinity value.Epsilon
: An epsilon value.
For integer types it is possible to express one of the special values:
minint
- The minimum value the integer type can hold.maxint
- The maximum value the integer type can hold.
Container types can also be expressed, but the contained-type should be
expressed within square-brackets []
. The following containers are supported:
array[type]
- C++ type is
std::vector
- C++ type is
dict[keytype, valuetype]
- C++ type is
std::map
- C++ type is
set[type]
- C++ type is
std::set
- C++ type is
struct[type0, type1, ...]
- C++ type is
std::tuple
- C++ type is
variant[type0, type1, ...]
- C++ type is
std::variant
- C++ type is
It may seem odd that variants are required to list the types they may contain, but this is due to C++ being a strongly-typed language. In order to generate bindings, to read from and append to a message, the binding generator must know all possible types the variant may contain.
Enumerations are expressed like a container, but the contained-type is an
identifier of the fully-qualified enum-name or a shortened self.
identifier
for locally defined types.
- enum[org.freedesktop.Example.Suits]
- enum[self.Suits]
A method must have the YAML property name
and may optionally have
parameters
, returns
, flags
, errors
, and description
. Each parameter
must have a name
, type
, and optional description
. Each return must have a
type
and may optionally have a name
and description
. Flags are a list of
sd-bus vtable flags; the supported values are deprecated
, hidden
,
unprivileged
and no_reply
, which corresponds to SD_BUS_VTABLE_DEPRECATED
,
SD_BUS_VTABLE_HIDDEN
, SD_BUS_VTABLE_UNPRIVILEGED
,
SD_BUS_VTABLE_METHOD_NO_REPLY
, respectively. Errors are a list of
fully-qualified or shortened self.
identifiers for errors the method may
return, which must be defined in a corresponding errors YAML file.
Example:
methods:
- name: Shuffle
flags:
- unprivileged
errors:
- self.Error.TooTired
- name: Deal
description: >
Deals a new hand to each player.
errors:
- self.Error.OutOfCards
- name: LookAtTop
returns:
- name: Card
type: struct[enum[self.Suit], byte]
- name: MoveToTop
flags:
- deprecated
- no_reply
parameters:
- name: Card
type: struct[enum[self.Suit], byte]
A property must have the YAML property name
and type
and may optionally have
description
, flags
, default
, and errors
. The default
defines the
default value of the property. See the Methods
section above for more
information on errors.
The supported values for flags
are and their equivalent sd-bus flag setting:
deprecated
- SD_BUS_VTABLE_DEPRECATEDhidden
- SD_BUS_VTABLE_HIDDENunprivileged
- SD_BUS_VTABLE_UNPRIVILEGEDconst
- SD_BUS_VTABLE_PROPERTY_CONSTemits_change
- SD_BUS_VTABLE_PROPERTY_EMITS_CHANGEemits_invalidation
- SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATIONexplicit
- SD_BUS_VTABLE_PROPERTY_EXPLICITreadonly
- (N/A)
If no flag is given, a property will default to emits_change
.
Both const
and readonly
prevent D-Bus clients from being able to write to a
property. const
is a D-Bus indication that the property can never change,
while readonly
properties can be changed by the D-Bus server itself. As
examples, the Version
property on a software object might be appropriate to be
const
and the Value
property on a sensor object would likely be readonly
.
Example:
properties:
- name: CardsRemaining
type: uint32
default: 52
flags:
- const
description: >
The number of cards remaining in the deck.
errors:
- self.Error.InvalidNumber
A signal must have the YAML property name
and may optionally have a
description
and list of properties
. Properties are specified the same as
interface properties.
Example:
signals:
- name: Shuffled
description: >
The deck has been shuffled.
- name: Cheated
properties:
- name: CardToTop
type: struct[enum[self.Suit], byte]
A path must have the YAML property name
& value
and may optionally have a
description
and segments
. Each segments
entry must have the YAML property
name
& value
and may optionally have a description
& nested segments
.
Example:
paths:
- name: CardGames
description: >
The root path for the card games.
value: /xyz/openbmc_project/card_games
segments:
- name: BlackJack
description: >
The relative path for the black jack game.
value: black_jack
- name: Rummy
description: >
The relative path for the rummy game.
value: rummy
A common approach is to have a single path which is used as a root of all
instances, which is often documented as a "namespace". For convenience, this can
be represented with a single namespace
value. If the interface is intended to
be used as a singleton at a specific object path, similarly the instance
value
can be used.
Example:
paths:
- namespace: /xyz/openbmc_project/decks
description: >
The root path for all decks.
- instance: /xyz/openbmc_projects/decks/standard
description: >
The root path for a standard deck of cards.
An interface can be implemented either by a single service or multiple services.
A singleton host service name must have the YAML property default
and may
optionally have a description
. xyz.openbmc_project.ObjectMapper
is one such
example.
Example:
service_names:
default: xyz.openbmc_project.deck
description: >
The service name for the card deck manager.
A multiton host service name must have the YAML property name
& value
and
may optionally have a description
.
Example:
service_names:
- name: BlackJack
description: >
The service name for the Back Jack game manager.
value: xyz.openbmc_project.black_jack
- name: Rummy
description: >
The service name for rummy game manager.
value: xyz.openbmc_project.rummy