Skip to content

Networking and data planes

A SpaceOS service can use four separate paths for data, called planes. Commands use a fifth path. A service must declare each path before SpaceOS connects it. Traffic on one path cannot be treated as traffic from another.

A SpaceOS service uses separate IP, frame-bus, bulk-data, and supervision planes, each with its own policy boundary.

PlaneCarriesAddressed byProtected by
IP LANOrdinary application traffic between servicesIP address and portDefault-deny policy in space-net, keyed by service identity
Frame busTelemetry, telecommand, events, parameters, data productsCCSDS APID, for sorting streams onlysend_to allow-list keyed by service identity
Bulk data linkHigh-throughput payload dataAn explicitly granted device or memory ringBroker-enforced bounds (direction, rate, memory)
Supervision pageHeartbeat, mission time, health, safe-modeA dedicated shared page per serviceEach field has exactly one writer; the host end belongs to space-runner

Configure and check a route

Declare each service interface in build.yaml:

partitions:
payload:
services:
- name: classifier
image: ghcr.io/<your-org>/classifier:1
runtime: oci
isolation: runc
interfaces:
- type: ip
bridges: [payload-net]
- type: frame_bus
apids: [0x120, 0x12F]
send_to: [ground]
- type: data_link
link: sensor-input
mbps: 200
mode: read
- type: supervision_page

Set the frame route and its queue limits in run.yaml:

partitions:
payload:
memory: 512
apids: [0x120, 0x12F]
send_to: [ground]
relay:
from: payload
to: [ground]
limits:
rate: 1000
burst: 64
queue_depth: 256
drop_policy: drop-new

Validate the route before booting:

Terminal window
space run payload:dev --runtime run.yaml --dry-run

After boot, inspect the applied routes and counters:

Terminal window
space report --json
space stats classifier

The report lists each granted interface. The counters show admitted frames, rate-limited frames, queue depth, and dropped frames by policy.

Decide which services may connect

The signed release lists the peers that each service may reach. space-net rejects every route not on that list. A route between projects must appear in both projects’ releases. The rule follows the project and service name, so changing or spoofing an IP address does not change access.

An APID is the 11-bit CCSDS number that labels a telemetry or command stream. Receivers use it to sort messages. SpaceOS still checks the sending service and its allowed destinations before forwarding a message.

Service IP network

A service’s ordinary networking is a standard IP LAN. The service binds ports on its declared bridges. A bridge is a named virtual network segment, the on-board equivalent of a Docker network: services that declare the same bridge can address each other on it, and a service that declares none has no IP neighbors. Bridge names such as payload-net are yours to choose, and they must match between build.yaml and run.yaml.

space-net assigns addresses on each bridge and forwards only the connections listed in the signed release. It also applies each service’s rate, burst, and queue limits.

Application packets do not pass through dom0. If space-net stops, networking stops and SpaceOS restarts that service. space-net cannot read another service’s memory or keys. The runner checks declared TCP and HTTP health endpoints and restarts only the service whose check fails.

Frame bus

Telemetry and command traffic travels as fixed 256-byte frames (the space-wire Msg format) carrying telemetry, telecommand, events, parameters, data products, health, and logs. Every telemetry source is a peer on this bus: it publishes frames by APID, and consumers subscribe by the APIDs they own, with space-net as the switch admitting each frame under the sender’s send_to allow-list.

The external flight computer is a peer too, reached over the mission’s physical bus. So is a flight simulator: it is attached at deploy time and is indistinguishable to consumers from the flight peer it stands in for. Ground twin tests therefore exercise the same consumer interfaces as flight.

The relay

One partition on the frame bus is the relay: the partition whose frames are carried to and from ground. relay.from names it, relay.to names the destinations its frames reach, and the reserved name ground means the ground link rather than another partition. The relay is bidirectional, so telecommands travel back from any destination to the from partition. Mission telemetry from sensors and services enters a partition and crosses to ground through that single relay point under a rate limit and a bounded queue.

If a one-partition composition omits the relay block, the first declared partition relays to the remaining partitions and to ground. Declare the block explicitly once the topology is part of the mission design.

Supervision shared memory

Each service shares one small memory page with the host, carrying a guest heartbeat, host acknowledgement, mission time, a health string, and the safe-mode command word. A wedged guest cannot send a frame, but a stalled counter on the page remains visible. Reading mission time costs a memory load rather than a message round-trip. The separate page also prevents a congested frame bus from forging health or suppressing safe-mode.

Liveness signals drive how the runner escalates: a service that is alive but no longer responding is isolated and restarted; a dead tender process is restarted with backoff; a faulted control plane drives itself to safe mode; a hung board is reset by the hardware watchdog. Each step contains the failure to the smallest boundary that explains it.

The link between a node and its ground endpoint is layered, and each layer has one job:

  • CFDP Class 2, the acknowledged mode of the CCSDS file-transfer protocol, owns object transfer: releases, signed commands, telemetry batches, and results have stable identities, and CFDP handles segmentation, retransmission, and resume across contact windows.
  • BPv7, the delay-tolerant bundle protocol, routes those objects across intermittent links; nodes store and forward according to contact plans.
  • BPSec, its security extension, protects each project’s objects end to end: integrity always, confidentiality when an intermediary is not trusted with the plaintext.
  • SDLS protects each data link hop with symmetric session keys, established and rotated through ML-KEM and over-the-air rekeying; space-secret alone turns a key identifier into key bytes.

The transport operator (relay, ground station, mission-ops network) sits inside the SDLS boundary but outside the BPSec boundary. It routes and rate-limits; it cannot read or forge project payloads. SDLS secures the pipe; BPSec secures the contents.

Approve commands separately from network access

A network connection does not permit a command. Local CLI commands use a private Unix socket and the operating system checks the caller. A command sent from ground includes its target, action, limits, sequence number, and expiration. The mission command key signs those fields. The node rejects a wrong signature, an expired command, or a repeated sequence number.

Know who can read payload data

BPSec encrypts payload data between the project and its destination. A relay or ground station can move that data but cannot read it. On a standard hypervisor, the target operator can inspect guest memory. Keeping data secret from that operator requires hardware the operator cannot read into: confidential-execution silicon that encrypts guest memory against the host, combined with key release conditional on an attestation of what is running.