close

Anmelden

Neues Passwort anfordern?

Anmeldung mit OpenID

Flow Control in geswitchtem Gigabit Ethernet

EinbettenHerunterladen
Semesterarbeit
Institut für Computersysteme
der ETH Zürich
Flow Control in geswitchtem Gigabit Ethernet
Rolf Laich
Abteilung IIIc
Sommersemester 1999
Betreuung : Christian Kurmann
Prof. Thomas Stricker
Inhaltsverzeichnis
1
2
2.1
2.1.1
2.1.2
2.1.3
2.2
3
3.1
3.2
3.2.1
3.2.2
3.3
3.3.1
3.3.2
4
4.1
4.2
4.3
4.3.1
4.3.2
4.3.3
4.3.4
4.3.5
4.4
4.4.1
4.4.2
4.4.3
4.4.4
4.5
4.5.1
4.5.2
4.5.3
4.5.4
4.5.5
4.6
5
6
7
7.1A1
7.2A1
7.3A2
Zusammenfassung
Einleitung
Datenflusskontrolle
Datenflusskontrolle unter TCP
Congestioncontrol in der Netzwerk Schicht
Datenflusskontrolle im Ethernet (Datalink Layer)
Aufgabenstellung
Konfiguration und Test der Hardwarekomponenten
Erzeugung von Netzverkehr
Flusskonrolle des Hamachi Netzwerkcontrollers
IEEE 802.3x Flusskontrolle
Andere Möglichkeiten für die Flusskontrolle
Flusskontrolle im Cabletron Smart Switch Router 8600
IEEE 802.3x Flusskonrolle
Andere Möglichkeiten für die Flusskontrolle
Protokolle für eine ausschliessende Verbindung zwischen zwei PC's
Zentraler vs. Verteilter Algorithmus
Realisierung des Protokolls
Modifikationen am Standardtreiber des Hamachi Controller
Änderung der Datenstruktur (nicht protokollspezifisch )
Änderungen in der Initialisierung
Änderung der Sendefunktionen hamachi_start_xmit(), hamachi_tx(),
hamachi_interrupt()
Änderung in der Funktion hamachi_tx_timeout()
Änderungen in der Funktion hamachi_get_stats()
Übersicht über eingesetzte Linux Kernfunktionalitäten
Die Struktur sk_buff und Aufbau eines Ethernet Frames
Gegenseitiger Ausschluss
Bottomhalf Funktionen
IO-Control
Implementierung des Protokolls unter Linux
Datenstruktur
Ereignisse für den Verbindungsaufbau und – Abbau
Zustandsübergänge
Meldungen
Funktionen
Erfahrungen mit dem Protokoll
Ausblick
Literaturverzeichnis
Anhang:
Readme zum Inhalt der einzelnen Verzeichnisse
Konfigurationen des Smart Switch Routers
Information bez. des Verhaltens des Smart Switch Routers
Seite -1-
2
3
3
4
4
5
5
6
6
7
7
9
9
9
10
12
12
16
16
16
16
17
17
17
18
18
19
20
20
20
20
21
21
22
22
22
24
25
26
26
26
26
1 Zusammenfassung
Am Institut für Computersysteme der ETH Zürich wird ein Forschungskluster mit einem
geswitchten Gigagbit Ethernet Netzwerk betrieben.
In Hinblick auf den Einsatz eines Zero Copy Treibers [6] wurde für dieses Netzwerk untersucht,
welche Möglichkeiten zur Kontrolle des Datenflusses bestehen und ob die IEEE 802.3x Kontrollmechanismen zur Datenflusskontrolle benutzt werden.
Ferner sollte ein Protokoll vorgeschlagen werden, mit dem eine exklusive Verbindung zwischen
zwei Rechnern hergestellt werden kann.
Es konnte gezeigt werden, dass bei entsprechender Konfiguration des eingesetzten Hamachi Controllers die IEEE 802.3x Datenflusskontrolle durchgeführt wird. Diese Datenflusskontrolle kann
aber den Datenverlust nicht verhindern.
Beim Hamachi Controller besteht zudem die Möglichkeit, nur Daten eines bestimmten Absenders
zu empfangen.
Der Switch, der in diesem Netzwerk eingesetzt wird, soll gemäss Dokumentation Quality of Service
Konfigurationen unterstützen. Allerdings konnte der Effekt solcher Konfigurationen nicht belegt
werden.
Ein Protokoll für den gegenseitigen Ausschluss in einem Verteilten System wurde im Treiber des
Netzwerkcontrollers eingebaut.
Es konnte gezeigt werden, dass mit diesem Protokoll eine exklusive Verbindung zwischen zwei
Rechnern hergestellt werden kann. Der Zusatzaufwand, der durch die Ausführung dieses Protokolls
verursacht wird, hängt davon ab, wie häufig eine solche Verbindung aufgebaut wird. Bei einem
»normalen« Durchsatz von 40 Mbs wird der Durchsatz um 2% verringert, wenn für jedes gesendete
MB die Verbindung aufgebaut und wieder abgebrochen wird (vorausgesetzt, dass nur ein Sender
aktiv ist ).
Zudem wurden verschiedene Modifikationen am Treiber des Hamachicontrollers vorgenommen.
Seite -2-
2 Einleitung
Die Übermittlungstechnologien haben sich in den letzten Jahren rasant entwickelt. Somit stellt nicht
mehr die verfügbare Bandbreite auf dem Übertragungsmedium einen Engpass dar. Vielmehr befindet sich der Flaschenhals des Computernetzwerkes beim Übergang vom Netzwerkkontroller zur
Applikation, welche Daten versenden bzw. empfangen will.
Üblicherweise wird diese Schnittstelle in verschiedene Ebenen ( layer ) mit klar definierten Aufgaben unterteilt ( Protokoll-Stack ).
Die Applikationen, welche Daten senden wollen, übergeben diese dem Protokoll-Stack. Die Applikationen, die Daten empfangen, lesen die Daten aus dem Protokoll-Stack. Bei diesen Übergaben
werden die Daten jeweils kopiert.
Ein Ansatz, die Effizienz von Computernetzwerken zu erhöhen besteht darin, den erwähnten Engpass, die Schnittstelle zwischen Applikationen und Netzwerk effizienter zu gestalten. Insbesondere
soll vermieden werden, dass Daten mehrmals kopiert werden!
Die Daten einer Applikation sollen beim Senden in den »Sendespeicher« des Adapters gemappt
werden. Beim Empfangen müssen die Daten direkt in den virtuellen Adressraum einer Applikation
gelangen.
In einer Diplomarbeit am Institut für Computersysteme [6] wurde ein Treiber für einen Gigabit
Ethernetadapter entwickelt, der nach obigem Prinzip arbeitet. Mit diesem Treiber konnte der
Durchsatz von ca. 40 auf ca. 60 MBs erhöht werden.
Diese Leistungssteigerung wird aber nur dann erreicht, wenn :
-
die gesendeten Pakete in der richtigen Reihenfolge eintreffen.
-
keine Pakete verloren gehen (durch Übertragungsfehler oder Überlastung des Übertragunsmediums).
-
keine Pakete eines anderen Senders den Datenstrom zur »Unzeit« unterbrechen. D. h. alle
Fragmente eines Zero Copy Paketes sollten direkt hintereinander beim Empfänger eintreffen
und nicht durch ein Paket eines anderen Senders unterbrochen werden.
Alle diese Bedingungen erfordern eine Kontrolle des Datenstromes im Netzwerk. Weshalb die
Datenflusskontrolle in einem geswitchten Gigabit-Ethernet ganz allgemein eine herausragende
Rolle spielt und welche Methoden dazu eingesetzt werden, soll im nächsten Abschnitt erläutert
werden.
2.1 Datenflusskontrolle
In einem geswitchten Gigabit Ethernet Netzwerk sind die einzelnen Rechner über einen Switch
miteinander verbunden. Gesendete Daten kommen bei einem sogenannten Input Port beim Switch
an und werden über einen Output Port an den Empfänger weitergeleitet. Diese Input und Output
Ports verfügen jeweils über einen Puffer mit bestimmter Grösse. Wenn für eine kurze Zeit der Datenstrom, der in den Switch hereinfliesst grösser ist, als derjenige, der herausfliesst, werden diese
Puffer gefüllt. Wenn der hereinfliessende Datenstrom wieder kleiner wird, können die Puffer entleert werden. Falls ein Ungleichgewicht zwischen hereinfliessendem Datenstrom und herausfliesSeite -3-
sendem Datenstrom aber zu lange andauert, wird es zu einem Überlauf dieser Puffer kommen und
Daten gehen verloren (Congestion).
Bei den Controllern der einzelnen Stationen sind ebenfalls Puffer vorhanden, die aber auch eine begrenzte Grösse haben. Auch diese Puffer werden überlaufen, wenn über längere Zeit mehr Daten
ankommen werden, als der Controller und der entsprechende PC verarbeiten können.
Diese Art des Datenverlustes spielt mit Abstand die wichtigste Rolle in einem Gigabit-Ethernet. Die
Wahrscheinlichkeit eines wirklichen Übertragunsfehlers (d. h eine 0 wird gesendet und eine 1
kommt beim Empfänger an) ist demgegenüber vernachlässigbar klein.
2.1.1 Datenflusskontrolle unter TCP
TCP (Transmission Control Protocol) bietet Applikationen eine zuverlässigen Netzwerkdienst an.
Dazu muss das Protokoll den Datenstrom kontrollieren.
Das Protokoll TCP versucht bereits zu vermeiden, dass es zu Congestion kommt. Bei einem Verbindungsaufbau verständigen sich Sender und Empfänger darüber, wieviele Bytes vom Empfänger
problemlos empfangen werden können ( Sendefenster ).
Der Sender beginnt eine kleine Anzahl von Bytes zu übertragen. Bei jeder Übertragung wird eine
Stoppuhr ( Timer ) gestartet. Wird der Empfang der verschickten Daten vom Empfänger bestätigt,
bevor der entsprechende Timer ausläuft, wird die Anzahl Bytes, die verschickt werden können,
verdoppelt. Das Vergrössern des Sendefensters dient dazu, die Congestion innerhalb des Netzwerkes zu verhindern. Es wird solange durchgeführt, bis es entweder zu einer Congestion gekommen
ist, oder das tatsächliche Sendefenster die Grösse des zu Beginn vereinbarten Sendefensters erreicht
hat.
Bei diesem Verfahren werden immer erst neue Daten versendet, wenn der Empfang der vorherigen
bestätigt worden ist. Auf diese Weise kann der Sender genau kontrollieren, wieviele Pakete unterwegs sind und seine Sendeleistung entsprechend dosieren.
Falls es dennoch zum Verlust von Daten kommt, wird beim Sender ein Timer ablaufen. Dadurch
wird der Sender veranlasst, die Übertragung des ausstehenden Paketes nochmals auszuführen.
Die Timer müssen natürlich mindestens so lange warten, wie ein Paket braucht, um von einer Station zur anderen und zurück zu gelangen. Es dauert also verhältnismässig lange, bis ein Fehler bemerkt werden kann. So ist es verständlich, dass der Verlust von wenigen Paketen zu einem dramatischen Einbruch des erreichten Durchsatzes führt.
Für ein Hochgeschwindigkeitsnetzwerk ist es demzufolge wichtig, dass die Congestion auf einer
tieferen Ebene vermieden werden kann.
2.1.2 Congestioncontrol in der Netzwerk Schicht
Eine wichtiger Grund, dass es zu Überlastungen im Netzwerk kommt, besteht darin, dass die Daten
sehr unregelmässig gesendet werden. Wenn das Netzwerk im voraus wüsste, wie der Netzverkehr
aussähe, könnte die Last besser verteilt werden.
Eine Möglichkeit besteht nun darin, dass bei der Eröffnung einer Verbindung angemeldet wird,
wieviele Daten übertragen werden sollen und wie schnell. Das Netzwerk kann nun beurteilen, ob
der gewünschte Service die Kapazität übersteigt oder nicht. Entsprechend kann die Verbindung akzeptiert oder zurückgewiesen werden.
Seite -4-
Ein solches Verhalten ist häufig in ATM Netzwerken realisert. Aber auch in Datagramm Netzwerken kann ein solches Verhalten implementiert werden.
Die Erstellung eines Protokolls für die Reservierung einer Hochgeschwindigkeitsverbindung zwischen zwei Stationen ist ein Schritt in dieser Richtung. Eine weitere Möglichkeit, den Datenverlust
etwas kontrollieren zu können besteht darin, dass bei einer Überlastung des Netzwerks zuerst Daten
mit einer geringeren Priorität verworfen würden.
2.1.3 Datenflusskontrolle im Ethernet (Datalink Layer)
Am effizientesten kann eine Datenflusskontrolle zwischen zwei direkt miteinander verbundenen
Stationen (PC - Switch, bzw. Switch - PC) gemacht werden und nicht zwischen Quelle und Endziel
einer Verbindung. Aufgrund dieser Tatsache wurde auch im Datalink Layer eine Datenflusskontrolle implementiert.
Für Netzwerke, bei denen eine gleichzeitige Verbindung in beide Richtungen besteht ( full duplex )
wurde eine allgemeine Architektur für die Netzwerkkontrolle entwickelt. Mit diesen Kontrollmechanismen wurde ein Protokoll zur Datenflusskontrolle realisiert. Diese Flusskontrolle soll zwischen zwei Verbindungspartnern funktionieren ( PC-Switch, Switch-PC, Switch-Switch, PC-PC ).
Wenn bei einem Empfänger die Input Puffer zu überlaufen drohen, schickt er ein Pause Frame an
seinen Verbindungspartner. Diese Pause Frames teilen dem Verbindungspartner mit, dass er mit
dem weiteren Senden von Daten warten muss.
Während der Zeit, in der keine neuen Daten gesendet werden kann der Rechner, der das Pause
Frame gesendet hat, seine Datenpuffer abarbeiten und entleeren. Beim Empfänger eines solchen
Pause Frames wird ein Timer gestartet. Erst wenn dieser Timer abgelaufen ist, darf er weiter senden.
Die Zeitdauer, die gewartet werden muss, ist im Pause Frame angegeben. Mit einem Pause Frame,
das die Wartezeit 0 enthält, kann ein Wartezustand bei einem Sender beendet werden.
Das Protokoll ist so definiert, dass keine Probleme auftreten, wenn ein Verbindungspartner das
Protokoll nicht unterstützt. Allerdings kann dann der Datenverlust nicht vermieden werden.
2.2 Aufgabenstellung
In dieser Arbeit wurden zwei Ziele verfolgt:
In einem ersten Schritt sollten die Switch - und Controller Hardware so konfiguriert werden, dass
die IEEE 802.3x Mechanismen zur Flusskontrolle benutzt werden.
Es sollte zudem untersucht werden, ob die eingesetzten Hardwarekomponenten weitere Möglichkeiten zur Flusskontrolle anbieten. Dabei ging es darum, ob mit geeigneten Konfigurationen eine
bestehende Punkt zu Punkt Verbindung vor Unterbrechung durch weitere Verbindungen geschützt
werden könnte.
In einem weiteren Schritt sollten Softwaremassnahmen vorgeschlagen und implementiert werden,
die es erlauben, eine Verbindung zwischen zwei Maschinen ausschliessend aufzubauen ( d. h. wenn
bereits eine Verbindung zu einer Maschine besteht, darf kein anderer PC gleichzeitig eine Verbindung aufbauen können ).
Seite -5-
3 Konfiguration und Test der Hardwarekomponenten
3.1 Erzeugung von Netzverkehr
Um das Verhalten der Hardwarekomponenten bezüglich der Datenflusskontrolle untersuchen zu
können, mussten grosse Mengen von Daten sehr schnell zwischen mehreren Maschinen versendet
werden.
Für die Anordnung der PC's wurden hauptsächlich zwei Strategien angewendet:
Im ersten Fall wurden die Tests so durchgeführt, dass zwei Sender-Maschinen gleichzeitig Daten zu
einer Empfängermaschine übermittelten. Mehr als drei Maschinen in einen Test einzubeziehen war
kaum möglich, da die PC's häufig besetzt waren.
Im zweiten Fall wurden zwei PC's direkt mit einem Netzwerkkabel verbunden. Mit dieser Anordnung konnte das Verhalten des Netzwerkkontrollers unabhängig vom Switch untersucht werden.
Um ein Ungleichgewicht zwischen Sender - und Empfängermaschine zu erzeugen, wurden für diese
Tests Warteschleifen in die Empfangsfunktion des Treibers eingebaut.
Für das Übermitteln und Empfangen der Daten wurden ebenfalls verschieden Programme eingesetzt.
Einfache Geschwindigkeitmessungen wurden mit einem Standardprogramm zur Messung des
Durchsatzes eines Netzwerkes netperf ( TCP Stream ) durchgeführt [14].
Zudem wurden einige Programme zum Senden und Empfangen von Daten geschrieben. Gegenüber
netperf verfügten diese Programme über folgende Zusatzfunktionalität:
-
Angabe des Type of Service (TOS)Feldes im IP Header ( vergl. [4] ): Das TOS kann in einem
Programm mit der Funktion setsockopt( sock, SOL_IP, IP_TOS, &tos,
sizeof( tos ))
gesetzt werden. Es sollte damit untersucht werden, ob Daten aufgrund dieses Feldes mit erhöhter Priorität behandelt werden können (vergl. unten ).
-
Zählen, wieviele Pakete von jedem Sender empfangen wurden
-
Zählen, wie häufig sich Pakete der zwei Sender abwechselten
In den Untersuchungen über die Flusskontrolle spielte der erreichte Durchsatz eine untergeordnete
Rolle. Viel wichtiger war herauszufinden, ob Pakete eines Senders bevorzugt werden oder nicht.
Dazu wurden die Anzahl der empfangenen Pakete jedes Senders gezählt, sowie die Häufigkeit, mit
welcher sich die Pakete der zwei Sender beim Empfänger abwechseln.
Zuerst wurden Daten über die TCP Socket Schnittstelle gesendet und empfangen. Es wurde jedoch
festgestellt, dass die Flusskontrolle des TCP Protokolls jegliche Kontrollmechanismen der Hardware unnötig machte. Die Flusskontrolle der Hardware sprang gar nie an.
Daraufhin wurde die UDP Socket Schnittstelle verwendet um Daten zu verschicken und zu empfangen. Beim Einsatz von UDP stellte sich aber das Problem, dass viele Daten im Protokollstack der
Empfängermaschine verloren gingen.
Immerhin konnte so erreicht werden, dass es zu einem Überlauf der Buffer der Empfängermaschine
kam, und die Flusskontrollmechanismen der Hardware untersucht werden konnten.
Seite -6-
3.2 Flusskonrolle des Hamachi Netzwerkcontrollers
Die PC's am Gigabit Ethernet sind mit einem Hamachi Netzwerkcontroller ausgerüstet. Dieser Adapter ist konform zum Ethernet Standard ( IEEE 802.3x ).
Für eine ausführliche Beschreibung der Funktionalität des Controllers sei auf die Spezifikation verwiesen [13].
3.2.1 IEEE 802.3x Flusskontrolle
Zur Aktivierung der Flow Control Funktionalität müssen im Hamachi Controller das Register »Receive FIFO Depth Markers« sowie das Register »Flow Control« entsprechend initialisiert werden.
Tab. 1: »Receive FIFO Depth Markers« Register 0x0B8: gesetzter Wert: 0x1E000C00
Bit:
Initialisierter Wert
Default Wert
Beschreibung
31-30
0x0
0x0
reserviert
29-16
0x1E00
0x3FFF
obere Marke für Receive FIFO
15-14
0x0
0x0
reserviert
13-0
0x0C00
0x3FFF
untere Marke für Receive FIFO
Mit dem »Receive FIFO Depth Markers« Register werden untere und obere Marken im Empfänger
Puffer definiert.
Beim Überschreiten der oberen Marke wird dem Verbindungspartner eine Pause-Meldung gesendet.
Beim Unterschreiten der unteren Marke wird dem Verbindungspartner die Aufforderung geschickt,
das nächste Datenpaket zu schicken, sofern zuvor eine Pause-Meldung geschickt worden war.
Tab. 2:»Flow Control« Register 0x0BC: gesetzter Wert: 0x3CFFFF
Bit:
Initialisierter Wert
Default Wert
Beschreibung
31-24
reserviert
x
reserviert
23
0
0
Test Pause; Funktion unklar
22
0
0
Pausenzähler Funktion unklar
21
1
0
Aktivierung des Sendens von Pausen
Meldungen
20
1
0
Aktivierung des Empfangens
Pausen Meldungen
19-17
b110
x
reserviert
16
0
0x0
Pausenmeldung verschickt aber noch
nicht angekommen
15-0
0xFFFF
0xFFFF
Wert für Pausendauer
von
Über das »Flow Control« Register wird die Funktionalität Pausen-Meldungen zu verschicken, zu
empfangen und zu bearbeiten initialisiert.
Seite -7-
Der Hamachi Controller verfügt über Register, aus denen die Anzahl versendeter bzw. empfangener
Pause-Meldungen herausgelesen werden kann. Zudem kann aus der Hardware herausgelesen
werden, ob es zu Überlauf im Empfangsbuffer gekommen ist.
Tab. 3: ausgelesene Statistikregister des Hamachi Controllers:
Register
Adresse
Funktion
aufgeführt unter:
0x320
multicast Frames
stats.multicast
0x330
empfangene Bytes
stats.rx_bytes
0x344
empfangene Pause Frames
stats.compressed
0x354
Zu grosse empfangene Frames
stats.rx_length_errors
0x360
Prüfsummenfehler
stats.rx_crc_errors
0x364
Symbolfehler ??
stats.rx_frame_errors
0x36C
Verworfen aus der Receive FIFO stats.rx_over_errors
wegen Überlauf
0x3B0
gesendeter Bytes
stats.tx_bytes
0x3C4
Gesendete Pause Frames
stats.tx_compressed
0x3C8
Wegen Pause Frame eingelegte stats.tx_window_errors
Pausen
Diese Statistikwerte können in der Datei /proc/net/dev abgefragt werden. Beim Lesen dieser Datei
wird die Funktion static int sprintf_stats(char *buffer, struct device
*dev)
aus der Datei src/linux/net/cor/dev.c aufgefrufen, die ihrerseits die Funktion
hamachi_get_stats() aufruft.
Diese Möglichkeit, direkt auf Information aus dem Treiber zuzugreifen, stellte sich als unverzichtbares Hilfsmittel dar.
Der Device-Driver für den Hamachi Controller ist noch nicht voll ausgereift.
Gemäss den Kommentaren im Quelltext wurde angenommen, dass die Ethernet Flusskontrolle aktiviert sei. Es zeigte sich aber, dass lediglich das Register »Flow Control« korrekt initialisiert worden
war.
Ferner blockierte häufig der Treiber beim Versenden grosser UDP Pakete ( > 512 Bytes ) und
musste jeweils neu gestartet werden.
Nachdem das Register »Receive FIFO Depth Markers« initialisiert worden war und die Sendefunktion des Treibers verbessert worden war, konnte gezeigt werden, dass der Hamachi Controller tatsächlich das spezifizierte Verhalten aufweist ( bei direkter Verbindung zwischen zwei Maschinen ).
Bei überlastetem Empfänger werden Pause-Meldungen verschickt, die den Sender dazu veranlassen,
mit dem Verschicken des nächsten Datenpaketes zuzuwarten.
3.2.2 Andere Möglichkeiten für die Flusskontrolle
Der Hamachi Controller kann dynamisch so konfiguriert werden, dass die Hardware nur DatenpaSeite -8-
kete eines bestimmten Absenders akzeptiert. Alle Pakete anderer Stationen werden verworfen. Die
so konfigurierte Maschine ist somit nur für einen einzigen Partner sichtbar.
Konfiguration für die Aktivierung des MAC Filtering im Hamachi Treiber:
/* frames von cs-zz14 sollen empfangen werden können */
/* Aktivierung der Filterung */
writeb( 0x00, ioaddr + AddrMode );
/*die Ethernet Adresse muss in der richtigen Reihenfolge
eingegeben werden. vgl. Spec Seite 100.
Adresse von cs-zz14-giga : 00:E0:B1:04:1A:32
schreiben der Adresse*/
writew( 0xE000, ioaddr + AddrMode + 2 );
writel( 0x321A04B1, ioaddr + AddrMode + 4 );
Dieses Verhalten wurde getestet, aber beim Entwurf eines Protokolls für die Reservierung der Verbindung zwischen zwei Maschinen nicht berücksichtigt.
Für die Nutzung dieser Option wäre eine zentrale Kontrollstation nötig, die Buch führte über die
vorhandenen PC's und deren aktuelle Zustände.
Mit einer solchen Konfiguration könnte aber eine bestehende Verbindung nicht mehr von einer anderen Maschine unterbrochen werden!
3.3 Flusskontrolle im Cabletron Smart Switch Router 8600
Der Forschungscluster wird durch einen 30 Gb Crossbarswitch, einen Smart Switch Router der Firma Cabletron, vernetzt.
Der Switch verfügt über 3 MB Input/Output Buffer pro Gb Port und hat einen Durchsatz von 32
Gbps. Der Switch ist ebenfalls konform zu mehren IEEE 802.3.. Standards (für detailliertere Angaben [10][11][12]).
3.3.1 IEEE 802.3x Flusskonrolle
Wie oben beschrieben, sollte der Switch ebenfalls auf Ethernet Pause-Meldungen reagieren können.
In der Dokumentation wurde kein Hinweis gefunden, dass ein entsprechendes Verhalten konfiguriert werden müsse.
In zahlreichen Tests wurde das Verhalten des Switches untersucht.
Ohne Aktivierung der Flusskontrolle auf dem Hamachi Controller kam es zu einem Überlauf des
Empfangpuffers der empfangenden Maschine. Nicht alle gesendeten Pakete wurden korrekt empfangen.
Mit Aktivierung der Flusskontrolle auf dem Hamachi Controller wurden vom Empfänger PauseMeldungen verschickt. Die Sendermaschinen erhielten diese Meldungen jedoch nicht. Es wurden
etwa 2/3 der gesendeten Pakete empfangen. Alle empfangenen Pakete waren korrekt und ohne Fehler. In den Statistiken des Smart Switch Routers ( statistics show port-stats allports, statistics show port-errors all-ports) wurden keinerlei Fehler,
Seite -9-
Pufferüberläufe oder verworfenen Pakete vermerkt. Mit Aktivierung der Flusskontrolle war der
Datenverlust grösser als ohne Aktivierung der Flusskontrolle.
Es wurde vermutet, dass der Switch die »Pausen-Meldungen« zwar versteht und für sich korrekt
bearbeitet. Die Meldungen werden aber nicht weitergeleitet auch wenn die Puffer im Switch voll
sind und überlaufen. Dies entspräche der Spezifikation von IEEE 803.2x.
Unklar ist jedoch, weshalb die Statistiken des Switches keinen Pufferüberlauf auswiesen.
Das beschriebene Verhalten wurde vom Hersteller bestätigt. In einer Mitteilung des Herstellers wird
zudem erklärt, weshalb die Pause Frames nicht weitergeleitet werden können. ( vergl. A3 ). Gemäss
Hersteller sollten die Pufferüberläufe aber in der Statistik vermerkt werden.
Bei kleineren Datenmengen ( UDP Pakete < 64 Bytes, 200'000 Pakete ) kam es zu keinen Datenverlusten!
3.3.2 Andere Möglichkeiten für die Flusskontrolle
Gemäss Dokumentation können im Switch Priorisierungen bestimmter Verbindungen sowie bestimmter Datenströme definiert werden.
Diese Konfigurationsmöglichkeiten werden als Quality of Service ( QoS ) Konfiguration bezeichnet. Dabei werden vier verschiedene Prioritäten beschrieben.
Höchste Priorität für Systemmeldungen ( control ), hohe Priorität (high), mittlere (medium) Priorität
und geringe Priorität (low). In der Grundeinstellung haben alle Datenströme die Priorität low. Die
Priorität eines Datenstromes soll gemäss Dokumentation die Art beeinflussen, wie der Switch
ankommende Daten in den Input und Output Puffern behandelt (queuing policy). Daten mit hoher
Priorität sollten zuerst behandelt werden. Somit wäre auch die Gefahr eines Datenverlustes bei
solchen Daten geringer.
Ein Datenstrom kann aufgrund verschiedener Felder der Header der Netzwerkschichten 2 (Datalink
Layer ), 3 ( Networklayer : Internet Protokoll [4] ), 4 ( Transport Layer ) oder 5 (Applikation Layer)
identifiziert werden (weitere vergl. [12]). Innerhalb eines IP Datenstroms können Pakete gemäss
Senderadressen, Empfangsadressen, Portnummern, verwendetem Protokoll (TCP/UDP) sowie Type
of Service Feld (TOS) priorisiert werden.
Am interessantesten erschien die Möglichkeit, Datenströme aufgrund des TOS Feldes zu definieren
und zu priorisieren. Dieses Feld kann von einer Applikation gesetzt werden. Wenn eine Hochgeschwindigkeitsverbindung zustande gekommen ist, könnten alle Daten dieser Verbindung mit erhöhter Priorität behandelt werden. Wenn es im Switch zu Congestion kommen sollte, würden die
Daten dieser Verbindung zuletzt verworfen.
Bei den anderen Felder handelt es sich um statische Systeminformation, die von einer Applikation
nicht beeinflusst werden kann.
Im Folgenden wurden verschiedene QoS Konfigurationen eingegeben und versucht, die Auswirkungen festzustellen:
-
Es wurde angenommen, dass in der Grundeinstellung alle gesendeten Daten zu demselben
Datenstrom gehörten. Somit wäre es nur nötig gewesen, die Priorisierung innerhalb eines
Datenstromes mit dem Befehl »qos precedence ip« neu zu definieren. IP Pakete sollten gemäss ihrem TOS - Feld priorisiert werden (vergl. Anhang A2).
-
Es wurden zwei IP Datenströme mit unterschiedlicher Priorität definiert. Die Ströme sollten
aufgrund des Wertes des TOS - Feldes identifiziert werden. Die Priorisierung innerhalb der
Datenströme war gleich wie oben (vergl. Anhang A2).
Seite -10-
-
Es wurden zwei IP Datenströme mit unterschiedlicher Priorität definiert, die aufgrund ihrer
Senderadresse identifiziert werden sollten (vergl. Anhang A2).
-
Es wurden für die Maschinen am Gigabit Ethernet ein eigenes vlan konfiguriert das auf dem
IP Protokoll basierte (vergl. Anhang A2).
Bei diesen Konfigurationen hätte interessiert, wie gross der Einfluss dieser Priorisierungen ist.
Ohne eine spezielle Konfiguration wurde die vorhande Bandbreite gleichmässig auf beide Sender
verteilt.
Mit einer QoS Konfiguration wurde erwartet, dass eine Applikation mehr Bandbreite zugeteilt
erhielte. Dies sollte sich in der Häufigkeit, mit der sich die Pakete der beiden Sender beim Empfänger abwechselten, zeigen. Im Fall einer Congestion sollten mehr Pakete des Datenstromes mit
höherer Priorität empfangen werden können als vom anderen.
Es konnte jedoch in keinem Versuch ein Einfluss nachgewiesen werden. Weder die Ergebnisse
der Empfängerapplikation noch die Statistiken des SSR deuteten darauf hin, dass irgend eine
Priorisierung vorgenommen worden war. Vom Werkzeug zur Überwachung der Funktionen des
Switches ( CoreWatch ) wurden auch keine Pakete ausgewiesen, die zu diesen Datenströmen
gehörten.
Bei Daten, die über TCP verschickt worden waren, kam es gar nie zu einem Datenverlust.
Bei UDP-Datenströmen war die Kontrolle über die empfangenen Pakete schwierig, da Probleme
mit dem UDP Stack bestehen. Das Zählen der empfangenen Pakete eines entsprechenden
Datenstromes im Treiber des Hamachi Controllers könnte genauere Hinweise über das Verhalten
der QoS Konfiguration liefern.
Zudem sollte an diesem Punkt Kontakt mit dem Hersteller des Switches aufgenommen werden,
um mehr Information zu erhalten.
Die Funktionalität zur Priorisierung gewisser Datenströme wäre sehr wünschenswert. Sie würde
es ermöglichen, einer bestimmten Verbindung im Switch mehr Bandbreite zuzusichern ( vergl.
Kapitel 5 ).
4 Protokolle für eine ausschliessende Verbindung zwischen
zwei PC's
In der Einleitung wurde beschrieben, dass es für das optimale Funktionieren des Zero Copy Drivers
wichtig ist, dass die Fragmente eines Zero Copy Paketes direkt nacheinander beim Empfänger eintreffen und dass keine Pakete verloren gehen. Andernfalls müssen die Daten wieder kopiert werden
bzw. müssten aufwendige »Retransmissions« durchgeführt werden.
Mit einem Protokoll, das eine ausschliessende Verbindung zwischen zwei Maschinen herstellt, kann
vermieden werden, dass zwei Sender gleichzeitig grosse Mengen an Daten demselben Empfänger
schicken. Dadurch kann die Wahrscheinlichkeit, dass es zu einer Überlastung des Switches oder
eines Empfängers kommt, erheblich reduziert werden. Die Ergebnisse aus den oben gemachten
Untersuchungen lassen den Schluss zu, dass es bei einem Sender und einem Empfänger nicht zu
Datenverlusten kommt ( auch ohne Kontrollmechanismen der Software, z. B. mit UDP).
Durch ein solches Protokoll wird aber nicht ganz vermieden, dass manchmal ein »fremdes« Paket
(eine Meldung des Protokolls) zwischen zwei Fragmente eines Zero Copy Paketes gerät! Die Häufigkeit eines solchen Ereignisses kann aber klein gemacht werden. Allerdings muss beachtet werSeite -11-
den, dass, wenn diese Wahrscheinlichkeit klein gemacht wird, die Latenzzeit gross wird. D. h. es
muss lange gewartet werden, bis die Verbindung aufgebaut werden kann.
Die Meldungen des Protokolls sind von minimaler Grösse (60 Bytes) und die Resynchronisierung
zwischen Sender und Empfänger ist einfacher als bei grossen Paketen.
Um ganz zu vermeiden, dass der Datenstrom eines Senders unterbrochen werden kann, müsste das
Protokoll auf einem anderen Netzwerk ausgeführt werden, oder über eine Verwaltungszentrale, die
nicht in den normalen Netzverkehr eingebunden ist.
Ein ausdrückliches Ziel für den Entwurf dieses Protokolls war aber eine zentrale Verwaltungsstation
zu vermeiden.
4.1 Zentraler vs. Verteilter Algorithmus
Mit einem Protokoll sollte erreicht werden, dass ein Sender, der die Zero Copy Funktionaliät benutzen möchte, nicht von einem anderen Sender unterbrochen wird, und somit die Vorteile des Zero
Copy Treibers verloren gehen.
Das gesuchte Protokoll soll eigentlich einen wechselseitigen Ausschluss in einem verteilten System
garantieren. Der kritische Abschnitt ist in diesem Fall das Senden eines Zero Copy Datenstroms an
einen bestimmten Empfänger.
In [2] sind zur Lösung eines solchen Problems ein zentraler und ein dezentraler Algorithmus beschrieben.
Beim zentralen Algorithmus existiert ein Koordinator, der einem Prozess die Erlaubnis erteilt, in
den kritischen Abschnitt einzutreten. Beim Beenden des kritischen Abschnittes teilt der Prozess
dem Koordinator mit, dass der kritische Abschnitt beendet ist. Dadurch erhält ein anderer Prozess
die Möglichkeit, ebenfalls in den kritischen Abschnitt einzutreten.
Natürlich funktioniert der Algorithmus nur solange der Koordintor funktionsfähig ist.
Beim dezentralen Algorithmus gibt es keinen einzelnen Koordinator. Hingegen ist die Zusammenarbeit aller vorhandener Prozesse für ein korrektes Funktionieren erforderlich. Demzufolge ist auch
die Anfälligkeit auf Ausfälle bei n beteiligten Prozessen n-mal grösser.
Das Protokoll wurde nach dem zentralen Algorithmus entworfen. Die Rolle des Koordinators übernimmt der Empfänger. Die Entscheidung über das Eintreten in einen kritischen Abschnitt wird zwar
zentral getroffen. Das Problem wurde aber so aufgeteilt, dass es mehrere kritische Abschnitte gibt.
Fällt eine Maschine aus, kann sie ohnehin nicht mehr erreicht werden. Die Verbindungsmöglichkeiten zu den anderen Maschinen bleiben unbetroffen.
Der Algorithmus aus [2] wurde in einem Punkt modifiziert. Ein Sender wartet nicht bis er die Erlaubnis erhält, in den kritischen Abschnitt einzutreten. Falls der Empfänger gerade besetzt ist, teilt
er das dem Sender mit. Dieser wartet eine zufällig gewählte Zeitspanne und wiederholt seine Anfrage. So ist es möglich, dass eine andere Maschine eine Verbindung zum Sender aufbaut, während
dieser am Warten ist. Mit geringem Zusatzaufwand kann dieses Protokoll auch sicher betrieben
werden, wenn einzelne Meldungen verloren gehen. Das beschriebene Protokoll kann einfach als
endlicher Automat beschrieben werden.
Figur 1 zeigt den Graphen des endlichen Automaten.
1a, 1b, 4
Seite -12-
waiting
2
1a
3
1a,2,3
4
receivingg
4
idle
sending
1b
1a,2,3
1,2,3
2,3,4
Tab. 4: Ereignisse im Automaten:
Ereigniss Nr
(Event )
Beschreibung
1a
SendRequest: Applikation will senden
1b
ReceiveRequest: Anfrage ob das Sender erlaubt ist
2
Ack: Bestätigung, dass gesendet werden darf
3
Nack: negative Antwort auf Receive Request
4
Release: Senden und empfangen werden beendet
In tabellarischer Form sind die Aktionen des Senders sowie des Empfängers auf die möglichen Ereignisse aufgeführt.
Seite -13-
Tab. 5: Zustandsübergänge des Senders:
Event
1a
IDLE
WAITING
SENDING
Sender verschickt einen Sendrequest der Applikation Sendrequest der Applikation wird
Receiverequest an die wird zurückgewiesen.
zurückgewiesen.
entsprechende
Adresse Folgezustand: WAITING
Folgezustand: SENDING
und wartet auf die Antwort.
Folgezustand: WAITING
1b
Siehe Zustandsübergänge Receiverequest
wird Receiverequest wird zurückgedes Empfängers
zurückgewiesen und eine wiesen und eine Nack Meldung
Nack Meldung erzeugt.
erzeugt.
2
3
4
Folgezustand: WAITING
Folgezustand: SENDING
Wird ignoriert:
Applikation darf senden.
Wird ignoriert:
Folgezustand: IDLE
Folgezustand: Senden
Folgezustand: IDLE
Wird ignoriert
Senden zur Zeit nicht erlaubt Wird ignoriert
Folgezustand: IDLE
Folgezustand: IDLE
Folgezustand: SENDING
Wirt ignoriert
-
Senden abgebrochen
Folgezustand: IDLE
Folgezustand: IDLE
Tab. 6: Zustandsübergänge des Empfängers:
Event
1a
IDLE
RECEIVING
Vergl. Zustansübergänge des Senders
Die Anfrage wird abgelehnt. Da der Receiver
seine ganze Leistung benötigt um den
Datenstrom des Empfängers entgegen zu
nehmen, sollte er nicht versuchen, auch
grosse Datenmengen zu verschicken
Folgezustand: RECEIVING
1b
Receiver verschickt eine Ack Meldung. Receiver verschickt eine Nack Meldung. Es
Die Verbindung kann aufgebaut weden existiert bereits eine Verbindung und der
Anfragesteller muss warten.
Folgezustand: RECEIVING
Folgezustand: RECEIVING
2
3
4
Wird ignoriert:
Wird ignoriert:
Folgezustand: IDLE
Folgezustand: RECEIVING
Wird ignoriert:
Wird ignoriert:
Folgezustand: IDLE
Folgezustand: RECEIVING
Wird ignoriert:
Die Verbindung wird aufgelöst
Folgezustand: IDLE
Folgezustand: IDLE
Aus dem Graphen ist ersichtlich, dass alle Zustände erreicht werden, und dass keine Situationen
Seite -14-
entstehen können, aus denen es keinen Ausweg mehr gibt ( Deadlocks; ausser wenn Meldungen
verloren gehen ).
4.2 Realisierung des Protokolls
Um zu veranschaulichen, wie das Protokoll arbeitet und wie es implementiert werden müsste, wurde in einem ersten Schritt eine Java-Simulation geschrieben. In diesem Programm wird ein Computernetzwerk mit mehreren Maschinen vereinfacht modelliert. Alle »Maschinen« versuchen zu einem zufällig gewählten Zeitpunkt einer anderen Maschine Daten zu schicken. Die Kontrolle, wer
gerade berechtigt ist, seine Meldungen zu verschicken, wird von den einzelnen »Maschinen« nach
dem beschriebenen Muster durchgeführt.
Im zweiten Schritt ging es darum, dieses Protokoll im Linux System zu integrieren.
Da verschiedene Protokolle der höheren Ebenen des Netzwerk Schichtenmodells diese
Funktionalität in Anspruch nehmen sollten, wurde entschieden, das Protokoll in der untersten
Schicht, dem Treiber des Netzwerkkontrollers, einzubauen.
Bevor mit der eigentlichen Implementierung des Protokolls begonnen werden konnte, mussten einige Änderungen im vorhandenen Treiber durchgeführt werden. Zudem musste eine Übersicht über
gewisse Basisfunktionalitäten des Linux Systems gewonnen werden.
In den folgenden zwei Abschnitten werden die Änderungen am Treiber erläutert, und die notwendingen Funktionen des Linuxsystems werden beschrieben. Viele dieser Hinweise über das Linuxsystem stammen aus [5].
4.3 Modifikationen am Standardtreiber des Hamachi Controller
4.3.1 Änderung der Datenstruktur (nicht protokollspezifisch )
In der Datenstruktur hamachi_private kommt ein Vektor pad[] vor. Gemäss den Kommentaren im Quelltext dient dieser Vektor lediglich zur zusätzlichen Speicherallokation. Mit dieser
»Reserve« soll erreicht werden, dass immer ein 32 Byte alignierter Pointer bei der Allokation zurückgegeben werden kann.
Um nicht immer nachzählen zu müssen, wurden diese pad Felder entfernt. Das muss jedoch bei der
Allozierung berücksichtigt werden. Der Speicherplatz, der alloziert werden muss, ist demzufolge
((sizeof( struct hamachi_private )+31)&~31)
4.3.2 Änderungen in der Initialisierung
Im obigen Abschnitt über die Flusskontrolle des Hamachi Treibers wurde bereits erwähnt, dass ein
Register für die Aktivierung der Flusskontrolle nicht gesetzt worden war. Diese Register wird in der
Funktion hamachi_open() zusätzlich geschrieben.
Bei der Interrupt Maske wird im Originaltreiber des Interruptbit für den Sendekanal gesetzt. So wie
der Treiber aufgebaut ist, braucht es keinen Senderinterrupt. Die Durchsatzleistung scheint durch
diese Konfiguration allerdings nicht beeinträchtigt.
Seite -15-
Ursprünglicher Wert der Intterrupt Mask: 0x80878787
Wert ohne Sender Interrupt: 0x80878687
4.3.3 Änderung der Sendefunktionen hamachi_start_xmit(), hamachi_tx(),
hamachi_interrupt()
Wie ober bereits erwähnt traten beim Versenden grosser UDP Pakete Probleme im Treiber auf. Die
Untersuchungen
ergaben,
dass
unter
gewissen
Umständen
die
Funktion
hamachi_start_xmit() blockierte.
Es wurde festgestellt, dass in der vorhandenen Implementierung ein Bit der Variable dev->tbusy
benutzt wird, um die Funktion hamachi_start_xmit() zu reservieren. Dasselbe Bit wird
ebenfalls benutzt, um den Zustand der Senderwarteschlange als voll bzw. leer zu markieren. Da
dieses Bit sowohl in der Funktion hamachi_start_xmit() als auch bei der Interruptbehandlung geschrieben wird, entsteht unter Umständen ein Konflikt, der dazu führen kann, dass die
Funktion hamachi_start_xmit() gleichzeitig mehrmals betreten wird. Dadurch ist die Korrektheit des Feldes cur_tx nicht für alle zugreifenden Prozesse gewährleistet.
Bei der Änderung wurde das Flag dev->tbusy ausschliesslich verwendet, um die Funktion
hamachi_start_xmit() vor mehrfacher »gleichzeitiger« Ausführung zu schützen. Das Flag
wird beim Eintritt in die Funktion gesetzt und beim Austritt wieder gelöscht.
Da auch im Interrupt dieses Flag gelöscht werden konnte, musste die entsprechende Stelle im Interrupthandler entfernt werden.
Abfragen auf dieses Flag in der Funktion hamachi_tx() werden unnötig, da das Flag in dieser
Funktion immer gesetzt ist.
Durch die beschriebenen Änderungen konnte eine Art der Blockierung der Sendeoperation behoben
werden. Zu einem späteren Zeitpunkt traten aber wiederum Blockierungen auf, deren Ursache noch
unklar ist.
Es wurde der Eindruck gewonnen, dass der ganze UDP Protokollstapel sehr unstabil sei und sehr
empfindlich auf Echtzeitverhältnisse reagiere. Gewisse Problem kommen vermutlich aus dem UDP
Stack und nicht in erster Linie aus dem Treiber.
4.3.4 Änderung in der Funktion hamachi_tx_timeout()
Beim Blockieren der Sendeoperation wurde jeweils die Funktion hamachi_tx_timeout()
aufgerufen. In dieser Funktion wurde ein Softreset des Controllers durchgeführt, und die Sender
sowie Empfängerkanäle neu gestartet.
Dieser Ablauf kann gemäss Spezifikation zur Blockierung des Sende - und Empfangskanal führen.
Zudem müssen gewisse Register wieder initialisiert werden, damit der Controller wieder arbeiten
kann.
In der Funktion hamachi_tx_timeout() wurde ein Softreset eingebaut, wie es in der Spezifikation beschrieben ist:
Zuerst werden die Sender-und Empfängerwarteschlangen freigegeben ( löschen der own bits ).
Danach muss gewartet werden, damit die Empfangs - und Sendeprozesse inaktiv werden. Erst wenn
Empfangs - und Sendeprozess inaktiv sind, darf ein Softreset gemacht werden. Zum Schluss werden
wieder alle Register mit dem Aufruf der Funktion hamachi_open() initialisiert.
Da die Blockierung des Treibers behoben werden konnte, wurde auch die Funktion
Seite -16-
hamachi_tx_timeout() nicht mehr intensiv getestet.
4.3.5 Änderungen in der Funktion hamachi_get_stats()
Um sehen zu können, wie die Flusskontrolle arbeitet, wurden die Register mit Informationen über
die gesendeten Pause Frames zusätzlich ausgegeben.
Es handelt sich dabei um die Register 0x344, 0x3c4 und 0x3C8.
Die Statistikangaben können über das File /proc/net/dev abgefragt werden. Die Information zu diesen Angaben ist in dieser Datei unter diesen Titeln vorhanden:
Tab. 7: zusätzlich ausgelesene Statistikregister
Receive: compressed
0x344
Transmit: compressed
0x3C4
Transmit: window
0x3C8
4.4 Übersicht über eingesetzte Linux Kernfunktionalitäten
4.4.1 Die Struktur sk_buff und Aufbau eines Ethernet Frames
Die Stuktur sk_buff wird unter Linux auf allen Ebenen des Protokollstapels zur Verwaltung von
Datenpaketen (Frames) verwendet. Eine gute Übersicht über die einzelnen Felder dieser Struktur
kann in [5] gefunden werden. Die Struktur sowie häufig eingesetzte inline Funktionen sind in der
Datei skbuff.h definiert.
Unter Linux ist ein Frame eine lineare Folge von Bytes. Um ein Frame zu erstellen, das verschickt
werden kann, muss zuerst ein Speicherbereich der gewünschten Grösse alloziert werden. Die Zeiger
data und tail zeigen in diesen Speicherbereich.
Es gibt eine vielzahl von Inlinefunktionen um Daten in diesen Speicherbereich hineinzuschreiben,
oder Teile dieses Speichers zu reservieren. Diese Funktionen verschieben die Zeiger data und tail
und führen die Länge des Frames nach.
Häufig werden die Daten nach dem Ethernet-Header mit einer bestimmten Alignierung eingefügt
(damit das Frame schneller kopiert werden kann).
Mit der folgenden Anweisungsfolge wird ein Ethernetframe erzeugt werden, das direkt verschickt
werden kann:
/* Deklaration eines ethernet header Zeigers */
struct ethhdr eh;
/*Deklaration eines sk_buff Zeigers und Allozierung eines Buffers.
15 wird addiert, damit der Zeiger auf den Etherentheader 16 Byte
aligniert werden kann.*/
struct sk_buff* skb = dev_alloc_skb( ETH_HLEN + datasize +15 );
if(!skb) return NULL;
/*Platz für den Ethernet Header wird reserviert. Zu data und tail
Zeiger wird (ETH_HLEN+15)&~15)addiert.*/
Seite -17-
skb_reserve( skb, (ETH_HLEN+15)&~15);
/*Zum tail-Zeiger wird sizeof(data) addiert und die Länge des
Frames wird incrementiert; der data-Zeiger wird zurückgegeben*/
my_data=(data*)skb_put( skb, sizeof(data) );
/*jetzt kann my_data wie ein normaler Zeiger auf eine Struktur
beschrieben werden.*/
initialize_mydata( my_data );
/* der data-Zeiger wird um ETH_HLEN decrementiert und len wird um
ETH_HLEN incrementiert*/
eh = (struct ethhdr*) skb_push( skb, ETH_HLEN );
/*jetzt kann der Ethernet-Header bearbeitet werden*/
initialize_ethernetheader( eh );
Gewöhnlich wird ein erzeugtes Frame über den Protokoll-Stapel in eine Warteschlange für die zu
versendenden Pakete eingefügt.
Beim Abarbeiten dieser Warteschlange, wird die Funktion dev->hard_start_xmit()
aufgerufen. Falls das Paket versendet wurde, gibt hard_start_xmit() den Wert Null zurück,
andernfalls einen Wert ungleich Null.
Konnte das Paket noch nicht versendet werden, wird der Versuch zu einem späteren Zeitpunkt wiederholt.
4.4.2 Gegenseitiger Ausschluss
Typischerweise werden in Computernetzwerken von der Hardware Signale ( Interrupts ) ausgelöst,
wenn ein Paket empfangen worden ist. Diese Interrupts unterbrechen den aktuell ausgeführten Programmabschnitt unvorhergesehen. Durch den Interrupt wird eine Routine aufgerufen, die in diesem
Fall das empfangene Paket an die oberen Schichten weiterleitet. Die Interruptroutine selber kann
nicht unterbrochen werden.
Nach Beendigung dieser Interruptroutine arbeitet das unterbrochene Programm dort weiter, wo es
aufgehört hat.
Im Fall eines Netzwerktreibers ist es durchaus möglich, dass ein Sendeprozess von einem Empfangsprozess unterbrochen wird. Da beide Prozesse mit teilweise denselben Daten arbeiten, müssen
Mechanismen gefunden werden, um gewisse Anweisungsfolgen unterbruchsfrei durchführen zu
können. Andernfalls wäre es möglich, dass durch einen Interrupt diese Daten in einen inkonsistenten Zustand gelangen. Unter Linux existieren einerseits Bit-Operationen, die garantiert atomar d.h.
ohne Unterbruch ausgeführt werden. Im Treiber des Hamachi-Controllers werden die Operationen
test_and_setbit() und clear_bit() benutzt, um gewisse Programmabschnitte zu reservieren. Allerdings kann auch ein »reservierter« Programmabschnitt unterbrochen werden.
Um wirklich einen ganzen Programmabschnitt ohne Unterbruch (atomar) auszuführen, muss wie
folgt vorgegangen werden:
-
Als erstes wird das Flag-Register des Prozessors mit der Funktion save_flags( flag )
gespeichert.
Seite -18-
-
Anschliessend wird mit dem Macro cli() das Interrupt enable des Prozessors gelöscht.
-
Am Ende des Programmabschnittes wird mit restore_flags( flag ) das Flag-Register des Prozessors auf den ursprünglichen Wert zurückgesetzt.
Beide Möglichkeiten wurden bei der Implementierung des Protokolls im Treiber des Hamachi Controllers ausgenutzt.
4.4.3 Bottomhalf Funktionen
Wie oben erwähnt, wird durch einen Interrupt das aktuell ausgeführte Programm unterbrochen. Zudem kann während der Ausführung der Interruptroutine nicht mehr auf Interrupts reagiert werden.
Aus diesen Gründen ist es sinnvoll, die Funktionen zur Behandlung von Interrupts möglichst kompakt zu halten. Dinge, die nicht dringend nach dem Interrupt ausgeführt werden müssen, sollen zu
einem späteren Zeitpunkt erledigt werden. Der Scheduler des Systems hat dann die Freiheit, diese
Aufgaben auszuführen, wann es am günstigsten ist.
Zu diesem Zweck existieren unter Linux sogenannte Bottomhalf's ( untere Hälften der Interrupts ).
Bottomhalf's sind Funktionen, die ausgeführt werden, nachdem ein Interrupt behandelt worden ist.
Die Bottomhalf Funktionen werden atomar ausgeführt. Da die Anzahl solcher BottomhalfFunktionen im System begrenzt ist, ( auf 32 ) wurden drei spezielle Bottomhalf Funktionen
geschaffen, mit denen beliebig viele Funktionen als Bottomhalf Funktionen registriert werden
können.
Um eine Funktion als eigene Bottom Halffunktion zu registrieren, muss eine Struktur struct
task_queue angelegt werden. Diese Struktur enthält einen Zeiger auf die Funktion, die ausgeführt werden soll, sowie einen Zeiger auf die Daten, die der Funktion als Argument dienen. Diese
Stuktur wird in eine lineare List eingefügt.
Um die Funktion dann ausführen zu lassen, muss mit der Funktion mark_bh( <name des
bottomhalf>_BH ) der systeminterne Bottomhalf markiert werden. Die systeminterne
Bottomhalf Funktion arbeitet die Liste ab und führt die Funktion mit angegebenem Argument aus.
Dieser Mechanismus wird angewendet, um eine Antwort des Protokolls auf eine Anfrage zu erzeugen.
4.4.4 IO-Control
Unter Linux existiert die Systemfunktion ioctl(), mit welcher Information zwischen Benutzer und Kernmodus ausgetauscht werden kann.
Diese Funktion wurde eingestzt, um einen Sendrequest sowie die Release Meldung von der SenderApplikation an den Treiber zu schicken. Die Details können in den Funktionen mii_ioctl() des
Hamachi-Controllers sowie der Funktion ioctl_request() entnommen werden.
4.5 Implementierung des Protokolls unter Linux
4.5.1 Datenstruktur
Implementiert wurde genau das oben beschriebene Protokoll. Der Einfachheit halber wurde davon
ausgegangen, dass keine Protokollmeldungen verloren gehen. Diese Annahme bestätigte sich auch
Seite -19-
in den durchgeführten Tests.
Wie bereits erwähnt, wird das Protokoll vom Hamachi Treiber ausgeführt.
Für die Implementierung wurde eine neue Datenstruktur eingeführt:
struct flow_control {
/* ethhdr für das Erstellen der Protokoll-Pakete */
struct ethhdr eh;
/* Zustand des endlichen Automaten */
long volatile state;
/* task queue für das erzeugen eines Replys auf eine Proto
koll meldung
*/
struct tq_struct repl;
/* für die funktion hamachi_start_xmit soll eine queue aufgebaut
werden */
struct sk_buff *skb;
};
/* im source code sind noch mehr Felder vorhanden, die aber nicht
mehr benötigt werden*/
Diese Struktur wurde in der Struktur hamachi_private integriert.
4.5.2 Ereignisse für den Verbindungsaufbau - und Abbau
Eine wichtige Entscheidung war, aufgrund welches Ereignisses ein Verbindungsaufbau gemacht
werden sollte.
Zuerst wurde versucht, das gesamte Protokoll für die oberen Netzwerkschichten unsichtbar zu machen. Eine Verbindung sollte für jedes IP-Paket aufgebaut werden, das sich über mehrere Fragmente
(vergl. [4]) erstreckt.
Es stellte sich aber heraus, dass unter Linux die Fragmentierung von Datenpaketen unter TCP so
durchgeführt wird, dass im Netzwerkcontroller immer nur nicht fragmentierte Pakete ankommen.
Somit konnte das Protokoll nur für UDP eingesetzt werden.
Grundsätzlich konnte das Protokoll auf diese Weise realisiert werden. Es musste aber festgestellt
werden, dass die Probleme mit dem UDP Protokoll-Stack so gross sind, dass keine vernünftigen
Resultate gezeigt werden konnten (vergl. unten ).
Schliesslich wurde entschieden, eine Verbindung direkt durch eine Applikation aufbauen zu lassen.
Über einen ioctl()-Aufruf kann ein Sendrequest dem Treiber mitgeteilt werden. Der Treiber
fragt beim Empfänger, ob er die Verbindung akzeptiere. In einem zweiten ioctl-Aufruf kann die
Applikation abfragen, ob die Verbindung akzeptiert worden ist oder nicht. In dieser Version ist die
Applikation in einem Wartezustand bis die Verbindung angenommen worden ist.
Die Applikation ist ebenfalls dafür verantwortlich, dass die Verbindung wieder abgebrochen wird.
Auch das geschieht über einen ioctl Aufruf, der eine entsprechende Release Meldung an den Empfänger auslöst.
Applikationen, die keinen solchen Verbindungsaufbau ausführen, merken nichts vom Protokoll.
4.5.3 Zustandsübergänge
Eine Maschine funktioniert entweder als Sender oder als Empfänger. Die Zustandsübergänge des
Senders werden beim Verbindungsaufbau und beim Empfang von Protokoll Meldungen
Seite -20-
durchgeführt ( Funktionen: mii_ioctl() und hamachi_interrupt()).
Die Zustandsübergänge des Empfängers werden durch Empfang von Protokoll Meldungen ausgelöst
( Funktionen: hamachi_interrupt(), fc_replay()).
4.5.4 Meldungen
Bei den Meldungen die zwischen den verschiedenen Maschinen verschickt werden, handelt es sich
um Ethernet Pakete. Um diese Pakete als Protokoll Meldungen zu kennzeichnen, wurde die Protokollnummer HAMACHI_P_FC definiert.
Ein Paket dieses Typs enthält zusätzlich zum Ethernet Paketheader ein Feld des Typs int. Die
möglichen Werte für dieses Feld sind RECEIVE_REQUEST, ACK, NACK, RELEASE.
4.5.5 Funktionen
Ein Paket für das Senden einer Meldung kann mit der Funktion
strukt sk_buff* fc_frame( struct ethhdr *eh, int msg );
erzeugt werden.
Der zurückgegebene sk_buff Zeiger kann direkt verwendet werden, um das Paket mit der Funktion hamachi_start_xmit() zu versenden. Beim Empfang werden die Pakete dieses Typs
nicht an obere Netzwerkschichten weitergeleitet.
Da der Sendekanal unter Umständen gerade besetzt ist, muss ein Protokoll-Paket in eine Liste eingefügt werden können, die zu einem späteren Zeitpunkt abgearbeitet wird. Die Protokoll Pakete
sollen mit möglichst hoher Priorität verschickt werden können.
Die Funktion hamachi_start_xmit() wurde so modifiziert, dass wenn der Sendekanal
besetzt ist eine Protokollmeldung in die vorgesehene Liste eingefügt wird ( Funktion fc_push()).
Andernfalls wird das übergebene Paket sofort versenden. Im Anschluss an eine Sendeoperation wird
die nächste Meldung aus der Liste für wartenden Protokoll Meldungen herausgeholt ( Funktion
fc_pop() ) und versandt. Dieser Vorgang wird wiederholt, bis keine Meldungen mehr in der Liste
sind.
Erst wenn alle Protokollmeldungen abgearbeitet sind, wird aus der Funktion ausgetreten.
4.6 Erfahrungen mit dem Protokoll
Das Protokoll konnte in beiden beschriebenen Varianten implementiert werden.
Für beide Varianten wurden Messungen durchgeführt. Diese Zeitmessungen wurden mit der Funktion gettimeofday() durchgeführt. Mit dieser Funktion können Genauigkeiten im Bereich von
ein paar Mikrosekunden (µs) erfasst werden. Die gemessenen Zeiten waren alle grösser als 100 µs.
Deshalb wurde angenommen, dass die Zeitauflösung dieser Funktion ausreiche.
In der Variante, die ausschliesslich mit UDP arbeitet, war es fast unmöglich, sinnvolle Ergebnisse
über den Zusatzaufwand der mit der Ausführung des Protokolls verbunden ist, zu gewinnen. Ständig blockierte entweder der Sender oder der Receiver. Häufig mussten die Maschinen neu gestartet
werden. Schliesslich gelang es, 100 UDP Pakete der grösse 64000 bytes zu versenden und Zeitmessungen durchzuführen. Es wurden mehrere Messungen gemacht, die einen Durchsatz von ca. 20-25
Seite -21-
MBs auswiesen.
Leider konnten keine Vergleichsmessungen ohne Protokoll gemacht werden. Mit den anderen Treiberversionen blockierte der Sender regelmässig nach wenigen versendeten Paketen.
Bei Messungen des Durchsatzes mit kleineren UDP Paketen ( Paketgrösse 1Kb ) wurde ein Durchsatz von ca. 40 Mbs erreicht. Es muss aber davon ausgegangen werden, dass ein erheblicher Teil der
Geschwindigkeit im UDP Stack verloren geht (bei der Defragmentierung ).
Bei der anderen Version wird der Verbindungsaufbau von einer Applikation verlangt. Anschliessend kann die Applikation so viele Daten verschicken wie sie will. Der Zusatzaufwand der Reservierung der Verbindung ist deshalb abhängig von der Häufigkeit, mit der eine solche Reservierung
gemacht wird.
Aus diesem Grund wurde versucht, die Zeit für einen einzigen Verbindungsaufbau zu messen. Aus
dieser Grösse kann dann geschlossen werden, wie stark der Zusatzaufwand ins Gewicht fällt.
Gemessen wurde die Zeit, die eine Station vom Send-Request bis zum Erhalten der Sendeerlaubnis
warten muss. Die ausgeführten Messungen lieferten Zeiten zwischen 200 und 800 us. Diese grossen
Schwankungen wurden mit der unterschiedlichen Beanspruchung des Switch erklärt.
In dieser Zeit sind auch das Öffnen eines Datagramm Sockets, das Finden des entsprechenden ioctlDevice's sowie der mehrmalige Aufruf der ioctl() Systemcalls beinhaltet.
Wenn man von einer mittleren Zeit von 500 µs ( eine halbe ms ) für einen solchen Verbindungsaufbau ausgeht, einen Durchsatz von 60 Mbs annimmt ( ohne Protokoll ) und für jedes versendete
MB Daten eine Verbindung alloziert und wieder abbricht, so führt dieser Verbindungsaufbau zu einem Geschwindigkeitsverlust von 3 %.
Wenn der Durchsatz ohne Protokoll kleiner ist, fällt auch der Overhead für die Ausführung weniger
ins Gewicht. Dasselbe gilt, wenn der Verbindungsaufbau weniger häufig durchgeführt wird.
Mit dieser Version wurden auch Tests mit drei Maschinen durchgeführt. Es konnte gezeigt werden,
dass die Implementierung des Protokolls tatsächlich den gegenseitigen Ausschluss erzwingt.
Seite -22-
5 Ausblick
Das Ziel der Bemühungen ist es, einen Netzwerkdienst für Hochgeschwindigkeitsverbindungen
einzurichten.
Appliktionen, die diesen Dienst in Anspruch nehmen wollen, müssen sich anmelden. Falls eine
solche Hochgeschwindigkeitsverbindung hergestellt werden kann, können die Daten versendet werden, und die Applikation gibt die Verbindung wieder frei.
In dieser Arbeit wurde gezeigt, dass von den eingesetzten Hardwarekomponenten Möglichkeiten
angeboten werden, um dem Verlust von Daten durch Congestion vorzubeugen. Das kann aber nur
erreicht werden, wenn das Netzwerk nur für kurze Zeit überlastet ist.
Zudem konnte gezeigt werden, dass mit einem geeigneten Protokoll ein gegenseitiger Ausschluss
von zwei Sendern zu demselben Empfänger gewährleistet werden kann.
Um einen Netzwerkdienst für maximalen Durchsatz implementieren zu können, ist beides Voraussetzung. Bis ein solcher high-throughput Service implementiert werden kann, müssen aber sicher
noch viele Probleme gelöst werden.
Sicher muss die QoS Konfiguration des SSR genau verstanden werden. Der Datenstrom einer
Hochgeschwindigkeitsverbindung müsste mit höchster Priorität behandelt werden können. Nur so
kann der Paketverlust auch bei maximaler Netzwerkauslastung klein gehalten werden.
Ferner sollte ein Protokoll für den gegenseitigen Ausschluss im Zero Copy Treiber integriert werden. Das vorgestellte Protokoll erfüllte zwar diese Grundanforderung. Sicher müsste aber auch der
Verlust von Protokollmeldungen behandelt werden. Zudem könnte überlegt werden, wie die ankommenden Anfragen der verschiedenen Sender fair behandelt werden sollen.
Ausserdem müsste der Zugang zum Netzwerk für alle Applikationen, die diesen Netzwerkdienst
nicht in Anspruch nehmen wollen, kontrolliert werden können. In der jetztigen Lage kann eine
Applikation Daten verschicken, ohne eine Verbindung verlangt zu haben. Die verfügbare Leistung
des Empfängers wird nach wie vor gleichmässig für die Behandlung aller hereinkommenden Daten
verwendet.
Beim
Empfänger
wird
also
kein
Unterschied
gemacht
zwischen
Hochgeschwindigkeitsverbindung und »normalem« TCP Stream. Das führt dazu, dass im Treiber
alle Daten kopiert werden müssen und der maximale Durchsatz nicht erreicht werden kann.
Seite -23-
6 Literaturverzeichnis
[1]
Andrew S. Tanenbaum. Computer Networks. Prentice-Hall, Inc., third edition 1996. ISBN 013-394248-1.
[2]
Andrew S. Tanenbaum. Moderne Betriebssysteme. Prentice-Hall, Inc., 2. Auflage 1995. ISBN
0-13-517889-4
[3]
Rich Seifert. Gigabit Ethernet: Technology and Applications for High-Speed LANs. Addison
Wesley, first edition 1998. ISBN 0-201-18553-9.
[4]
W. Richard Stevens. TCP/IP Illustrated, Volume 1. Addison-Wesley, 13-th edition 1999.
ISBN 0-201-63346-9.
[5]
Michael Beck, Harald Böhme, Mirko Dziadzka, Robert Magnus, Dirk Verworner. Linux
Kernel-Programmierung: Algorithmen und Strukturen der Version 2.0. Addison-Wesley,
vierte Auflage 1997. ISBN3-8273-1144-6.
[6]
Michel Müller. Zero-Copy TCP/IP mit Gigabit-Ethernet 1999. ETH Diplomarbeit.
[7]
Roman Roth, Vergleich von Message Passing und Distributed Shared Memory unter
Windows NT 1999. ETH Diplomarbeit.
[9]
Thomas M. Stricker, Christian Kurmann, Michaela Taufer, Felix Rauch. CoPs-Clusters of
PCs: Project Overview. http://www.cs.inf.ethz.ch/CoPs/index.html
[10] Cabletron
Systems,
Inc.
Smart
Switch
Router
http://www.cabletron.com/products/items/SSR-16/. Cabletron System Homepage.
8600.
[11] Cabletron Systems, Inc. SmartSwitch Router 2000 Getting Started Guide.
[12] Cabletron Systems, Inc. SSR User Reference Manual.
[13] Packet Engines, Inc. G-NIC II Hamachi Engeneering
http://www.packetengines.com/. Packet Engines Homepage.
Design
Specification.
[14] Hewlett-Packard Company. Netperf: A Network Performance Benchmark. Revision 2.1,
1996.
Seite -24-
7 Anhang
7.1 A1: Readme zum Inhalt der einzelnen Verzeichnisse
7.2 A1: Konfigurationen des Smart Switch Routers
7.3 A2: Information bez. des Verhaltens des Smart Switch Routers
Seite -25-
Autor
Document
Kategorie
Uncategorized
Seitenansichten
2
Dateigröße
78 KB
Tags
1/--Seiten
melden