Skip to content

Drop the route record on any network status route failure - #96

Merged
puddly merged 1 commit into
zigpy:devfrom
t3hk0d3:fix/forget-route-record-on-link-failure
Nov 13, 2026
Merged

puddly merged 1 commit into
zigpy:devfrom
t3hk0d3:fix/forget-route-record-on-link-failure

Conversation

@t3hk0d3

@t3hk0d3 t3hk0d3 commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Problem

handle_network_status handled LinkFailure, LegacyLinkFailure and LegacyNoRouteAvailable by removing only the routing table entry. The route record was dropped only for SourceRouteFailure. Because route_to prefers the route record, later sends to that destination kept using the stale path until a new route record replaced it or the stack restarted.

We hit this with a direct (relay-less) route record for a router that had moved. The coordinator's transmission was MAC-acked by another device, so handle_unicast_send_failure never ran. The only failure signal was the LinkFailure network status, and every toggle failed until a restart.

Change

  • Routing::forget_route_to(destination) removes both the routing table entry and the route record, and returns whether a record was removed.
  • handle_network_status uses it for all four route-failure statuses, so the next send falls back to route discovery.
  • Unit tests in routing.rs cover direct and source-route records, the routing entry, and leaving other destinations untouched.

Testing

  • cargo test -p ziggurat-zigbee -p ziggurat-driver
  • cargo clippy -p ziggurat-zigbee -p ziggurat-driver --all-targets -- -D warnings -Dclippy::all -Dclippy::nursery
  • cargo fmt --all --check

The driver-side wiring has no unit test.

🤖 Generated with Claude Code

A relay reporting LinkFailure, LegacyLinkFailure or LegacyNoRouteAvailable
for a destination removed the routing table entry but kept its route
record; only SourceRouteFailure dropped the record. Since route_to prefers
the record, every later send to that destination took the same dead path
until the record was replaced or the stack restarted.

This happens when the concentrator's own transmission succeeds but the
next device cannot forward it, e.g. a direct (relay-less) record for a
router that moved out of range while another device still acks the frame.

Routing::forget_route_to now drops both the route and the record, and
handle_network_status uses it for every route failure status, so the next
send falls back to route discovery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@puddly
puddly merged commit 2c7157e into zigpy:dev Nov 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants