Linux-Kernel TCP/IP-Architektur: Paketfluss, Socket-Buffer (sk_buff) & NAPI-Polling
Erstellt: 08.11.2026 · Zuletzt aktualisiert: 08.11.2026 · Nejat Hakan
Management Summary: Jedes Netzwerkpaket, das einen Linux-Server erreicht oder verlässt, durchläuft das Netzwerk-Subsystem des Linux-Kernels. Für ein professionelles Systems Engineering genügt kein theoretisches Lehrbuchwissen: Entscheidend ist das Verständnis, wie physische Ethernet-Frames via Direct Memory Access (DMA) in Ringpuffer des Kernels gelangen, über die Datenstruktur
struct sk_buffverwaltet, mittels NAPI-SoftIRQs lastoptimiert abgearbeitet und an die POSIX-Socket-Warteschlangen im User-Space übergeben werden.
-
Kernel-Datenstrukturen
Die Anatomie von
struct sk_buff: Zero-Copy-Pufferverwaltung im Kernel-RAM überskb_push,skb_pull, Headroom- und Tailroom-Zeiger. -
Interrupts & NAPI-Polling
Der Übergang von physischen Hardware-Interrupts (Hard-IRQ) zu SoftIRQ-Polling-Schleifen (
NET_RX_SOFTIRQ), um Interrupt-Stürme bei 10G/40G-Lasten zu verhindern. -
Vom Kabel zum Socket
Verfolge eingehende Frames durch L2-Treiberverifikation, L3-IP-Routing und Netfilter-Hooks bis hin zur L4-TCP-Segmentzusammensetzung und Socket-Pufferung.
-
Kernel-Diagnose & Tuning
Hardware-Ringpuffer mit
ethtool -ginspizieren, CPU-Paketverluste in/proc/net/softnet_statanalysieren und Backlog-Warteschlangen optimieren.
1. Das pragmatische 4-Schichten-Kernelmodell vs. OSI-Theorie
Während in der Fachliteratur oft das theoretische 7-Schichten-OSI-Modell gelehrt wird, implementiert der Linux-Kernel in der Praxis das schlankere 4-Schichten-TCP/IP-Modell.
%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
L7["Schicht 7: Anwendung<br/>Nginx, SSHd, Daemons<br/>POSIX-Socket Deskriptor"]
L4["Schicht 4: Transport<br/>TCP/UDP Zustandsautomat<br/>sk_receive & sk_write"]
L3["Schicht 3: IP / Routing<br/>Netfilter & Routing<br/>Header-Parsing, TTL"]
L2["Schicht 2/1: Link & PHY<br/>Treiber, DMA-Ringpuffer<br/>Hard-IRQ & SoftIRQ"]
L7 <-->|"sys_sendto / recvfrom"| L4
L4 <-->|"Header modifiziert"| L3
L3 <-->|"Routing & MAC-Lookup"| L2
Referenztabelle der Kernel-Komponenten
| TCP/IP-Schicht | Protokolldateneinheit (PDU) | Kernel-Subsystem & Kernfunktionen | Zentrale Diagnosewerkzeuge |
|---|---|---|---|
| Anwendung | Nutzdaten (Payload) | POSIX VFS Sockets (sys_read, sys_write, epoll) |
ss -tulpne, lsof -i |
| Transport | TCP-Segment / UDP-Datagramm | tcp_v4_rcv(), udp_rcv(), TCP-Staukontrolle (CUBIC/BBR) |
ss -ti, cat /proc/net/tcp |
| Vermittlung (IP) | IP-Paket | ip_rcv(), Netfilter (NF_INET_PRE_ROUTING), ip_forward() |
ip route get, nft list ruleset |
| Sicherung (Link) | Ethernet-Frame | NIC-Treiber (e1000e, virtio_net), napi_gro_receive() |
ethtool -S eth0, ip -s link |
2. Kernel-Speicherarchitektur: struct sk_buff
Das Herzstück des Linux-Netzwerkstacks ist die Datenstruktur struct sk_buff (definiert in <linux/skbuff.h>). Um Durchsätze von vielen Gigabit pro Sekunde zu gewährleisten, kopiert der Kernel niemals die Nutzdaten eines Pakets hin und her. Stattdessen verschiebt er lediglich Speicherzeiger innerhalb eines zusammenhängenden Puffers:
+-----------------------------------------------------------------------+
| struct sk_buff Kontrollstruktur (Metadaten, Zeiger, Interface-Ref) |
+-----------------------------------------------------------------------+
| | | |
v v v v
head data tail end
+----------------+------------------+----------------+
| Headroom | Paket-Nutzdaten | Tailroom |
| (Reserviert | (Header + User- | (Reserviert |
| für L2/L3/L4 | Anwendungs- | für Protokoll|
| Header) | Daten) | Trailer) |
+----------------+------------------+----------------+
Zero-Copy Zeiger-Operationen
skb_push(skb, len): Verschiebt dendata-Zeiger nach links in den Headroom. Wird beim Senden (Egress) verwendet, wenn Schicht 4 den TCP-Header und Schicht 3 den IP-Header voranstellt.skb_pull(skb, len): Verschiebt dendata-Zeiger nach rechts. Wird beim Empfangen (Ingress) genutzt, um Header schichtweise abzustreifen, bevor die Daten an den User-Space übergeben werden.skb_reserve(skb, len): Verschiebtdataundtailvorab, um ausreichend Headroom für Protokoll-Header freizuhalten.
Performance-Vorteil des Zero-Copy-Designs
Da Header lediglich durch das Inkrementieren oder Dekrementieren von Speicheradressen (data und tail) hinzugefügt oder entfernt werden, benötigt der Linux-Kernel keine zeitaufwendigen Speicherallokationen (kmalloc) oder Kopieroperationen (memcpy) pro Protokollschicht.
3. Der Ingress-Paketfluss: Vom Kabel zum Socket
Das Verständnis des Paketpfads von der physischen Netzwerkleitung bis zum Anwendungsprozess ist die Grundlage für jede professionelle Fehleranalyse:
%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
A["Ethernet-Kabel / Glasfaser"] --> B["NIC Controller (PHY/MAC)"]
B --> C["DMA-Transfer in Host-RAM<br/>RX-Ringpuffer"]
C --> D["Hard-IRQ<br/>NIC meldet CPU-Kern"]
D --> E["NAPI-Scheduling<br/>Setzt NET_RX_SOFTIRQ"]
E --> F["ksoftirqd Poll-Schleife<br/>Treiber holt Frames"]
F --> G["L2: napi_gro_receive()<br/>GRO aggregiert Pakete"]
G --> H["L3: ip_rcv()<br/>Netfilter & Routing"]
H --> I["L4: tcp_v4_rcv()<br/>TCP-Zustandsautomat"]
I --> J["POSIX-Socketpuffer<br/>sk_receive_queue"]
J --> K["User-Space Prozess<br/>epoll & recvfrom()"]
Die Schlüsselrolle von NAPI (New API) & SoftIRQs
Bei hohen Übertragungsraten (z. B. 10 Gbit/s und Millionen Paketen pro Sekunde) würde ein Hardware-Interrupt pro Paket das System lahmlegen (Interrupt Storm / Livelock), da die CPU nur noch mit Kontextwechseln beschäftigt wäre.
Linux löst dieses Problem durch NAPI (New API):
1. Das erste ankommende Paket löst einen Hard-IRQ aus.
2. Der Interrupt-Handler schaltet weitere Hardware-Interrupts für diese Queue vorübergehend stumm und meldet einen SoftIRQ (NET_RX_SOFTIRQ) an.
3. Der Kernel-Dämon ksoftirqd startet eine Polling-Schleife und leert den DMA-Ringpuffer in festen Batches (Standard-Budget: meist 300 Pakete).
4. Erst wenn der Puffer vollständig geleert ist, werden die Hardware-Interrupts wieder scharf geschaltet.
4. Kernel-Inspektion & Tuning in der Praxis
1. Hardware-Ringpuffer der Netzwerkkarte prüfen
Prüfe, ob deine Netzwerkkarte unter Last Pakete verwirft, weil der Ringpuffer zu klein dimensioniert ist:
# Aktuelle und maximale Puffergrößen anzeigen
sudo ethtool -g eth0
# Beispielausgabe:
# Ring parameters for eth0:
# Pre-set maximums:
# RX: 4096
# TX: 4096
# Current hardware settings:
# RX: 512
# TX: 512
Wenn unter Last Paketverluste (rx_dropped) auftreten, passe den Puffer an das Hardware-Maximum an:
2. SoftIRQ-Statistiken und CPU-Verluste überwachen
Der Kernel führt Statistiken zur Paketverarbeitung in /proc/net/softnet_stat. Jede Zeile repräsentiert einen CPU-Kern:
Bedeutung der Spalten:
* Spalte 1 (total_frames): Gesamtzahl der vom CPU-Kern verarbeiteten Netzwerkframes.
* Spalte 2 (dropped_frames): Verworfene Frames, weil die Backlog-Warteschlange net.core.netdev_max_backlog vollgelaufen ist.
* Spalte 3 (time_squeeze): Häufigkeit, mit der die NAPI-Polling-Schleife ihr Budget (net.core.netdev_budget) aufgebraucht hat, obwohl noch Pakete im Puffer warteten.
# Lesbare Auswertung via AWK
awk '{printf "CPU %2d: Verarbeitet=%10d Verwurfe=%6d Squeezed=%6d\n", NR-1, "0x"$1, "0x"$2, "0x"$3}' /proc/net/softnet_stat
3. Backlog-Puffer über sysctl anpassen
Steigen die Werte in Spalte 2 oder 3 an, vergrößere die Puffer über /etc/sysctl.d/99-network-performance.conf:
# Datei: /etc/sysctl.d/99-network-performance.conf
# Maximale Anzahl an Paketen im Eingangs-Backlog des Kernels
net.core.netdev_max_backlog = 16384
# Maximales NAPI-Paket-Budget pro Polling-Zyklus
net.core.netdev_budget = 600
# Maximale Verweildauer (in Mikrosekunden) in einem NAPI-Polling-Zyklus
net.core.netdev_budget_usecs = 4000
Sofort ohne Neustart aktivieren:
5. Nächste Schritte
Mit dem soliden Verständnis des Kernel-Paketflusses und der sk_buff-Speicherarchitektur geht es im nächsten Schritt an die exakte Adressierung und Netzwerkgrenzen:
-
IPv4-CIDR-Subnetting & Adressierung
VLSM-Subnetzberechnung, RFC-1918-Grenzregeln und Host-Kalkulationstabellen für den Systemalltag.