MMotor OS
System

Networking

Networking lives in sys-io, on moto-netstack, the Motor OS networking stack. It is configured from one file, /system/cfg/sys-net.toml, read when sys-io starts. As of August 2026 it is considered ready for production use within its supported feature set: static IPv4 and IPv6, DHCPv4, TCP and UDP, native DNS, and fail-stop diagnostics.

Configuration

A malformed file prevents sys-io from starting. A valid file that matches no network device deliberately leaves only loopback and logs the unmatched devices. The file is an image input, so use DHCP for one reusable cloud image, or provision a distinct file into each static-address image.

Interfaces

loopback enables the built-in 127.0.0.1/8 and ::1/128 interface. auto_icmp_echo_reply controls automatic echo replies; it does not bypass the rules that suppress multicast, broadcast, and foreign-destination replies.

Each [devices.NAME] table consumes one virtio-net device. With mac, the entry selects that exact hardware address; without it, entries consume the remaining devices in table-name order. Unmatched entries and unconfigured devices are logged. A static device looks like this:

[devices.net0]
cidrs = ["192.0.2.10/24", "2001:db8::10/64"]
dns_servers = ["192.0.2.53", "2001:db8::53"]

[[devices.net0.routes]]
ip_network = "0.0.0.0/0"
gateway = "192.0.2.1"

[[devices.net0.routes]]
ip_network = "::/0"
gateway = "2001:db8::1"

dns_servers supplies resolver addresses for a static device. Each route's gateway must be reachable through a CIDR on the same device. Route selection uses the longest matching prefix and prefers a connected route over an equally specific gateway route.

For a reusable DHCPv4 image:

[devices.net0]
dhcp = true

DHCP owns the device's IPv4 address, default route, and advertised DNS servers. Static IPv4 CIDRs, routes, or DNS servers on the same device are rejected, while static IPv6 configuration may coexist. On renewal, replacement, or lease loss, sys-io updates the address and route and atomically republishes the aggregate active DNS server list in /system/cfg/libc/resolv.conf. Wildcard TCP listeners begin accepting on an address when a lease installs it and stop accepting new connections when the address disappears; established connections are not aborted only because a lease was lost, and applications must still handle the ordinary I/O failure that follows when the old address is no longer usable.

Admission limits

max_half_open_global and max_half_open_per_listener (defaults 128 and 32) bound sockets in SYN-RECEIVED. max_backlog_global and max_backlog_per_listener (defaults 128 and 32) bound the pools of listening sockets behind listeners: a pool starts at the size the program asked for, 4 by default, and doubles whenever a burst of simultaneous connections empties it, because a connection that finds no listening socket is refused rather than queued. All four must be nonzero. Each socket reserves receive and transmit rings, so large values have a direct memory cost; lower them on a small VM, raise them for a server that meets large connection bursts or many slow, distant clients.

Response rate limits

max_icmp_error_rate, max_rst_rate, and max_syn_cookie_rate (defaults 200, 200, and 1000 per second, with a one-second burst) limit, per external device, the replies that go wherever a packet's source address points: automatic ICMP errors, resets answering traffic at closed ports, and the stateless SYN|ACKs a flooded listener answers with once SYN cookies engage. That source address is the sender's to forge, so an unlimited rate would let anyone use the machine as a reflector. A suppressed reply is simply not sent; loopback is exempt. Zero is rejected; omit a key to keep its default.

What the stack supports

AreaSupportedNot supported yet
IPv4Static addresses, DHCPv4, ARP, fragmentation and reassembly, path MTU discovery, longest-prefix routing.
IPv6Static addresses and routes, neighbor discovery, fragmentation, a bounded 64-entry neighbor cache, a reduced source-address selection policy.DHCPv6, SLAAC, router advertisements, and general extension-header support.
TCPCUBIC congestion control with a 10-segment initial window; SACK; RACK-TLP loss recovery (RFC 8985); RFC 7323 timestamps and window scaling; SYN cookies under flood; keepalive; zero-window probing; TIME-WAIT retention; per-connection linger on close; family-correct wildcard listeners.SO_KEEPALIVE is always on and not yet configurable.
UDPUnicast, connected and unconnected, IPv4 and IPv6, with bounded receive queues.Multicast and broadcast.
ICMPEcho request and reply (ping), with automatic replies configurable; incoming errors are validated before they affect a flow.Raw sockets.
NamesThe DNS resolver service, a hosts file, and resolv.conf maintained by sys-io.

Socket options exposed to programs: TCP_NODELAY, TTL, SO_LINGER, receive and send buffer sizes, IPV6_V6ONLY, and shutdown of either direction. TCP buffers default to 128 KiB per direction and can be set between 16 KiB and 8 MiB. A graceful close of a connection that never sent a byte is reset rather than FIN-closed; this is an accepted non-POSIX exception.

Capacity and performance

From a program's point of view

std::net works: TcpListener, TcpStream, UdpSocket, name resolution, nonblocking mode, timeouts, and shutdown. The Motor OS ports of mio and Tokio sit on an edge-triggered readiness interface in the runtime, so Tokio and everything built on it (hyper, axum, russh) works. Programs on Motor OS get real error kinds for a reset connection; a few conditions (refused, unreachable, broken pipe) still surface as NotConnected, and giving them their own codes is on the follow-up list. A connect through std currently tries only the first resolved address.

Failure and diagnostics

sys-io owns live filesystem and networking state that cannot be reconstructed safely in a replacement process, so Motor OS uses a fail-stop policy: if sys-io exits or is killed, the kernel logs its status and halts the VM instead of attempting an unsafe partial restart.

Configure the hypervisor to retain the VM's serial console. Kernel, sys-io, sys-init, and headless service logs are emitted there, and it remains the only diagnostic channel when networking or sys-io itself has failed. For QEMU, run-qemu.sh uses -nographic, so redirect its stdout and stderr to a retained log; cloud deployments should enable their provider's serial-console capture before first boot. ss lists TCP sockets and stats reads the net.* counters (packets, drops, half-open and backlog counts, SYN cookie and suppression counters, reassembly outcomes); see Logs and diagnostics.

What is deliberately accepted

The remaining networking work, about fifty robustness, completeness, and test items, is tracked in docs/plans/networking-remaining-steps.md in the repository.