Outcall
SpecificationsS001 · Bridge Management

Functional requirements

S001 Functional Requirements

Bridge lifecycle

S001-FR-001 [P1] outcalld MUST create the bridge interface via netlink using the rtnetlink crate. It MUST NOT shell out to ip or brctl.

S001-FR-002 [P1] Bridge creation MUST be idempotent. If the bridge already exists, outcalld MUST attach to it and reuse its interface index.

S001-FR-003 [P1] After creation or attach, outcalld MUST bring the bridge interface up (link state UP).

nftables base ruleset

S001-FR-004 [P1] outcalld MUST apply a base nftables ruleset to the inet outcall table with a forward chain.

S001-FR-005 [P1] The base ruleset MUST enforce a default-BLOCK policy: all forwarded traffic entering or leaving the bridge interface MUST be dropped unless explicitly allowed.

S001-FR-006 [P1] The base ruleset MUST accept packets in established or related connection tracking states, so responses to allowed outbound connections can return.

S001-FR-007 [P1] The nftables chain policy MUST be accept (not drop) so that forwarded traffic on interfaces unrelated to the bridge is not affected.

S001-FR-008 [P1] Before applying rules, outcalld MUST delete any existing inet outcall table (clean-slate). Deletion failure (table does not exist) MUST be silently ignored.

Teardown

S001-FR-009 [P1] Teardown MUST execute in this order: S001-FR-009.a Delete the inet outcall nftables table (warn on failure, do not abort). S001-FR-009.b Bring the bridge interface down. S001-FR-009.c Delete the bridge interface via netlink.

S001-FR-010 [P1] When outcalld receives SIGINT (Ctrl-C) or SIGTERM, it MUST execute the teardown sequence before exiting.

Status

S001-FR-011 [P1] The status query MUST perform a fresh check every call: S001-FR-011.a Query netlink for the bridge interface existence. S001-FR-011.b Run nft list table inet outcall to check if the nftables table is active. S001-FR-011.c Return bridge name, up/down state, interface index, and nftables active flag.

Configuration

S001-FR-012 [P1] The bridge name MUST be configurable via outcalld --bridge <name>.

S001-FR-013 [P1] The default bridge name MUST be outcall0, defined as DEFAULT_BRIDGE_NAME in outcall-api.

Daemon integration

S001-FR-014 [P1] The bridge endpoints MUST be served on the host unix socket via axum: S001-FR-014.a GET /api/v1/bridge — status S001-FR-014.b POST /api/v1/bridge/up — initialize S001-FR-014.c POST /api/v1/bridge/down — teardown

S001-FR-015 [P1] The outcall CLI MUST provide bridge status, bridge up, and bridge down subcommands that talk to the host API.

S001-FR-016 [P1] The bridge module and API module MUST be gated with #[cfg(target_os = "linux")]. On non-Linux platforms, outcalld MUST log a warning and skip bridge initialization.

S001-FR-017 [P1] Bridge management MUST run as a Tokio task within the outcalld process. The BridgeManager MUST be shared via Arc<Mutex<BridgeManager>> between the API handlers and the main task.

Observability

S001-FR-018 [P1] All bridge operations (create, attach, up, rules applied, teardown) MUST emit structured log events via the tracing crate.

S001-FR-019 [P1] Bridge errors MUST use typed error variants (BridgeError) via thiserror: S001-FR-019.a Connection — netlink connection failure S001-FR-019.b Operation — bridge link operations (create, up, down, delete) S001-FR-019.c Nftables — nft command failures

Host socket lifecycle

S001-FR-020 [P1] outcalld MUST accept a --socket <path> flag for the host API socket path (default: /run/outcall/host.sock, defined as DEFAULT_HOST_SOCKET in outcall-api).

S001-FR-021 [P1] On startup, outcalld MUST create the parent directory of the socket path if it does not exist (create_dir_all).

S001-FR-022 [P1] On startup, outcalld MUST remove any stale socket file at the configured path before binding. Removal failure (file does not exist) MUST be silently ignored.

S001-FR-023 [P1] outcalld MUST bind a tokio::net::UnixListener at the socket path and serve the axum router over it.

S001-FR-024 [P1] On shutdown, outcalld MUST remove the socket file after teardown completes.

CLI transport

S001-FR-025 [P1] The outcall CLI MUST communicate with outcalld by sending raw HTTP/1.0 requests over the unix socket and reading the full response after the server closes the connection.

S001-FR-026 [P1] The CLI MUST use synchronous std::os::unix::net::UnixStream (not Tokio). The CLI does not require an async runtime.

S001-FR-027 [P1] The CLI MUST accept a global --socket <path> flag (default: DEFAULT_HOST_SOCKET) to locate the daemon socket.

S001-FR-028 [P1] If the socket is not reachable, the CLI MUST print cannot connect to outcalld at <path> — is it running? to stderr and exit with code 1.

On this page