4. Das KNet-Programm

4.1 Einleitung

Was ist KNet:

"KNet, ein Programm zur Simulation von Kommunikations-Netzwerken auf der Basis paketorientierter, verbindungsloser Datenkommunikation."


4.2 Schichten-Modell

Wie im Kapitel "Einleitung" schon erwähnt, dient ein Netzwerk der Abstraktion von physikalischen Gegebenheiten bzw. Einschräkungen.

In der Praxis hat sich gezeigt, dass es sinnvoll ist, ein Netzwerk in mehrere Schichten zu gliedern, die alle ein bestimmtes Abstraktionslevel darstellen, und vor der nächst höheren Schicht Detailinformationen verbergen.

Ob man ein Netzwerk nun in zwei, vier oder sieben Schichten einteilt, hängt im Allgemeinen von der Sichtweise und den Anforderungen an das Netzwerk ab (siehe Abb. 8).


Abb. 8: Schichtenmodell aus Applikationssicht und aus Netzwerksicht

Das in diesem Praktikum verwendete Netzwerk (KNet) wurde in vier Schichten aufgeteilt, wobei sich die unterste Schicht (die Übertragungsschicht) aus mehreren Schichten zusammensetzt, da es sich hierbei um TCP-Verbindungen handelt, die vom Unix-Kernel über Sockets bereitgestellt werden. Es handelt sich hierbei also um ein "komplettes" Netzwerk (Schicht I bis 4), nämlich dem Internet.

Ein KNet-Netzwerk ist aus Unix-Sichtweise nur eine Anzahl von Applikationen, die über TCP- bzw. UDP Verbindungen miteinander Daten austauschen (wie auch andere Unix-Applikationen z.B. FIP, NFS,..), (siehe Abb. 9).


Abb. 9: KNet-Netzwerksicht (unter UNIX)

Die anderen drei Schichten dieses Netzwerkes sind die Link-Schicht (Datensicherungsschicht), die dafür Sorge trägt, dass Daten-Pakete zwischen zwei Netzwerk-Knoten korrekt übertragen werden, die Netzwerkschicht, die aus den einzelnen Verbindungen ein Netzwerk aufbaut, über das Daten von einem Knoten zu einem beliebigen anderen Knoten übertragen werden können, und die Anwendungsschicht, die dafür sorgt, dass überhaupt Daten über dieses Netzwerk zu transportieren sind.

4.3 Netzwerk-Hierarchie

In Abb. 10 ist ein aus vier KNet-Knoten bestehendes Netzwerk abgebildet, dessen physikalische Abbildung auf das Internet (hier aus drei Rechnern IP-Adressen bestehend) vollkommen unabhängig von der Netzstruktur ist.


Abb. 10: KNet-Netzwerk und dessen Abbildung au das Internet

Dies ist dadurch möglich, weil das KNet-Programm auf dem Internet (auf Unix-Sockets) aufsetzt und dieses als "Physikalische Schicht" betrachtet.

Dass das Internet wiederum auf anderen Netzwerken (möglicherweise SONET oder WDM) aufsetzt, wird vom KNet-Programm ebenso abstrahiert, wie eine KNet-Applikation von dem unterliegenden Internet abstrahiert wird.


Abb. 11: KNet-Netzwerk (3 Knoten und dessen Übertragungsweg im Internet)

4.4 KNet Modul-Struktur

Um das KNet-Programm übersichtlich zu halten und möglichen Erweiterungen nicht im Wege zu stehen, wurde es in eine Vielzahl von kleineren Modulen aufgeteilt, die bestimmte Aufgabengebiete abdecken. Die Module, die der Anwendungsschicht zuzuordnen sind, repräsentieren die einzelnen Applikationen (wie z.B. ping, traceroute, tftp, ..) und die Netzwerk-Dienste (wie z.B. Echo).


Abb. 12: KNet-Modul-Struktur

Das wichtigste Modul der Netzwerkschicht ist das Routing-Modul (route.c), dass für die Verwaltung und Auswertung der Routingtabellen zuständig ist.

Es baut auf dem Link-Modul auf, welches virtuell die Verbindungen zwischen den einzelnen KNet-Netzwerkknoten darstellt und von dem Verhalten der Schnittstelle zum System (dem zugrundeliegenden Netzwerk) abstrahiert.

Diese Schnittstelle wird unter dem Device-Modul zusammengefasst, welches den Verbindungsaufbau, -abbau und die eigentliche Datenübertragung regelt. Verschiedene Schnittstellen-Typen (TCP-,.UNIX Domain-, Layer2 -Sockets) sowie deren physikalische Adressierung werden durch darunterliegende Module (device_tcp, device_l2 ...) in ihrem Verhalten (Funktionsaufruf-Verhalten) auf einen Nenner gebracht. Die schon aus dem Block C bekannte Datensicherungsschicht ist wiederum in eigenen Modulen untergebracht.


Abb. 13: KNet-Informations-Fluss

Weitere Module sind jeweils zur Adressverwaltung und deren Namensrepräsentation (host.c), zur Portverwaltung (service.c) sowie zur Auswertung von Benutzereingaben bzw. der Konfigurationsdateien (console-task.c, scanner.c, parser.c) aufgebaut.

