Repository navigation
Conversation
… length, not a fixed /24 The locator preference from #866 compared the first three octets, so a peer on a network wider than a /24 (the issue's host had its Wi-Fi on 10.5.15.154/17) with a different third octet fell back to the first announced locator, the original #865 bug in a narrower form. - rtps core: isSameSubnetAddress() / isSameSubnet() take a prefix length (default 24, the previous behaviour); prefixLengthFromNetmask() converts a dotted-quad mask. The participant carries the local prefix length (DomainConfig::local_prefix_length -> Participant::reuse()), and every selection site uses it: SEDP topic data, the CycloneDDS default-locator fallback, the SPDP locator lists and the metatraffic selection. The SPDP multicast lists skip the on-network replacement, which never applied to them. - Facade: RtpsParticipant::Config::interface_netmask ("255.255.128.0" or "17"). Empty: the netmask of the interface that owns interface_address on the host (getifaddrs / GetAdaptersAddresses, auto-detected or configured address alike), a /24 on ESP targets. - Ethernet::netmask() and ethernet_netmask() on the Ethernet boards so applications can pass the netif's mask; the rtps and esp32-p4-function-ev-board examples do. - Python: RtpsParticipant.Config(interface_netmask=...). - pc/tests/rtps_locator_subnet: prefix-length checks and /17 SEDP + SPDP selection cases next to the existing /24 ones. No wire-format change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open issues
What changed in this PR
Updates RTPS “same subnet” locator selection to use the interface’s actual prefix length (CIDR) instead of assuming a fixed /24, improving correctness on networks like /17 and other non-/24 subnets.
Changes:
- Add prefix-length aware subnet checks (
isSameSubnetAddress,isSameSubnet) and netmask→prefix conversion. - Thread the local prefix length through participant/domain/discovery selection paths (SEDP/SPDP/metatraffic).
- Expose
interface_netmaskin the facade (C++/Python) and surface Ethernet netmask on ESP boards + update examples/tests.
| File | Description |
|---|---|
| pc/tests/rtps_locator_subnet.cpp | Expands tests to cover prefix-length behavior (/16, /17, /32, /0) and netmask conversion. |
| lib/python_bindings/rtps_bindings.cpp | Adds interface_netmask to Python config/init and forwards into Rtps::Config. |
| components/rtps/src/rtps_participant.cpp | Implements interface netmask parsing + host netmask detection and passes computed prefix length into Domain config. |
| components/rtps/src/entities/Participant.cpp | Stores and reuses local prefix length in Participant instances. |
| components/rtps/src/entities/Domain.cpp | Passes domain-configured prefix length into participant reuse. |
| components/rtps/src/discovery/TopicData.cpp | Makes SEDP unicast locator preference prefix-length aware. |
| components/rtps/src/discovery/SPDPAgent.cpp | Uses participant prefix length when selecting on-subnet metatraffic locator. |
| components/rtps/src/discovery/SEDPAgent.cpp | Uses participant prefix length when selecting on-subnet endpoint locators and parsing TopicData. |
| components/rtps/src/discovery/ParticipantProxyData.cpp | Uses prefix length in list replacement logic; prevents multicast lists from using on-network replacement. |
| components/rtps/include/rtps_participant.hpp | Adds interface_netmask to facade config and updates interface resolution API. |
| components/rtps/include/rtps/entities/Participant.hpp | Adds participant field for local prefix length and updates reuse signature. |
| components/rtps/include/rtps/entities/Domain.hpp | Adds local_prefix_length to DomainConfig. |
| components/rtps/include/rtps/discovery/TopicData.hpp | Updates readFromBuffer API to accept optional prefix length. |
| components/rtps/include/rtps/discovery/ParticipantProxyData.hpp | Documents and updates locator-list reading API to include prefix length. |
| components/rtps/include/rtps/common/Locator.hpp | Introduces DEFAULT_SUBNET_PREFIX_LENGTH, prefix-aware subnet checks, and netmask→prefix conversion. |
| components/rtps/example/main/rtps_example.cpp | Passes Ethernet netmask into RtpsParticipant config on ESP example. |
| components/rtps/README.md | Documents interface_netmask behavior and recommendations for ESP targets. |
| components/ethernet/src/ethernet.cpp | Tracks netmask alongside IP and resets it on link/IP changes. |
| components/ethernet/include/ethernet.hpp | Exposes Ethernet::netmask() and stores netmask atomically. |
| components/esp32-p4-module-dev-kit/include/esp32-p4-module-dev-kit.hpp | Adds ethernet_netmask() helper. |
| components/esp32-p4-function-ev-board/include/esp32-p4-function-ev-board.hpp | Adds ethernet_netmask() helper. |
| components/esp32-p4-function-ev-board/example/main/esp32_p4_function_ev_board_example.cpp | Fetches netmask and passes it to RTPS participant config. |
| components/esp32-p4-eth/include/esp32-p4-eth.hpp | Adds ethernet_netmask() helper. |
| components/esp32-ethernet-kit/include/esp32-ethernet-kit.hpp | Adds ethernet_netmask() helper. |
Review effort: Lite
| bool parse_netmask(const std::string &text, uint8_t &prefix_length) { | ||
| unsigned a = 0, b = 0, c = 0, d = 0; | ||
| if (std::sscanf(text.c_str(), "%u.%u.%u.%u", &a, &b, &c, &d) == 4) { | ||
| if (a > 255 || b > 255 || c > 255 || d > 255) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Done in 9fbb686: the dotted-quad parse now uses a %c sentinel and only accepts exactly four conversions, so "255.255.255.0foo" is rejected (and "17" already used the same sentinel).
| logger_.debug("No netmask known for {}; assuming a /{} network (set interface_netmask)", addr, | ||
| prefix_length); | ||
| } | ||
| logger_.info("Interface {}/{}", addr, prefix_length); |
There was a problem hiding this comment.
Done in 9fbb686: the auto-detected address is logged at INFO only where auto-detection happens (host, as before this PR); the per-start "Interface a.b.c.d/n" line is now DEBUG, so an explicitly configured address adds no INFO output.
|
|
||
| bool check_spdp() { | ||
| // 3. Fill each list with off-subnet locators, then announce the on-subnet one. | ||
| bool isSameSameSubnetClamp() { |
There was a problem hiding this comment.
Renamed to isSameSubnetPrefixClamp() in 9fbb686, with a comment on what it checks.
- parse_netmask(): a dotted quad with trailing characters
("255.255.255.0foo") is rejected (a %c sentinel must not match).
- resolve_interface(): the auto-detected address is logged at INFO
where it is found (host blocks only, as before); the per-start
"Interface a.b.c.d/n" line is DEBUG. ESP targets share the
empty-address error with the host instead of an early return, which
also removes the duplicate / always-false auto_detect conditions
cppcheck reported on the ESP configuration.
- Windows adapter cursor is a pointer to const.
- Test helper renamed isSameSubnetPrefixClamp().
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU


Summary
Follow-up to #866 / #865. The same-subnet locator preference compared the first three octets, i.e. it assumed every network is a /24. The issue's own host had its Wi-Fi on
10.5.15.154/17: a board on that network with a different third octet would have fallen back to the first announced locator, the original bug in a narrower form.rtpscore:isSameSubnetAddress()/isSameSubnet()take a prefix length (default 24, the previous behaviour; clamped to 32, 0 matches everything);prefixLengthFromNetmask()converts a dotted-quad mask (non-contiguous masks are rejected). The participant carriesm_localPrefixLength, set throughDomainConfig::local_prefix_lengthandParticipant::reuse(), and every selection site fix(rtps): prefer the peer's unicast locator on our subnet; correct the GAP length #866 added (SEDP topic data, the CycloneDDS default-locator fallback, the SPDP locator lists) plus the existing metatraffic selection use it. The SPDP multicast lists no longer go through the on-network replacement, which never applied to them.RtpsParticipant::Config::interface_netmask("255.255.128.0"or"17"). Empty means: on the host, the netmask of the interface that ownsinterface_address(read fromgetifaddrs/GetAdaptersAddresses, for an auto-detected and for an explicitly configured address alike); on ESP targets, a /24 with a debug log. An invalid value failsstart().Ethernet::netmask()andethernet_netmask()on the four Ethernet boards, so an application can pass the netif's mask next to its IP; thertpsandesp32-p4-function-ev-boardexamples do.RtpsParticipant.Config(interface_netmask=...)(keyword, appended last so positional callers are unaffected).pc/tests/rtps_locator_subnetgains the prefix-length checks (explicit /16, /17, /32, /0, clamp, netmask conversion) and /17 SEDP + SPDP selection cases, alongside the existing /24 ones.No wire-format change.
Test plan
rtps_locator_subnet(new checks),rtps_golden,rtps_sedp_dedicated_locator,rtps_pubsubpass against the installed librarycomponents/rtps/examplebuilds for esp32 (IDF 6.1, component manager off)components/esp32-p4-function-ev-board/examplebuilds for esp32p4 (IDF 6.1)ESPP_BUILD_PYTHON=ONbuilds (binding compiles)🤖 Generated with Claude Code
https://claude.ai/code/session_01DFjjnq3XCTRAXENSxsCxJU