Ubuntu’s networking stack has evolved into a layered, declarative model that emphasizes consistency across server, desktop, cloud, and embedded variants. At the center is Netplan, introduced in Ubuntu 17.10 and made default in 18.04, which acts as the unified configuration layer. Below it sit two primary renderers (backends): systemd-networkd (default on servers) and NetworkManager (default on desktops since ~23.10 with bidirectional integration). At the lowest level, the Linux kernel exposes network interfaces via netlink and sysfs.
This article explains the architecture, data flow, renderer differences, and how they interact with kernel primitives in Ubuntu 24.04 LTS through 25.10+ (as of 2026).
1. Layered Architecture Overview
Layer Component Role Config Location Typical Use Case
Configuration Netplan Declarative YAML parser & backend generator /etc/netplan/*.yaml All Ubuntu variants
Renderer / Manager systemd-networkd Lightweight, systemd-integrated daemon Generated in /run/systemd/network/ Servers, cloud, headless
Renderer / Manager NetworkManager Dynamic, policy-driven manager with GUI/CLI/DBUS Generated in /run/NetworkManager/ Desktops, laptops, Wi-Fi
Kernel Interface netdev + rtnetlink Device registration, IP config, routing, tc, etc. sysfs /sys/class/net/, netlink All
Netplan is not a network daemon — it is a generator that translates YAML into renderer-specific configs during boot or on netplan apply. It runs once per change and exits.
2. Netplan: The Single Source of Truth
Netplan reads YAML files from /etc/netplan/ (processed in lexical order, higher numbers override lower).
Key structure (version 2 is current and stable):
YAML
network: version: 2renderer: networkd# or NetworkManager
ethernets: enp3s0: dhcp4: trueoptional: true# don't wait for this link at boot
bridges: br0: interfaces: [enp3s0, enp4s0] addresses: [192.168.1.10/24] gateway4: 192.168.1.1 nameservers: addresses: [8.8.8.8, 1.1.1.1] wifis: wlan0: access-points: "MySSID": password: "secret" dhcp4: trueWorkflow:
- netplan generate → parses YAML, validates, writes backend files to /run/
- netplan apply → generate + apply (restarts renderer if needed)
- netplan try → safe apply with 120s rollback
Since Ubuntu 23.10 (and polished in 24.04+), NetworkManager uses libnetplan as its backend on desktop. Changes via nmcli or GUI are written back to Netplan YAML → bidirectional sync. On servers, renderer remains networkd by default.
3. Renderer Comparison: systemd-networkd vs NetworkManager
Feature / Aspect systemd-networkd NetworkManager
Default on Ubuntu Server / cloud images Desktop (since 23.10 full integration)
Resource footprint Very low (~few MB RAM) Higher (GUI/DBUS/policy engine)
Boot-time dependency Tight systemd integration Can delay boot if waiting for connections
Dynamic changes Static config; needs restart for changes Excellent (Wi-Fi roaming, VPN, hotspots, 802.1x)
Wi-Fi support Basic (needs wpa_supplicant integration) Native, full-featured (WPA3, regulatory domain)
CLI tool networkctl nmcli / nmtui
GUI None GNOME Settings / plasma-nm / etc.
Policy / Dispatcher networkd-dispatcher (script hooks) Dispatcher scripts + DBUS events
Cloud-init compatibility Excellent (native) Good, but less common on servers
SR-IOV, VRF, WireGuard, VXLAN Full kernel-level support Good, but some advanced features lag
systemd-networkd excels in predictable, headless environments — no DBUS, no polkit, fast boot.
NetworkManager shines where networks are dynamic (laptops, Wi-Fi-heavy desktops).
4. Kernel Interfaces: The Foundation
Both renderers ultimately configure the kernel via rtnetlink (netlink socket family AF_NETLINK / RTNETLINK).
Key kernel abstractions:
- Interfaces — /sys/class/net/<ifname> (eth0, enp3s0, wlp2s0, br0, vlan10, wg0…)
- Permanent MAC: used by Netplan for stable matching (match.macaddress)
- IP configuration — ip addr add, ip route add (via rtnetlink)
- Routing tables — Main + custom tables (VRF uses separate tables)
- tc (traffic control) → qdisc, classes, filters (Netplan supports basic offload)
- nftables / iptables — Firewalling (separate from IP config)
- ethtool — Offloads, ring sizes, link settings
Netplan → renderer → libudev + rtnetlink → kernel.
Example flow for static IP on enp3s0:
- Netplan YAML → renderer config
- systemd-networkd → sets IP via rtnetlink
- Kernel → assigns to interface, updates neigh table, routes
5. Practical Internals & Troubleshooting
- Check active renderer: cat /etc/netplan/*.yaml | grep renderer or networkctl status vs nmcli device status
- See generated files: ls /run/systemd/network/ or /run/NetworkManager/system-connections/
- Debug application order: systemd-analyze critical-chain network-pre.target (networkd) or journalctl -u NetworkManager
- Switch renderer (server → desktop style): Edit YAML to renderer: NetworkManager, then: sudo apt install network-managersudo netplan generate && sudo netplan apply
- Advanced: Match by permanent MAC (stable across VF renames):
YAML
match: macaddress: 00:16:17:aa:bb:ccset-name: lan0Summary: Mental Model (2026 Perspective)
- Netplan = declarative YAML front-end → single source of truth
- Renderer = backend executor (networkd for servers, NetworkManager for desktops)
- Kernel = ultimate enforcer via rtnetlink / sysfs
This design gives Ubuntu excellent consistency: the same YAML works across cloud images, bare-metal servers, and desktops (with renderer swapped). It reduces cognitive load for admins managing hybrid fleets while preserving each renderer’s strengths.
For production servers, stick with networkd + Netplan — predictable, lightweight, and deeply integrated with systemd. For workstations or Wi-Fi-heavy use, let NetworkManager take the reins via Netplan’s bidirectional bridge.
Mastering this stack means treating /etc/netplan/ as the canonical config location and using netplan generate –debug liberally when things go sideways.