Skip to main content

Control API v1alpha1

Diagram showing the Control API v1alpha1 local socket model from routerd main sockets and managed daemon sockets to status, events, commands, resource phases, and local-only client contracts

routerd and its managed daemons expose a local HTTP+JSON API over Unix domain sockets. The API is not for remote management — it is the channel through which routerctl, the routerd controllers themselves, and operations scripts on the same host read state.

routerd main process

routerd serve listens on:

/run/routerd/routerd.sock
/run/routerd/routerd-status.sock

The main control socket is intended for privileged local clients and exposes mutating endpoints such as apply and delete. The read-only status socket exposes only status-style endpoints and is safe for regular users to query.

Read endpoints on the main control socket expose status, events, and resource state. Highlights:

Method and pathPurpose
GET /api/control.routerd.net/v1alpha1/statusrouterd's own status
GET /api/control.routerd.net/v1alpha1/connectionslive connections from conntrack or pf state
GET /api/control.routerd.net/v1alpha1/dns-queriesDNS query history
GET /api/control.routerd.net/v1alpha1/traffic-flowstraffic flow history
GET /api/control.routerd.net/v1alpha1/firewall-logsfirewall log entries

Controller status

Status.status.controllers and the Controllers endpoint include both the configured controller mode and runtime reconcile state. Runtime fields include interval, lastTrigger, lastReconcileTime, nextReconcileTime, reconcileCount, reconcileErrorCount, consecutiveErrorCount, currentError, lastDuration, maxDuration, averageDuration, lastError, lastErrorTime, and lastErrorClearedAt. reconcileErrorCount is cumulative; use currentError and consecutiveErrorCount to decide whether the controller is failing now. These fields are observational; clients should tolerate them being absent before a controller has run.

Managed daemons

Stateful daemons each have their own socket:

/run/routerd/dhcpv6-client/wan-pd.sock
/run/routerd/dhcpv4-client/wan.sock
/run/routerd/pppoe-client/wan-pppoe.sock
/run/routerd/healthcheck/internet.sock

On FreeBSD, the equivalent path is /var/run/routerd/....

Common daemon endpoints

Method and pathPurpose
GET /v1/healthzLiveness check
GET /v1/statusDaemon status and related resource state
GET /v1/eventsEvent log; supports since, wait, topic query parameters
POST /v1/commands/reloadRe-read configuration
POST /v1/commands/renewDaemon-specific active operation (DHCPv6 Renew, DHCPv4 lease refresh, immediate health probe, etc.)
POST /v1/commands/stopGraceful shutdown

The semantics of renew differ per daemon: DHCPv6 sends a Renew, DHCPv4 refreshes the lease, healthcheck triggers an immediate probe.

Phase vocabulary

ResourceStatus.phase uses a shared vocabulary across resources:

PhaseMeaning
PendingWaiting for required input
BoundA lease (DHCP, etc.) is held
AppliedHost-side state has been applied
UpA tunnel or link is up
InstalledRoutes or configuration files are installed
HealthyHealth check meets its success threshold
UnhealthyHealth check meets its failure threshold
ErrorAn operation failed

Each phase carries a conditions array. Decisions in client code should be based on phase and conditions, not on log strings.

Events

Events have a topic and attributes:

{
"topic": "routerd.dhcpv6.client.prefix.renewed",
"attributes": {
"resource.kind": "DHCPv6PrefixDelegation",
"resource.name": "wan-pd"
}
}

routerd persists events into SQLite. Managed daemons additionally keep them in their own events.jsonl files. EventRule and DerivedEvent consume this stream to emit virtual events.