Post

How Linux Handles Networking

How Linux Handles Networking

How Linux Actually Handles Networking

Linux doesn’t do “one way.” It does all the ways, simultaneously, and leaves you to figure out who’s in charge. If you’ve ever wondered why your interface comes up with a random IP or why NetworkManager keeps rewriting your static config, welcome to the jungle.


What Is a Network Framework?

When we say network framework in Linux, we’re not talking about a single neat API. We’re talking about the scaffolding that sits between you and the kernel, which is the only thing that really moves packets.

Let’s start from the bottom and work upward.


1. The Kernel: The Only Thing That Actually Moves Packets

The Linux kernel is the core networking engine. It owns:

  • Interface drivers (physical and virtual)
  • IP addressing and routing tables
  • Neighbor tables (ARP, NDP)
  • Netfilter (firewall/NAT)
  • Traffic control (tc)

All network configuration ultimately lives here. When you add an IP, a route, or a VLAN, you’re really just updating kernel state — there’s no config file, no database, just in-memory tables.

The kernel doesn’t care how those tables got populated. It doesn’t parse YAML or INI files. It just maintains data structures that define what exists.


Netlink is the protocol that connects user space to the kernel’s networking subsystem. Every configuration change you make — no matter which tool you use — becomes a Netlink message under the hood.

Example:

1
ip addr add 192.168.10.10/24 dev eth0

That doesn’t “write” to /etc/network/interfaces or any file. It sends a Netlink request to the kernel asking to bind an address object to eth0.

Every modern tool — NetworkManager, systemd-networkd, netplan, even old ifupdown — uses Netlink to communicate with the kernel. That’s the glue holding this ecosystem together.


3. User Space: The Chaos Layer

Above Netlink sits the part you actually touch — the user-space frameworks. Each one tries to make network configuration easier, which usually means different syntax and another daemon.

Roughly speaking:

  • Low-level tools: ip, ss, tc, bridge — direct Netlink access, no middleman.
  • Mid-level daemons: systemd-networkd, NetworkManager, ifupdown — read configs and manage interfaces persistently.
  • Declarative frontends: Netplan, ifcfg — wrappers that generate config for those daemons.

Each exists because someone decided the previous one was “too complicated,” and then built something worse.


4. How It All Ties Together

Here’s the real flow of how your command becomes a packet:

  1. You edit a config file (/etc/netplan/01-eth.yaml, /etc/network/interfaces, etc.)
  2. A framework parses that file (netplan, networkd, NetworkManager, etc.)
  3. That framework’s daemon sends Netlink messages to the kernel
  4. The kernel updates its interface, routing, and neighbor tables
  5. Packets start flowing

That’s it. Human → Text → Daemon → Netlink → Kernel. Every framework is just another way of expressing step 2.


5. Why You Should Care

Because when something breaks, you need to know who’s actually at fault.

  • If ip addr shows the wrong IP, the kernel’s state is wrong.
  • If your manual config keeps disappearing, a daemon overwrote it.
  • If routes exist but packets vanish, the kernel is doing what it was told — the higher layers lied.

Knowing which layer owns what will save you hours of chasing ghosts that don’t exist.


The 10,000-Foot View: The Stack in Motion

At the end of the day, everything ends up in the same kernel tables. Linux networking isn’t a single stack — it’s a democracy of competing frameworks all claiming to represent the same truth.

Now that you understand the anatomy, let’s break down the main contenders — the ones you’ll actually work with.


/etc/network/interfaces:

This is where it all began on Debian and early Ubuntu. No daemons, no abstractions, no YAML — just text files and predictable behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto eth0.10
iface eth0.10 inet static
    address 192.168.10.10/24
    gateway 192.168.10.1
    vlan-raw-device eth0

auto br0
iface br0 inet static
    address 10.10.0.2/24
    bridge_ports eth1 eth2
    bridge_stp off

You bring it up with ifup and down with ifdown. No magic. No race conditions. It either works or it doesn’t.

Use it when: You want static, minimal, and deterministic networking — like on routers, appliances, or lab boxes that should never surprise you.


Netplan: The Modern YAML Layer

Ubuntu eventually decided everything needed YAML. Enter Netplan — a declarative front-end that translates YAML into config for either systemd-networkd or NetworkManager, depending on which renderer you choose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
network:
  version: 2
  renderer: networkd
  ethernets:
    ens160:
      dhcp4: no
  vlans:
    vlan10:
      id: 10
      link: ens160
      addresses: [192.168.10.10/24]
      gateway4: 192.168.10.1
  bridges:
    br0:
      interfaces: [ens161]
      addresses: [10.10.0.2/24]
      mtu: 9000

It’s clean, predictable — and one typo away from losing your SSH session. Netplan doesn’t touch the kernel directly; it just feeds your YAML to its chosen backend.


systemd-networkd:

systemd-networkd doesn’t care about YAML or pretty formatting. It’s an INI-style service that configures interfaces directly through Netlink at boot.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# /etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
VLAN=vlan10
Bridge=br0

# /etc/systemd/network/20-vlan10.netdev
[NetDev]
Name=vlan10
Kind=vlan
[VLAN]
Id=10

# /etc/systemd/network/50-br0.network
[Match]
Name=br0
[Network]
Address=10.10.0.2/24

It reads config files and updates the kernel state directly.


NetworkManager:

It wants to manage everything — Ethernet, Wi-Fi, VPNs, bridges, bonds, DNS, and your sanity.

1
2
3
4
5
6
7
8
nmcli con add type ethernet ifname eth0 \
  ipv4.addresses 192.168.1.10/24 ipv4.gateway 192.168.1.1 ipv4.method manual

nmcli con add type vlan ifname eth0.20 dev eth0 id 20 \
  ipv4.addresses 192.168.20.10/24 ipv4.gateway 192.168.20.1 ipv4.method manual

nmcli con add type bridge ifname br0 ipv4.addresses 10.10.0.2/24 ipv4.method manual
nmcli con add type bridge-slave ifname eth1 master br0

It’s a daemon talking to D-Bus talking to Netlink. On a desktop, that’s great. On a headless server, it’s asking for trouble.


The ifcfg Era: RHEL’s Old School

CentOS and RHEL 7 relied on /etc/sysconfig/network-scripts/ifcfg-* files. They were eventually replaced by NetworkManager keyfiles — but they linger in legacy environments.

1
2
3
4
5
6
7
8
9
10
11
12
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=none

# VLAN example
DEVICE=vlan10
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.10.10
PREFIX=24
GATEWAY=192.168.10.1
VLAN=yes

Use it when: You’re stuck supporting old infrastructure. Otherwise, don’t.


iproute2: The Bare Metal Interface

Everything else you’ve seen ultimately calls this. iproute2 is the real interface to the kernel — a set of tools that talk to Netlink directly.

1
2
3
4
5
6
7
8
ip link add link eth0 name eth0.10 type vlan id 10
ip addr add 192.168.10.10/24 dev eth0.10
ip link set eth0.10 up

ip link add name br0 type bridge
ip link set eth1 master br0
ip addr add 10.10.0.2/24 dev br0
ip link set br0 up

This is the truth. No daemons, no layers, no translation. If ip shows it, the kernel knows it. If it’s missing, everything above it is lying.

Use it when: You’re debugging, scripting, or building automation that shouldn’t depend on a daemon’s opinion.


Closing Thought (Just one):

Every one of these frameworks manipulates the same kernel through Netlink. They just wrap it differently.

This post is licensed under CC BY 4.0 by the author.