- adds circuit reroute state (active/Limbo) with a grace timer, entered on
an ingress ChannelClosed fault for a reroutable circuit and torn down on
grace expiry; issues a controller-signed reroute token at circuit
creation when reroutable
- adds the takeover splice (X1): re-splices a reroutable circuit's ingress
to a new router under the circuit's mutation guard, preserving the
terminator side, advancing the iteration, and minting a fresh token
- stamps the fault reason on router-emitted ingress faults so only a
channel close is Limbo-eligible
- keeps the D3 idle scanner from prematurely reaping Limbo circuits
Implements the router-side Connect-V2 sessionless dial path. Dials are
authorized locally via the RouterDataModel instead of a controller-issued
service session token; circuit creation flows through the existing
`CreateCircuitV3` controller endpoint (#3721). Builds on the sdk-golang
v2 migration.
- Adds `processConnectV2` on `edgeClientConn`: resolves the service by id
or name via the RouterDataModel, checks dial access, and dispatches to
the controller via `sendCreateCircuitV3Msg`. Supports both
`xgEdgeForwarder` (SDK xgress) and `nonXgConnectHandler` flow-control
modes, selected by the SDK's `UseXgressToSdkHeader`.
- Makes `CircuitId` optional in `DecodeCreateCircuitV3Request`. The V2
router path does not pre-assign a circuit ID; the controller generates
it as V1/V2 already do. Without this the decoder rejected the empty
header and every V2 dial hung until timeout. Adds a regression test.
- Splits `checkAccess` to close a posture-check bypass on the V2 path.
The old single `checkAccess` short-circuited to nil for non-OIDC
sessions (V1 ran posture at the controller during `CreateSession`); V2
has no such step, so posture would have been skipped. `checkAccess` now
always runs the RDM `HasAccess` (policy + posture) check;
`checkAccessIfOidc` keeps the OIDC-only gate for the V1 and bind paths.
- Sends the V2 `state_connected` on the default (data) sender rather than
the control sender. On multi-underlay channels the two senders are
independently ordered, so an early terminator payload on the data
sender could beat `state_connected` to the SDK and be dropped (channel/v5
has no message-priority API).
- Updates `xgEdgeForwarder.lastRx` on every forward path, including the
fast `timeout == 0` `TrySend` branch used for normal payload dispatch.
The old code only updated it on the `timeout > 0` path, so active V2
circuits looked idle and could be unrouted prematurely.
- Adds `state.ConnState.ServiceId`, populated by the connect handlers from
the service session token (V1) or the request header (V2). The
non-xgress V2 path previously left this empty, so `handleDialAccessLost`
could not identify and close V2 non-xgress circuits when dial access was
revoked.
- Skips conns with no `ServiceSessionToken` in `RemoveLegacyServiceSession`;
a sessionless V2 conn's token is nil and the cleanup loop previously
dereferenced it unconditionally, which would panic the router.
- Advertises Connect-V2 via the `RouterCapabilityConnectV2` bit in the
listener hello so SDKs can detect V2 support.
- Wires `ContentTypeConnectV2` and `ContentTypeXgControl` handlers in
`Acceptor.BindChannel`, and adds `handleXgControl` for SDK-side xgress
control messages, preserving `ControlUserVal` so trace-route responses
correlate back to the initiator's `SendForReply` waiter.
- Adds `RouterDataModel.serviceNameIndex` for O(1) name->id lookup in the
V2 dial path, maintained with rename safety at the `HandleServiceEvent`
mutation points.
- Adds `tests/connect_v2_test.go` covering end-to-end V2 dataflow and the
V1 fallback (`ForceConnectV1`), asserting the dial path via the SDK
`DialEvent`.
- Propagates a V2 initiator's graceful half-close to legacy hosts via
`edgeXgressConn.FlowFromFabricToXgressClosed`, which emits an edge FIN
when the fabric->app half of the circuit closes. The SDK signals
half-close to its router xgress peer with the native xgress EOF flag;
without translating that to an edge FIN, a legacy host reading to EOF
stalled until teardown.
- Records the dialing identity id as the circuit `ClientId` for
sessionless V2 dials, since there is no dial session to key on; updates
`Test_OidcEvents` to match.
- Adds `tests/connect_v2_teardown_test.go` covering client- and
host-initiated close propagation on both the V2 and forced-V1 paths.
- Polls for the asynchronous conn close in the SDK posture-check tests
(`awaitClientConnClosed`): revocation tears the circuit down out of
band, so checking `IsClosed` immediately after the first read error was
racy.
- Temporarily pins sdk-golang/v2 to the openziti/sdk-golang#959 commit,
which carries the matching xgress conn-close-on-teardown fix the V2
posture tests depend on; to be repointed at the next sdk-golang
pre-release before merge.
For openziti/sdk-golang#936.
- moves the channel dependency to channel/v5 v5.0.10 and sdk-golang to v1.9.0 in the root and zititest modules
- mechanically rewrites every channel/v4 import path to channel/v5
This is the import-path-only step; the API-level changes the switch requires land in the following commit. This commit does not build on its own.
- adds ErrorType constants for rejected-by-application, DNS resolution failed,
port not allowed, invalid link destination, and resources not available
- adds corresponding CircuitFailureCause strings reported in circuit events
- extracts classifyDialError() in route handler to map dial errors to specific
error codes using typed errors, syscall constants, and string matching
- detects DNS errors via *net.DNSError and string fallback for ER/T hosted
services where errors are serialized through the SDK message protocol
- detects resource exhaustion via EMFILE, ENFILE, ENOBUFS syscall errors
- introduces InvalidLinkDestinationError typed error in forwarder package
- adds unit tests covering all 16 classification cases
- adds integration tests for rejected-by-application (SDK host),
DNS resolution failed, connection refused, and port not allowed
(ER/T host mode) with circuit event verification
- adds CreateEnrollAndStartTunnelerEdgeRouterWithCfgTweaks to test context
- adds CreateCircuitV3 message type and handler for routers that have
already authorized dials locally via RDM, bypassing service session
tokens in favor of identity ID, service ID, and pre-assigned circuit ID
- renames CreateCircuitRequest/Response to CreateCircuitV2Request/V2Response
for clarity now that V3 exists
- adds CircuitManager.Reserve to atomically claim circuit IDs before routing,
preventing collisions on pre-assigned IDs
- extends CreateCircuitParams with GetCircuitId so V3 can supply a
pre-assigned circuit ID (falls back to UUID generation when empty)
- fixes IsDialableByIdentity which was incorrectly calling IsBindableByIdentity
- extracts V2 handler into its own file create_circuit_v2.go
- adds CreateCircuitV3RequestType/ResponseType (20222/20223) to edge_ctrl protobuf
- registers V3 handler in controller server