Reise eines IPv4 Paketes durch den Linux Kernel

Empfängt die Netzwerkkarte einen Ethernet Frame mit passender MAC Adresse[*], so schreibt sie den Inhalt in einen Puffer und löst einen Interrupt aus. Eine vom Kartentreiber registrierte Funktion wird vom Kernel Interrupt-Handler aufgerufen und führt dann folgende Aktionen mit abgeschalteten Interrupts durch:

Die netif_rx() Funktion bereitet den Kernel auf die weitere Verarbeitung des Pakets vor, indem die sk_buff Struktur in die Liste[*] eingehender Pakete hinzugefügt wird und ein NET_RX Softirq gesetzt wird.
Softirqs werden bearbeitet, wenn entweder ein Hardware-Interrupt bearbeitet wurde, ein System-Call aufgerufen wurde oder der Kernel-Scheduler neu Prozessorzeit vergibt.

War ein NET_RX Softirq gesetzt, so wird die Funktion net_rx_action() aufgerufen. Diese Funktion entnimmt einen sk_buff aus der Paketliste und prüft in den zwei Listen, ptype_all und ptype_base, ob sie dem Paket entsprechende Protokoll-Handler enthalten.
Protokoll Handler registrieren sich zusammen mit einer neuen Adressfamilie beim Systemstart oder durch Hinzufügen von Kernelmodulen. Sie spezifizieren einen Zeiger auf eine Funktion, die das ankommende Paket weiter behandeln soll. Im Falle von IPv4 ist das ip_rcv().

Die Funktion ip_rcv() überprüft zuerst, ob das Paket tatsächlich für diesen Host bestimmt ist. Dies ist nur dann der Fall, sich die Netzwerkkarte im ,,promiscous Mode`` befindet. Sind Paket-Header und Checksumme in Ordnung, durchläuft das Paket den ersten Netfilter Hook (NF_IP_PRE_ROUTING) und wird dann in ip_rcv_finish() weiter untersucht. Hier wird zunächst die Routingfunktion ip_route_input() aufgerufen um den weiteren Weg des Pakets zu bestimmen. Soll das Paket weitergeleitet werden, so geht es an ip_forward(), sonst an ip_local_deliver(). ip_mr_input() behandelt Multicast Paketen. Im Falle eines Fehlers, versendet ip_error() die entsprechende ICMP Fehlermeldung und zerstört den sk_buff.

Ist das Paket zur lokalen Zustellung bestimmt worden, werden, falls notwendig, in ip_local_deliver() Fragmente zusammengesetzt. Bevor ip_local_deliver_finish() aufgerufen wird, passiert das Paket einen weiteren Netfilter Hook (NF_IP_LOCAL_IN). Vor der Weitergabe des Paketes an den nächsten Netzwerklayer, wird noch nach einen wartenden ,,RAW IP Socket`` gesucht. Falls eine passender gefunden wird, bekommt die raw_v4_input() Funktion einen Clone des Pakets.

Anschließend muss, ähnlich wie in net_rx_action(), das richtige Protokoll gefunden werden. Für IP Pakete können das TCP, UDP, ICMP und IGMP sein. Für jedes der Protokolle steht eine entsprechende Funktion zur Verfügung (zBsp. tcp_v4_rcv(), udp_rcv(), ...), die das Paket weiter verarbeitet. Netfilter und iptables arbeiten jedoch nur mit Paketen des IP Layers[*].

Wurde ein Paket an ip_forward() übergeben, wird zuerst die TTL überprüft. Ist sie <= 1 so wird das Paket verworfen, sonst um 1 dekrementiert. Bevor die Funktion ip_forward_finish() aufgerufen wird, passiert das Paket den Netfilter Hook NF_IP_FORWARD. ip_forward_finish() setzt eventuell noch fehlende IP Optionen und übergibt das Paket an ip_send(), die eventuell Fragmentierung veranlasst. Die nächste Station, ip_finish_output(), setzt im sk_buff das Netzdevice gemäß der Routingentscheidung und, bevor ip_finish_output2() aufgerufen wird, muss das Paket noch den letzten Netfilter Hook (NF_IP_POST_ROUTING) passieren. ip_finish_output2() übergibt dann schließlich die Paketdaten an die darunterliegende Schicht.

Lokal erzeugte Pakete, können durch vier verschiedene Funktionen den IP Netzwerklayer Layer betreten (ip_build_and_send_pkt(), ip_queue_xmit(), ip_build_xmit(), ip_queue_xmit2()). Im IP Layer muss zunächst ein IP Header dem sk_buff hinzugefügt werden, bevor der Netfilter Hook (NF_IP_LOCAL_OUT) passiert wird. Nach dem Passieren des Hooks wird nochmal überprüft, ob durch den Hook die Route verändert wurde. Anschließend verlässt das Paket über ip_finish_output() und ip_finish_output2() den IP Layer.

Klaus Rechert 2004-03-09