Next: Netzwerkgeräte
Up: Netzwerkkommunikation
Previous: TCP/UDP
  Contents
Die IP-Schicht stellt einen allgemeinen ''Paketübermittlungsdienst''
zur Verfügung. Man übergibt ihr ein Paket und einen Adressaten und
sie kümmert sich um die Übermittlung. Es wird nicht garantiert, dass
das Paket auch ankommt. Dafür sind dann übergeordnete Schichten wie
z.B. TCP zuständig.
Als wichtigste Datenstruktur der Implementierung der IP-Schicht im
Linux Kernel ist die struct iphdr [include/linux/ip.h]:
-
- struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
/*The options start here. */
};
Man kann die Aufgaben der IP-Schicht in das Empfangen, das Weiterleiten
und Senden von IP-Paketen unterteilen. Dabei sieht der Ablauf wie
folgt aus (alles IPv4):
Empfangen:
- Erhalt des Pakets
Mit der Funktion
int ip_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt)
[net/ipv4/ip_input.c] empfängt die IP-Schickt einen Puffer skb
vom Netzwerkgerät dev der darunter liegenden Schicht.
- Überprüfen des IP-Headers
RFC 1122 konform wird in der obigen Funktion geprüft ob:
1. die angegebene Länge des Paktes gültig ist (mind. die Länge eines
IP Headers)
2. die IP-Versionsnummer korrekt ist (IPv4 == 4)
3. die IP Checksumme stimmt
- Vergleich der Zieladresse mit der eigenen Adresse
Ist das Paket nicht für den lokalen Rechner, dann wird es weitergeleitet.
(In Funktion
ip_rcv_finish(struct sk_buff *skb), Abfrage von
ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)
Ist es für den lokalen Rechner wird
int ip_local_deliver(struct sk_buff *skb)
aufgerufen, sonst
int ip_forward(struct sk_buff *skb)
[net/ipv4/ip_forward.c]
- Defragmentierung des IP-Pakets
Wurde das Paket nicht weitergeleitet, wird es per ip_local_deliver()
auf dem Host weiterverarbeitet. Ist das Paket ein IP-Fragment, wird
versucht mit Hilfe schon empfangender Pakete es zu defragmentieren.
Ist das noch nicht möglich (weil noch Fragmente fehlen), dann wird
das Paket in einer Fragmentliste gespeichert. Dies ist durch die Funktion
struct sk_buff *ip_defrag(struct sk_buff *skb) [net/ipv4/ip_fragment.c]
implementiert.
- Übergabe des Pakets an das nächste Protokoll
Die Funktion ip_rcv_finish() ruft die Funktion skb->dst->input(skb)
auf, welche vorher auf den Funktions-Zeiger der entsprechenden input
Funktion der höheren Transportschicht gesetzt wurde.
Weiterleiten:
- Überprüfen des ttl Feldes im IP-Header
Ist der Wert kleiner oder gleich 1, wird das Paket verworfen und eine
entsprechende ICMP-Nachricht an den Absender geschickt.
(in int ip_forward(struct sk_buff *skb) [net/ipv4/ip_forward.c])
Wirklich dekrementiert wird das TTL Feld erst später.
- Überprüfen des Pakets auf fehlerhaftes/ungewolltes Routing
(zum Beispiel wenn ''strict routing'' verlangt wird und das Ziel
kein Gateway ist)
- Kopieren des Paket-Headers
Da im folgenden der IP-Header verändert wird, muss der Header des
sk_buff kopiert werden (copy on write, Funktion skb_cow()
in [include/linux/skbuff.h]).
- Setzen/Ändern von IP Optionen
In int ip_forward_finish(struct sk_buff *skb) [net/ipv4/ip_forward.c]
Aufruf von
void ip_forward_options(struct sk_buff *skb) [net/ipv4/ip_options.c]
- Senden
In int ip_forward_finish(struct sk_buff *skb) [net/ipv4/ip_forward.c]
Aufruf von
int ip_send(struct sk_buff *skb) (als static
inline in [include/net/ip.h] implementiert).
Dort wird vorher überprüft ob das Paket die MTU Grösse überschritten
hat, und dann entweder per
int ip_fragment(struct sk_buff *skb, int (*output)(struct
sk_buff*))
fragmentiert oder gleich per
int ip_finish_output(struct sk_buff *skb)
verschickt. (beide Funktionen implementiert in [net/ipv4/ip_output.c])
Senden:
- Erhalt des Pakets
(z.B. durch Aufruf der Funktion int ip_queue_xmit(struct
sk_buff *skb) [net/ipv4/ip_output.c])
- Ermitteln der Ziel-Route
Aufruf der Funktion ip_route_output(&rt, daddr, sk->saddr,
RT_CONN_FLAGS(sk), sk->bound_dev_if) [include/net/route.h]
um das Netzwerkgerät zu ermitteln, über welches das Paket verschickt
werden soll.
- Füllen des IP-Headers
Mit Hilfe der Funktion unsigned char *skb_push(struct sk_buff
*skb, unsigned int len) [include/linux/skbuff.h] wird am Anfang
des sk_buff Puffers Platz für einen IP-Header geschaffen.
Dieser wird dann mit den entsprechenden Werten wie Quell- und Ziel-Adresse
gefüllt.
- Fragmentierung des IP-Pakets
In int ip_queue_xmit2(struct sk_buff *skb) wird überprüft
ob das Paket die MTU Grösse überschritten hat. Ist das der Fall, dann
wird es mit Hilfe der Funktion int ip_fragment(struct sk_buff
*skb, int (*output)(struct sk_buff*)) [net/ipv4/ip_output.c]
in mehrere Teile zerlegt.
- Setzen der IP-Checksumme
Aufruf der Funktion void ip_send_check(struct iphdr *iph)
[net/ipv4/output.c], welche die Checksumme berechnet und im IP-Header
einträgt.
- Übergabe an das entsprechende Netzwerkgerät
Durch den Aufruf von skb->dst->output(skb) wird die dev_queue_xmit()
des Netzwerkgerätes aufgerufen, welches sich dann um das Verschicken
des Paktes kümmert.
Next: Netzwerkgeräte
Up: Netzwerkkommunikation
Previous: TCP/UDP
  Contents
2002-02-17