utils: zbus proxy for OpenThread Border Router D-Bus interface#457
utils: zbus proxy for OpenThread Border Router D-Bus interface#457glennswest wants to merge 2 commits into
Conversation
OpenThread's posix border router (otbr-agent) exposes a per-Thread-
interface D-Bus service at io.openthread.BorderRouter.<ifname> under
the well-known object path /io/openthread/BorderRouter/<ifname>.
Existing rs-matter Linux deployments that ship OTBR alongside the
Matter stack want to talk to it from inside the same process — get
the current Thread dataset, monitor SRP server state, watch for
attach/detach events — without shelling out to ot-ctl.
Adds rs-matter/src/utils/zbus_proxies/openthread/{,border_router.rs}:
a hand-written zbus proxy for the BorderRouter interface, sourced
from openthread's own introspect.xml at
<https://github.com/openthread/ot-br-posix>.
Only the methods the controller currently needs are proxied — the
file is structured so additional methods can land incrementally
without disturbing existing users. Gated behind the existing `zbus`
feature, no new dependency or feature added.
Test plan
---------
- cargo check -p rs-matter --no-default-features
--features='std,rustcrypto,log,os,zbus' --lib
builds clean.
- cargo clippy on the same feature set produces no openthread-related
warnings.
Use case: zman's matter controller surfaces Thread network state
(attach status, channel, PAN ID) in its admin UI by reading this
service from the OTBR co-located on the same Pi.
There was a problem hiding this comment.
Code Review
This pull request introduces a new module for OpenThread Border Router D-Bus proxies. The reviewer identified a bug where the #[proxy] macro was missing the default_service parameter, which is necessary for correct D-Bus connectivity, and suggested using an enum for the device_role property to improve type safety and robustness.
| #[proxy( | ||
| interface = "io.openthread.BorderRouter", | ||
| default_path = "/io/openthread/BorderRouter/wpan0" | ||
| )] |
There was a problem hiding this comment.
The #[proxy] macro uses the interface name as the default D-Bus service name if default_service is not specified. In this case, it would default to io.openthread.BorderRouter.
However, the OpenThread D-Bus service is named io.openthread.BorderRouter.<ifname>, which for the hardcoded wpan0 interface would be io.openthread.BorderRouter.wpan0. Without specifying the correct default_service, attempts to use this proxy with default settings will fail to connect.
Please add the default_service to the #[proxy] attribute.
#[proxy(
interface = "io.openthread.BorderRouter",
default_service = "io.openthread.BorderRouter.wpan0",
default_path = "/io/openthread/BorderRouter/wpan0"
)]| #[zbus(property)] | ||
| fn device_role(&self) -> zbus::Result<String>; |
There was a problem hiding this comment.
The device_role property returns a string, but the set of possible values is finite. To improve type safety and make the API more robust, consider defining an enum for the device role. zbus can automatically handle the conversion from a D-Bus string.
You could define an enum like this, for example, above the BorderRouter trait:
use serde::{Deserialize, Serialize};
use zbus::zvariant;
#[derive(Debug, Clone, PartialEq, Eq, zvariant::Type, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[zvariant(signature = "s")]
pub enum DeviceRole {
Disabled,
Detached,
Child,
Router,
Leader,
}Then, you can change the property in the trait to use this enum:
#[zbus(property)]
fn device_role(&self) -> zbus::Result<DeviceRole>;This change will prevent bugs related to typos in role strings and make the code that uses this proxy cleaner.
|
PR #457: Size comparison from da2d79e to 1614abf Full report (8 builds for (core), dimmable-light, onoff-light, onoff-light-bt, speaker)
|
|
@glennswest there is no point in opening new PRs if the previous ones are not finished, as nothing would ever be merged. Please check my feedback in your previous PRs. |
…derRouter.wpan0 Addresses Gemini review (project-chip#457): #[proxy] had default_path set but not default_service, so the proxy defaulted the bus name to the interface name (io.openthread.BorderRouter) instead of the actual openthread daemon service name (io.openthread.BorderRouter.<ifname>). Hardcoding wpan0 matches the hardcoded default_path; multi-interface support can come as a follow-up (constructor that takes ifname + builds both names). Not addressed: the medium-priority device_role enum suggestion. The set of values is documented in the property's doc comment and the call sites match on strings today; converting to a typed enum is a worthwhile follow-up but not a correctness fix.
|
PR #457: Size comparison from da2d79e to 251f789 Increases above 0.2%:
Full report (8 builds for (core), dimmable-light, onoff-light, onoff-light-bt, speaker)
|
|
Closing in favor of #472 |
Similar to #457 (and the justification for #457 is actually good!) but also: - The full dBus API, not just "what currently the controller needs" - Not sure who is "the controller", but "a" controller might need other APIs too - We try to expose the full API in all zbus proxies anyway - Copyright headers in the rs-matter format, not shortened. Why are they shortened?!?! - A promise to assess the Gemini code review feedback
Summary
OpenThread's posix border router (
otbr-agent) exposes a per-Thread-interface D-Bus service atio.openthread.BorderRouter.<ifname>(typicallywpan0) under/io/openthread/BorderRouter/<ifname>.Linux rs-matter deployments that ship OTBR alongside Matter often want to talk to it from inside the same process — read the current Thread dataset, monitor SRP-server state, observe attach/detach — without shelling out to
ot-ctl. This PR adds a hand-writtenzbusproxy for that interface.What's in
rs-matter/src/utils/zbus_proxies/openthread.rs— module root.rs-matter/src/utils/zbus_proxies/openthread/border_router.rs—#[proxy]-generated trait for the BorderRouter interface, sourced from openthread's own introspect.xml.Only the methods the controller currently needs are proxied. The file is structured so additional methods can land incrementally without disturbing existing users.
Feature gating
Gated behind the existing
zbusfeature — no new feature, no new dependency.Test plan
cargo check -p rs-matter --no-default-features --features 'std,rustcrypto,log,os,zbus' --lib— clean.cargo clippyon the same feature set — no warnings on the new module.cargo xtask copyright check— clean.cargo fmt -- --check— clean.Use case
zman's matter controller (deployed on a Pi running OTBR) reads Thread network state (attach status, channel, PAN ID, dataset) directly via this proxy for its admin UI's Border Router status card, instead of shell-execing
ot-ctl.