Skip to content

BackoffDialPolicy cannot (re)establish a grouped channel: never sets IsFirstGroupConnection #250

Description

@plorenz

Problem

BackoffDialPolicy.Dial (the only DialPolicy implementation shipped) builds its connect headers with TypeHeader, ConnectionIdHeader, GroupSecretHeader, and IsGroupedHeader, but never sets IsFirstGroupConnection.

A MultiListener only creates a new channel for a grouped underlay when IsFirstGroupConnection is set; otherwise, if no channel already exists for the connection id, it closes the underlay (multi_listener.go, the !isFirst branch). So BackoffDialPolicy can only ever add an underlay to an already-established group. It cannot:

  • establish the first underlay of a group, or
  • recover a channel that is configured to survive full underlay loss (Min: 0 / MinTotalUnderlays: 0) and re-dial.

The DialPolicy interface gives the policy no way to know a dial is a first/re-establishment dial, even though the channel core knows it (in dialUnderlay, total underlay count == 0).

This blocks migrating ziti's control channel and link (xlink) dialers, which in v4 set IsFirstGroupConnection (and rotate the group id) on first connection and after full loss.

Proposed fix

  1. Add a first-connection signal to the DialPolicy contract:
    Dial(underlayType, connectionId string, groupSecret []byte, isFirst bool, connectTimeout, cancel) (Underlay, error).
    The channel core computes isFirst in dialUnderlay (total underlay count == 0) and passes it.
  2. BackoffDialPolicy honors it: when isFirst, set IsFirstGroupConnection=true and derive a fresh iteration-suffixed connection id (matching v4's groupId-N scheme, which avoids attaching to a still-closing listener-side channel during the loss/reconnect race); otherwise reuse the current iteration id with no header.

AcceptUnderlay validates by group secret (not connection id), so an iterated wire id is safe for the local channel; the divergence between the channel's fixed local id and the iterated wire id is cosmetic (logging only).

This is a breaking change to the DialPolicy interface, but BackoffDialPolicy is the only implementer today, so the cost is minimal and best paid before downstream consumers write policies against the current (incomplete) signature.

Metadata

Metadata

Assignees

No one assigned

    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