Der Informationsfluss zwischen den einzelnen Modulen ist in Abb. 12 dargestellt. Von den verschiedenen Device-Typen empfangenen Daten werden über das Device-Modul zum Routing-Modul geleitet, welches dann entscheidet, wohin das Datenpaket geschickt werden soll.

Entweder ist es für den lokalen Netzknoten bestimmt, dann wird es über das Service-Modul (port-Verwaltung) einer der Applikations-Module zugeführt. Oder es ist für einen anderen Knoten bestimmt, dann wird es über das Link-Modul an einen anderen Knoten weitergeleitet.

Wird vom Benutzer eine Applikation gestartet, so werden die erzeugten Daten-Pakete von dem entsprechenden Applikations-Modul dem Routing-Modul übergeben, welches dann dieselben Entscheidungen zu treffen hat, als wäre das Paket von einer der Schnittstellen gekommen.

Als kurze Einführung, soll der Datenfluss nach einer Benutzer-Eingabe (Tastatur) dargestellt werden.


Abb. 14: Informationsfluss bei einer Benutzer-Eingabe

Nachdem das Device-Modul eine Eingabezeile von der Tastatur (File-Deskriptor 0/stdin) gelesen hat, wird diese Zeile an die Console-Task geschickt. Dieses Modul analysiert die Zeile zuerst syntaktisch (scanner.c) und danach semantisch (parser.c), um dann der Eingabe entsprechend zu reagieren bzw. entsprechende Funktionen auszuführen (Applikation starten / stoppen, Tabellen anzeigen / verändern ...).

4.5 Router Modul

Die zentrale Rolle des KNet-Programms nimmt das Routing-Modul ein, welches die Routing- Tabelle verwaltet und bei jedem Daten-Paket neu auswertet.

Die Routing-Tabelle besteht aus einem Array (Feld) aus Pointern, die auf einzelne Strukturen zeigen, sogenannte Routing-Einträge (siehe Abb. 15). In jeder dieser Strukturen ist eine (Ziel-) Netzwerk-Adresse inklusive der dazugehörigen Netzmaske und eine zu dieser Adresse führende Verbindung gespeichert. Zusätzlich sind noch die Entfernung des Ziel-Netzwerkes (HopCount) und die Übertragungskapazität (Metric) der dorthin führenden Verbindung gespeichert.

Die Verbindung an sich ist hier lediglich in Form eines Index-Wertes für die im Link-Modul gespeicherten Verbindungs-Daten gespeichert, so dass nur über geeignete Funktionen des Link-Moduls (z.B. GetLinkState) weitere Informationen erhalten werden können, die dafür aber auch immer auf dem aktuellen Stand sind.


Abb. 15: Aufbau der Routingtabelle

Bei jedem Paket (Aufruf der routePacket()-Funktion) wird durch Vergleichen der Zieladresse mit der in jedem Routing-Eintrag vorhandenen Netzwerk-Adresse und die bitweise Verknüpfung beider Adressen, für jeden so ausgewählten möglichen Weg (Route) der Pointer des entsprechenden Routingeintrages in eine zweite Tabelle kopiert. Alle so erhaltenen Wege werden in dieser Tabelle so sortiert, dass der beste Weg (RoutingEintrag) an erster Stelle steht. Über die in diesem Eintrag vermerkte Verbindung wird dann das Paket mittels einer entsprechenden Link-Modul-Funktion (LinkSendPacket()) übertragen.

Auf diese Weise kann mit Routing-Einträgen hantiert werden (ausgewählt, sortiert), ohne die eigentliche Routing-Tabelle und ihre Informationen verändern zu müssen. Außerdem kann man mit Pointern wesentlich effektiver und einfacher hantieren, als mit Strukturen usw. (falls man mit den Pointern im Allgemeinen klarkommt).

Die über die Routingeinträge direkt oder indirekt erhaltenen Informationen müssen verschieden ausgewertet und gewichtet werden, um ein vergleichbaren Wert zweier Routing-Einträge zu erhalten.

So sollte z.B. die default-Route (Ziel-Adresse 0.0.0.0, Netzmaske 0.0.0.0) für jede gesuchte Adresse eine Möglichkeit darstellen, aber nur im Sinne von "Kennst Du keinen Weg für dieses Paket, dann schicke es über die default-Route, vielleicht kann ja dort jemand etwas damit anfangen".

Ist dagegen irgendein Weg für diese Adresse definiert, so sollte dieser, falls dessen Metric nicht sehr viel schlechter als die der defauIt-Route ist, genommen werden. Also sollte die Anzahl der Nullen in der Netzmaske mit in die Entscheidung fließen, z.B. eine Null entspricht einer Metric-Verschlechterung von 5, so ist auf den Metric-Wert der default-Route der Wert 20 zu addieren, und auf den Metric-Wert der Netzmaske 255.255.0.0 dementsprechend der Wert 10.

Auch der Verbindungszustand (Verbindung aufgebaut gleich Metric 0, Verbindung geschlossen gleich Metric 5) und die Anzahl der fehlgeschlagenen Verbindungsaufbauversuche sollte "irgendwie" mit in die Entscheidung einfließen.