Skip to content

Support for Recover method on bridged endpoints #149

Open

Description

@jk-ozlabs

Currently, a Recover invocation will attempt a Get Endpoint ID (to check endpoint connectivity), but will do so using a physical addressing:

	/*
	 * Test if we still have connectivity to the endpoint. If we do, we will get a
	 * response reporting the current EID. This is the test recommended by 8.17.6
	 * of DSP0236 v1.3.1.
	 */
	rc = query_get_endpoint_id(ctx, &peer->phys, &peer->recovery.eid,
				   &peer->recovery.endpoint_type,
				   &peer->recovery.medium_spec, /*peer=*/NULL);

The NULL peer causes the physical addressing there.

Since we cannot target bridged endpoints with a phys address, we will need to use vanilla EID addressing for those.

Activity

  1. self-assigned this
    on Mar 30, 2026
  2. faizana-nvidia commented on Jul 27, 2026

    @faizana-nvidia
    Contributor

    Hello @jk-ozlabs

    I too was looking for this, if you still haven't picked it up as your current working item, I'll be happy to push a change.

  3. jk-ozlabs commented on Jul 28, 2026

    @jk-ozlabs
    MemberAuthor

    @faizana-nvidia sure, if you want to look at this!

    I'd suggest working out a plan here before writing the implementation though, there are some design points for the recovery flow that we would need to sort out too. Mainly:

    • we'll probably want to check connectivity to the bridge too
    • we'll need to handle cases where the EID has been reassigned by the downstream bus owner (ie, has a new UUID), by generating a remove & re-add.
  4. faizana-nvidia commented on Jul 28, 2026

    @faizana-nvidia
    Contributor

    great! let me update here with the flow

  5. faizana-nvidia commented on Aug 13, 2026

    @faizana-nvidia
    Contributor

    Downstream Endpoint Recovery Flow

    method_endpoint_recover (D-Bus entry point) — unchanged for both peer types

    flowchart TD
        A([method_endpoint_recover called]) --> B{peer->degraded?}
        B -- yes --> Z([no-op, return OK])
        B -- no --> C["set recovery.npolls, recovery.delay\nschedule peer_endpoint_recover timer\npeer->degraded = true\nemit Connectivity changed"]
        C --> D([return — common for direct and downstream peers])
    
    Loading

    peer_endpoint_recover (timer callback) — downstream branch inserted after physical probe

    flowchart TD
        TIMER([timer fires: peer_endpoint_recover]) --> DEC[Decrement recovery.npolls]
    
        DEC --> PHYS["[EXISTING — unchanged]\nPhysical probe\nquery_get_endpoint_id\n  dest=peer->phys, peer=NULL\n  → for direct: tests the device\n  → for downstream: tests the bridge\nstores result in recovery.eid"]
    
        PHYS --> PHYSOK{responded?}
        PHYSOK -- no --> RESCHED
    
        PHYSOK -- yes --> BRIDGE["[NEW]\nfind_bridge_for_peer:\nscan peers for p where\n  p.pool_size > 0\n  && match_phys(p.phys, peer.phys)\n  && p.pool_start <= peer.eid\n       < p.pool_start + p.pool_size"]
    
        BRIDGE --> ISBRIDGE{downstream\npeer?}
    
        %% ── DOWNSTREAM BRANCH (new) ──────────────────────────────
        ISBRIDGE -- "yes\n(bridge found)" --> EIDRP["[NEW — downstream only]\nEID-routed probe\nquery_get_endpoint_id\n  dest=peer->phys, peer=peer\n  → routed through bridge to device\noverwrites recovery.eid with\ndownstream device's EID"]
    
        EIDRP --> EIDOK{responded?}
        EIDOK -- no --> RESCHED
    
        EIDOK -- yes --> UUIDQ["[NEW — downstream only]\nUUID via EID routing\nquery_get_peer_uuid_by_eid\n  → gets downstream device UUID\n  not the bridge UUID"]
    
        UUIDQ --> UUIDOK{UUID query\nsucceeded?}
        UUIDOK -- no --> RECLAIM
    
        UUIDOK -- yes --> UUIDMATCH{UUID matches\npeer->uuid?}
    
        UUIDMATCH -- "yes — same device" --> EIDMATCH{recovery.eid\n== peer->eid?}
        EIDMATCH -- yes --> SUCCESS
        EIDMATCH -- "no — EID drifted\nbridge is bus owner,\ncannot send Set Endpoint ID" --> RECLAIM
    
        UUIDMATCH -- "no or nil UUID\nnew device at this EID" --> READD["[NEW — downstream only]\nBridge re-assigned EID to new device\n\nsave phys / eid / net\nremove_peer old  → emits EndpointRemoved\nadd_peer eid, net, allow_bridged=true\nsetup_added_peer new  → emits EndpointAdded"]
        READD --> DONE([return])
    
        %% ── DIRECT ENDPOINT BRANCH (existing, unchanged) ─────────
        ISBRIDGE -- "no\n(direct endpoint)" --> DIRECT["[EXISTING — unchanged]\nif recovery.eid != peer->eid:\n  query_get_peer_uuid_by_phys\n  UUID mismatch → remove_peer\n                  + endpoint_assign_eid\n  UUID match    → endpoint_send_set_endpoint_id\n                  + change_peer_eid"]
        DIRECT --> SUCCESS
    
        %% ── SHARED SUCCESS PATH (existing, unchanged) ────────────
        SUCCESS(["[EXISTING — unchanged]\npeer->degraded = false\nemit Connectivity changed\nunref recovery.source\nzero recovery.delay / npolls"])
    
        %% ── SHARED RESCHEDULE / RECLAIM (existing, unchanged) ────
        RESCHED{recovery.npolls > 0?}
        RESCHED -- yes --> RETRY[reschedule timer\nat recovery.delay]
        RESCHED -- no --> RECLAIM
        RECLAIM([reclaim: remove_peer])
    
    Loading

  6. faizana-nvidia commented on Aug 13, 2026

    @faizana-nvidia
    Contributor

    Updating the flow here, will create PR for the same if this flow looks okay.

  7. amboar commented on Oct 1, 2026

    @amboar
    Contributor

    I find that mermaid diagram tricky to comprehend. A text description may help.

  8. faizana-nvidia commented on Oct 1, 2026

    @faizana-nvidia
    Contributor

    I find that mermaid diagram tricky to comprehend. A text description may help.

    yeah its outdated now, flow has changed a bit based on review discussion on #175

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions