Zum Inhalt

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_buff verwaltet, 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 über skb_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 -g inspizieren, CPU-Paketverluste in /proc/net/softnet_stat analysieren 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 den data-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 den data-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): Verschiebt data und tail vorab, 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:

# RX- und TX-Ringpuffer auf 4096 Descriptoren vergrößern
sudo ethtool -G eth0 rx 4096 tx 4096

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:

# Rohstatistiken je CPU-Kern anzeigen
cat /proc/net/softnet_stat

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:

sudo sysctl --system

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.

    Zum IPv4-Subnetting Leitfaden