Aktualisierung des PTPPatch für Kernel 2.6.15 Überarbeitung des
Transcription
Aktualisierung des PTPPatch für Kernel 2.6.15 Überarbeitung des
Aktualisierung des PTPPatch für Kernel 2.6.15 und Überarbeitung des Codes „Faster Initial Convergence“ von CADPC Name: Martin Rabanser Matrikelnr.: 0217224 Datum: 14.09.2006 Tutor: Michael Welzl Inhaltsverzeichnis 1. Einführung in PTP..................................................................................................................................1 1.1 Problemstellung...............................................................................................................................1 1.2 Das Performance Transparency Protocol (PTP)..............................................................................1 1.3 Einsatzgebiete..................................................................................................................................2 1.4 Die Teststrecke................................................................................................................................3 2. Patchen des Kernels...............................................................................................................................4 2.1 Ausgangssituation...........................................................................................................................4 2.2 Wahl einer geeigneten aktuellen Kernelversion..............................................................................5 2.3 Die Änderungen im Detail..............................................................................................................5 2.4 Kritische Stellen..............................................................................................................................8 2.5 Generieren des PTPPatches............................................................................................................9 2.6 Installation & Test des PTPPatches.............................................................................................10 3. Aktualisierung von CADPC.................................................................................................................12 3.1 Einführung in CADPC..................................................................................................................12 3.2 Faster Initial Convergence.............................................................................................................13 4. Literaturverzeichnis.............................................................................................................................17 5. Anhang.................................................................................................................................................18 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser 1. Einführung in PTP 1.1 Problemstellung Aufgabe dieses Teils der Bakkalaureatsarbeit war es, den bestehenden Kernelpatch für die Version 2.4.26 auf einen aktuellen Kernel (2.6.15) umzuschreiben, damit die Verwendung des PTPProtokolls bzw. dessen Weiterentwicklung auch für die nächste Zukunft gesichert ist. Arbeit und Aufwand dafür sind mit dem Versionssprung des Patches von 2.2 auf 2.4 vergleichbar. 1.2 Das Performance Transparency Protocol (PTP) Bei Netzwerkverbindungen bei denen ständig viele Daten übertragen werden, beispielsweise Streaming, Videotelefonie etc. kommt es vor, dass die Übertragungsrate entweder grösser oder kleiner als die Kapazität eines Routers ist. Im ersten Fall hat die Verbindung einen Flaschenhals und Pakete werden verworfen. Im zweiten Fall wird die Verbindung nicht optimal ausgenutzt da zu wenig Pakete gesendet werden. Genau an diesem Punkt soll das PTPProtokoll eingreifen und die Übertragungsrate an die größtmögliche Bandbreite auf einem Netzwerkpfad anpassen. Das PTPProtokoll wurde von Michael Welzl spezifiziert und soll dazu beitragen den Netzwerkverkehr zu optimieren und Router optimal auszulasten, indem Daten über deren Auslastung gesammelt und ausgewertet werden. Dabei Seite 1 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser werden Bandbreiteninformationen von jedem Router auf einem Netzwerkpfad an Pakete gehängt, welche am Endknoten die Grundlage für die Performanceberechnungen darstellen. Anschließend werden die errechneten Daten dem Sender zurückgeschickt, welcher angemessen auf die Informationen reagieren kann. Ziel ist es, dieses Teilprotokoll mit einem bestehenden Protokoll wie z.B. UDP zu kombinieren, sodass der Anwender (oder die Anwendung) auf einer höheren Schicht von der Optimierung nichts bemerkt und das Protokoll eigenständig und automatisch ein gesamtes Teilnetz optimiert. 1.3 Einsatzgebiete Das PTPProtokoll wurde dazu entwickelt, die Übertragungsraten für Applikationen an die Gegebenheiten des Pfades anzupassen. Ein aktuelles Beispiel dafür wäre die Videotelefonie. Ein weiteres Einsatzgebiet wäre das PTPProtokoll als Administrationstool für eine Domäne, in dem ein Administrator die Kontrolle über all seine Rechner hat. So könnte das Protokoll dazu eingesetzt werden, um dem Administrator zu signalisieren an welchen Stellen sein Netzwerk besonders stark ausgelastet ist bzw. wo es Flaschenhälse gibt. Da dies aber nicht das verfolgte Ziel bei der Spezifikation des Protokolls war, kann es für dieses Szenario durchaus notwendig sein, einige Anpassungen an der Implementierung vorzunehmen. Grundsätzlich kann dieses Protokoll als Grundlage für Staukontrolleverfahren Seite 2 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser wie z.B. CADPC eingesetzt werden, welches weniger Paketverluste und teilweise höhere sowie glattere Übertragungsraten als TCP erreicht. [Michael Welzl: Scalable Performance Signalling And Congestion Avoidance. Kluwer Academic Publishers, August 2003] 1.4 Die Teststrecke Das Testen des PTPProtokolls ist mit einigem Aufwand verbunden, da 2 Endknoten nicht genügen, sondern ein Netzwerk mit mindestens 3 Rechnern zum Einsatz kommen muss, wobei einer davon als Router fungiert. Der Aufwand für den Betrieb der beiden Endknoten ist relativ gering. Es genügt die Installation eines beliebigen Linuxsystems, Voraussetzungen sind lediglich ein funktionierendes Netzwerk in der Version IPv4 und ein “gccKompiler”. Dieser ist zwar nicht zwingend notwendig, aber die Kompilierung der Testprogramme auf dem Zielrechner garantiert deren korrekte Funktion. Eventuell kann auch eine Knoppixdistribution zum Einsatz herangezogen werden, sollten keine Linuxrechner zur Verfügung stehen und/oder eine Neuinstallation zu aufwendig sein. Andere Betriebssysteme kommen derzeit nicht in Frage, da die Sockets mit dem Protokoll Nr. 123 initiiert werden, welches zwar offiziell bei der Authorisierungsstelle angemeldet wurde, aber sicher noch nicht in jedem Betriebssystem verwendet werden kann. Weiters greifen sowohl Client als auch Server auf einen Handler zurück, der auf die posixkonforme IPC von Unix aufsetzt, welche bei weitem nicht von allen Systemen eingehalten wird. Seite 3 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Das Aufsetzen des PTPRouters ist im Vergleich zu den Endknoten wesentlich aufwendiger. Voraussetzung hierfür sind ein beliebiges Linuxsystem sowie der Einsatz des richtigen Kernels und 2 Netzwerkinterfaces. Verwendet wird hier der Standard Vanillakernel dessen Versionsnummer mit der des PTPPatches übereinstimmt, sodass er vor seinem Einsatz erfolgreich gepatcht werden kann. Bei Verwendung anderer Konfigurationen ist keinerlei Funktion gewährleistet. Damit die Pakete richtig geroutet werden muss der Kernel gepatcht und mit allen wichtigen Routerfunktionen übersetzt werden (IPForward). Anschließend wird dieser Kernel gestartet, die Netzwerkinterfaces richtig initialisiert und manuell die Bandbreite des aktuellen Router eingestellt, damit das PTPProtokoll Daten sammeln und auswerten kann. 2. Patchen des Kernels 2.1 Ausgangssituation Ausgangssituation für diese Version war der Patch für den Kernel 2.4.26. Die Vorgangsweise ist dieselbe, nachdem die Codezeilen des alten Patches in die Quelldateien des neuen Kernels eingefügt sind, kann mit dem Testen und Kompilieren begonnen werden. Dabei werden Veränderungen am Netzwerkinterface und den Strukturen geklärt, notiert und der Zugriff darauf so lange angepasst bis eine korrekte Funktion des PTPRouters sichergestellt ist. Diese sollen im Folgenden genauer beschrieben werden. Seite 4 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser 2.2 Wahl einer geeigneten aktuellen Kernelversion Zur Zeit dieser Entscheidung befand sich die aktuelle Kernelversion des Kernel 2.6 gerade auf Versionsnummer 2.6.15. Durch die stetige Weiterentwicklung des Kernels ist die Verbreitung dieser Version schwierig abzuschätzen, jedoch bedarf es für einen Versionssprung des Patches innerhalb des 2.6er Kernels keinen großen Aufwand. Die relevanten Files des Netzwerkinterfaces werden innerhalb derselben Kernelversion bis auf Korrekturen von Bugs und Erweiterung der Funktionalität nicht verändert. Zur Zeit der Entstehung dieses Dokumentes existieren weder für Kernel 2.7 noch 2.8 Vorabversionen, sodass eine Portierung auf diese noch nicht in Betracht gezogen werden kann. 2.3 Die Änderungen im Detail Da testweises Patchen des Kernel 2.6.15 mit dem Patch linux2.4.26ptp.patch mit unzähligen Fehlern abbrach, musste jede Zeile des Patches für den Kernel 2.4.26 manuell in den Quellcode des Kernels 2.6.15 eingefügt werden. Die Schwierigkeit bestand zum Einen darin die richtigen Stellen zu finden, da sich die Netzwerkimplementierung des IPProtokolls v4 von Kernel 2.4 auf 2.6 wie schon von 2.2 auf 2.4 etwas geändert hatte. Weit aufwendiger war auch hier das Verstehen des Codes und die Suche von Funktionen, die es von Version 2.4 auf Version 2.6 entweder nicht mehr gab, oder veränderte Datentypen oder Aufrufe aufwiesen. Zu Gute kamen hier die die bereits gemachten Erfahrungen beim Seite 5 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Anpassen des Patches von Version 2.2 auf 2.4, da die Funktionalität des Netzwerkinterfaces im Kernel 2.4 schon bekannt war. Auf die Angabe der Zeilenänderungen wird wiederum verzichtet, da der Kernel manuell gepatcht wurde und die richtigen Codestellen ohnehin gesucht werden mussten. Die Angaben der Zeilennummern werden später im Kernelpatch automatisch mitprotokolliert. Die Deklaration static &ptp_inode.u.socket_i; struct wurde auf socket static *ptp_socket; reduziert, da die Struktur static *ptp_socket struct struct = socket inode ptp_inode; nicht mehr existiert. Eine neue Bibliothek musste mittels #include <linux/rtnetlink.h> eingebunden werden, um auf die Konstante RT_SCOPE_UNIVERSE zugreifen zu können. Weiters hat sich die Struktur struct net_device_stats so verändert, dass auf die übermittelten Bytes nun direkt zugegriffen werden kann. Also von htonl(stats->stats->tx_bytes); auf htonl(stats->tx_bytes);. Um auf die Funktion ip_send_reply() zugreifen zu können, musste die Bibliothek #include <net/ip.h> eingebunden werden. Eine große Anzahl von Fehlern mit der Information der Dereferenzierung eines Zeigers auf unvollständige Typen hat die mangelnde Einbindung der Bibliothek #include <linux/ip.h> bereitet. Auf diese Fehler wird hier nicht genauer Seite 6 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser eingegangen, die Datei mit dem Fehler log kann im Anhang eingesehen werden. Die Codezeile arg.n_iov = 2; bereitete einen Fehler, da die Struktur arg kein Element namens n_iov mehr hat. Da dies nicht weiter schlimm ist, wurde die Zeile einfach ausgeklammert. In Struktur struct sock; hat sich der Name des Elementes allocation wie folgt verändert: Von ptp_socket->sk->allocation = GFP_ATOMIC; auf ptp_socket->sk->sk_allocation = GFP_ATOMIC;. Auch das Setzen der maximalen TTLZeit muss nun anders gehandhabt werden: Aus ptp_socket->sk->protinfo.af_inet.ttl = MAXTTL; wird inet_sk(ptp_socket->sk)->uc_ttl = MAXTTL;. Folgende Zeilen sind im Netzwerkinterface des 2.6.15er Kernels nicht mehr von Relevanz und wurden ausgeklammert: // ptp_inode.i_mode = S_IFSOCK; // ptp_inode.i_sock = TRUE; // ptp_inode.i_uid = 0; // ptp_inode.i_gid = 0; // ptp_socket->inode = &ptp_inode; Wiederum in Struktur struct sock; muss auf das Element num anders zugegriffen werden. Anstatt ptp_socket->sk->num = 256; wird der Wert Seite 7 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser nun mit inet_sk(ptp_socket->sk)->num = 256; gesetzt. Die Versionen der „automake“Pakete sind mit der neuen Kernelversion auch weitergereift, deshalb war es notwendig auch die Makefiles und Konfigurationsdateien des Kernels zu verändern. Wie deren Syntax gehandhabt wird kann sowohl im Anhang enthaltenen Quellcode des Patches eingesehen werden, sowie in der „automake“ bzw. Kerneldokumentation nachgelesen werden. Alle anderen Codezeilen des PTPProtokolls wurden nur an den richtigen, zum Teil verschobenen, Zeilen eingefügt. Die Zeilennummern sind allein im Patch ersichtlich. 2.4 Kritische Stellen Bei der Anpassung des Protokolls gab es schon bei der Portierung auf den Kernel 2.4 es einige Stellen die bis nach der Testphase als kritisch galten. Diese seien hier aufgeführt, auch weil diese bei der Portierung auf den aktuellen Kernel Schwierigkeiten bereiten hätten können. In Datei linuxkernel/include/linux/sysctl.h wurden im Kernelpatch 2.4.26 zwischen Zeile 348 und 368 bei folgendem Enum weitere Einträge angefügt, sodass die Konstante NET_IPV4_CONF_IF_SPEED nun den Wert 20 erhält. Diese Zeile galt damals als kritisch, da nicht sicher war ob der Wert 20 in Zukunft von einer anderen Konstanten im Enum genutzt wird. Diese Seite 8 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Initialisierung hat sich nun aber geändert und kann somit als unkritisch betrachtet werden. Als kritisch gelten könnten auch die obengenannten entfernten Codezeilen. Da jedoch alle Berechnungen sowie Tests dagegen sprechen werden diese als überflüssig betrachtet und somit deren Entfernung gerechtfertigt. 2.5 Generieren des PTPPatches Nachdem alle Einträge des „alten“ Patches im neuen Kernel an deren richtigen Stellen eingefügt sind und die Kompilierung des manuell gepatchten Kernel keinen Fehler mehr ergibt, kann die erste Version des neuen Kernelpatches generiert werden. Wie dieser erstellt wird, kann jederzeit im Patch selbst überprüft bzw. nachgeschlagen werden. Verwendet wird hierbei der Befehl diff, welcher Unterschiede zwischen Dateien findet. Voraussetzung sind Verzeichnisse namens linux-2.6.15, welches den originalen entpackten Vanillakernel 2.6.15 enthält, und linux-2.6.15-ptp, welches einen entpackten und manuell gepatchten Kernel enthält. Vor dem Generieren des Patches muss sichergestellt sein, dass sich keine Objektdateien oder dergleichen in den Verzeichnissen befinden. Dies stellt der Befehl make mrproper sicher, welcher die Verzeichnisse „säubert“. Anschließend vergleicht der Befehl diff -Naur linux-2.6.15/ linux-2.6.15.ptp/ > linux2.6.15-ptp.patch den Inhalt aller Unterverzeichnisse und Dateien des originalen Kernels mit jenen des manuell Gepatchten und schreibt die Seite 9 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Unterschiede in die Datei linux-2.6.15-ptp.patch mit. Die vergleichsweise unkomplizierte Generierung des Patches ist somit abgeschlossen und erste Tests können gestartet werden. 2.6 Installation & Test des PTPPatches Damit das PTPProtokoll nun mit dem neuen Kernel getestet werden kann, muss der Kernel gepatcht werden. Damit wird auch der Patch selbst auf dessen korrekte Funktion getestet werden. Der Befehl patch -p0 < linux-2.6.15ptp.patch, ausgeführt im selben Verzeichnis wo er erstellt wurde (impliziert die Option p0) auf einen neu entpackten Vanillakernel 2.6.15, modifiziert die Quelldateien wie gewünscht. Im nächsten Schritt wird der Kernel kompiliert, wobei darauf geachtet werden muss, dass die Option, den PTPCode mit zu übersetzen, auch aktiviert ist. Damit diese Option anwählbar ist, bedarf es der Aktivierung des Schalters Prompt for development Menüpunkt Code maturity and/or level incomplete code/drivers im options. Standardmäßig ist diese Option schon aktiviert. Anschließend kann unter Networking->Networking Options der Punkt IP: PTP support (EXPERIMENTAL) (NEW) angewählt werden. Zu beachten ist weiters die grundsätzliche Aktivierung der Netzwerkunterstützung inklusive der Auswahl der richtigen Treiber für die Netzwerkhardware, sowie für IPForwarding. Seite 10 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Sobald der Kernel erfolgreich übersetzt und der Router mit diesem gestartet wurde, benötigt das Protokoll für einen funktionierenden Einsatz noch die Information über die Kapazität der Netzwerkverbindung. Dies muss manuell im /proc Verzeichnis gesetzt werden und wird von folgenden Codezeilen automatisiert, vorausgesetzt die Netzwerkschnittstellen zwischen in Verbindung mit den beiden Endknoten sind jeweils eth0 und eth1: echo 10000 > /proc/sys/net/ipv4/conf/all/mib2_if_speed echo 10000 > /proc/sys/net/ipv4/conf/default/mib2_if_speed echo 10000 > /proc/sys/net/ipv4/conf/eth0/mib2_if_speed echo 10000 > /proc/sys/net/ipv4/conf/eth1/mib2_if_speed Hierbei wird MIB2_IF_SPEED auf den Wert 10000 gesetzt. Dies ist kein reeller Wert und dient lediglich zum Testen. Zur Überprüfung der korrekten Funktion des neuen PTPKernels wurden die bereits bestehenden Client/ServerProgramme herangezogen. Da diese für den Kernel 2.4 umprogrammiert und verwendet wurden und bereits dort aktuelle Distributionen verwendet wurden, liefen sie auch beim Test für den Kernelpatch 2.6.15 ohne Probleme. Deren Funktionen sind im Dokument „Aktualisierung des PTPProtokolls“ genauestens beschrieben. Seite 11 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser 3. Aktualisierung von CADPC 3.1 Einführung in CADPC Congestion Avoidance with Distributed Proportional Control (CADPC) ist ein Netzwerkprotokoll, das von Michael Welzl für die Dissertation Scalable Performance Signalling and Congestion Avoidance entwickelt wurde. Die Idee des Protokolls besteht darin, im Unterschied zu TCP und UDP Zusatzinformationen über einen Pfad im Internet zu sammeln und entsprechend zu verwerten. Diese Informationen bestehen vorwiegend aus Bandbreiteninformationen der einzelnen Router die Aufschluss über deren verfügbaren Kapazitäten geben. Für das korrekte Sammeln dieser Informationen wird Performance Transparency Protocol (PTP) verwendet, ebenfalls von Michael Welzl entwickelt. PTP setzt auf IP auf, wobei die Informationen im selben Format gesammelt werden wie über SNMP, welches von Netzwerktools verwendet wird. Mit PTP werden Informationen abgefragt, die für SNMPMIB2 zur Verfügung gestellt werden. Aus diesen Informationen kann CADPC am Endpunkt eines Pfades Staukollisionen berechnen. Im Unterschied zu TCP, welches jeweils Antwortpakete erwartet und so Kollisionen nur dadurch bemerkt indem es sie selbst erzeugt. Trotzdem bietet TCP sowohl eine zuverlässige Übertragung als auch eine intelligentes Bandbreitenhandling. Seite 12 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Im Vergleich ignoriert UDP Staukollisionen seinerseits völlig. CADPC stellt weder eine Konkurrenz zu UDP noch zu TCP dar, da es einerseits selbst keine Netzwerkschicht definiert und andererseits die gesammelten Daten von anderen Protokollen bezieht, die zur Berechnung der Bandbreiteninformationen notwendig sind. Beim Einsatz von PTP sind die Dienste von Client und Server nicht im eigentlichen Sinne zu verstehen. Der Server, welcher Daten mit limitierter Bandbreite schickt muss gleichzeitig PTPPakete erzeugen und an den Zielrechner bzw. Client schicken. Dieser wiederum muss jene Pakete abfangen, auswerten und das Ergebnis zurück an den eigentlichen Server schicken. Somit dient der Client während des Einsatzes von PTP als Informationsserver für den eigentlichen Sender. 3.2 Faster Initial Convergence Der Einsatz von CADPC und PTP bietet für bestehende dauerhafte Verbindungen wie z.B. Streaming Vorteile. Messungen belegen aber ein Verhalten, dass bei wachsendem Netzwerkverkehr die Dauer der Konvergierung zur maximalen Übertragungsrate von hinzukommenden Verbindungen proportional zur bereits bestehenden Anzahl von Verbindungen ist. Zum Teil dauert das Konvergieren bis zur maximalen Übertragungsrate eines Streams länger als die Übertragung selbst dauert. Dieses Verhalten wird in Kapitel 4.4.2 Seite 13 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser der Originaldokumentation Scalable Performance Signalling and Congestion Avoidance ausführlich behandelt und mathematisch optimiert. Die Optimierung sieht vor die Verbindungsraten konstant zu überprüfen und im Falle einer neuen, hinzukommenden Verbindung deren Rate manuell zu steigern. In der Implementierung geschieht dies in Datei cadpc.cc in der Funktion updateRate(). Der bestehende Code wurde so umgeschrieben, dass er sich so eng wie möglich an die bereits aktualisierte Dokumentation hält. Zwar wurde der Code dadurch modifiziert, das Verhalten des schnellen StartupMechanismus verändert sich damit jedoch nicht, da die dokumentierten mathematischen Formeln optimiert sind und deshalb entsprechend implementiert sein müssen. Anschließen wurde er von veralteten und zum Teil überflüssigen Kommentaren sowie auskommentierten Aufrufen gesäubert und durch aktuelle ersetzt. Mit dem Protokoll wurden keine Tests durchgeführt, um die Effizienz des schnelleren Startupmechanismus zu belegen. Diese Tests wurden bereits von Ben Lavender in seinem Report on using PTP for CADPC dokumentiert. Zwischen der dort verwendeten und der aktuellen Version von CADPC gibt es keine Unterschiede in der Funktionalität und den erzielten Ergebnissen. Im Folgenden werden die verwendeten Variablen und Formeln erläutert. In Tabelle 1 sind die verwendeten Variablen in den mathematischen Formeln zusammengefasst und mit deren Codependant aufgelistet. Da der theoretische Seite 14 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Teil des Mechanismus durch mathematischen Berechnungen belegt ist, werden dort naheliegenderweise mathematische Ausdrücke und Variablenbezeichnungen verwendet. Im Code werden dagegen, zur besseren Übersicht des Programmierers, aussagekräftige Variablenbezeichnungen verwendet. Mathematische Variable Codevariable m addUsers n convUsers_ x convRate_ x(t) currentRate x(t+1) newRate a smoothness lambda(0) traffic lambda(t) convTraffic ny supConvTraffic Tabelle 1: Mathematische Variablenbezeichnungen in Formeln und entsprechend im Code Tabelle 2 zeigt wie die mathematischen Formeln im Code kommentiert sind. Für die Implementierung selbst werden die Variablen laut Tabelle 1 verwendet. Die jeweils darüberstehenden Kommentare dienen lediglich zur bessern Lesbarkeit des Codes. Die Spalte der Kapitel bezieht sich auf den Abschnitt in der Seite 15 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser Originaldokumentation Scalable Performance Signalling and Congestion Avoidance. Kapitel 4.11 Formel Code x t1=x t a1− x t− t k x t x(t + 1) = x(t) + x(t) * a * (1 x(t) – k * lambda(t)) 4.12 n= t 1−t 4.13 4.14 n y =n x = 1−t n = lambda(t) / (1 lambda(t))" ; "m = (lambda(t) ny) / x(t) ny = (n * (1 lambda(t)) / (n + 1) n1 1 x = 1 / (n + m + 1) nm1 Tabelle 2: Vergleich mathematische Formeln und Code Seite 16 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser 4. Literaturverzeichnis • Michael Welzl.:Scalable Performance Signalling And Congestion Avoidance. Kluwer Academic Publishers, August 2003, ISBN 1402075707 • Alessandro Rubini, Jonathan Corbet: Linux Device Drivers, 2nd Edition. O'Reilly Juni 2001, ISBN 0596000081 • The Linux Kernel API, GNU Seite 17 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser 5. Anhang cadpc.cc #include "cadpc.h" #include <stdio.h> int hdr_cadpc::offset_; // static offset of CADPC header static class CADPCHeaderClass : public PacketHeaderClass { public: CADPCHeaderClass() : PacketHeaderClass("PacketHeader/CADPC", sizeof(hdr_cadpc)) { bind_offset(&hdr_cadpc::offset_); } } class_cadpchdr; static class CADPCClass : public TclClass { public: CADPCClass() : TclClass("Agent/CADPC") {} TclObject* create(int, const char*const*) { return (new CADPCAgent()); } } class_cadpc; void CADPCIpgTimer::expire(Event *) { a_->timeout(CADPC_IPG_TIMEOUT); } void CADPCRttTimer::expire(Event *) { a_->timeout(CADPC_RTT_TIMEOUT); } //---------------------------------------------------------------------// CADPCAgent::CADPCAgent // Initialize the CADPC agent. // Bind variables which have to be accessed in both Tcl and C++. // Initializes time values. //---------------------------------------------------------------------CADPCAgent::CADPCAgent() : Agent(PT_CADPC_DATA), ipgTimer_(this), rttTimer_(this), ipg_(2.0), timeout_(2.0), rttFactor_(2.0), smoothness_(1.0) { bind("packetSize_", &size_); bind("timeout_", &timeout_); // Default 2 seconds Seite 18 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser // multiply the RTT for feedback timeout with this factor bind("rttFactor_", &rttFactor_); // Default 2.0 // smoothness of the control (factor a in equation) bind("smoothness_", &smoothness_); // Default 0.5 bind("startup_", &startup_); // Default 1 bind("maxrate_", &maxrate_); bind("rateMultiplier_", &rateMultiplier_); firstTime_ = TRUE; convRate_ = 0; convTraffic_ = 0; convUsers_ = 0; addUsers_ = 1; oldTraffic_ = 0; feedback_received_ = 0; timeoutOccured_ = FALSE; running_ = 0; ipg_ = 2.0; // TRUE = remember: don't update rtt // will be changed with the first PTP-ACK anyway } // Cancel all our timers before we quit CADPCAgent::~CADPCAgent() { stop(); } //---------------------------------------------------------------------// CADPCAgent::UpdateTimeValues // Update the values for srtt_, variance_ and timeout_ based on // the "sampleRtt". Use Jacobson/Karl's algorithm. // // "sampleRtt" is the sample round trip time obtained from the // current ack packet. //---------------------------------------------------------------------void CADPCAgent::UpdateTimeValues(double sampleRtt) { timeout_ = sampleRtt*rttFactor_; } //---------------------------------------------------------------------// CADPCAgent::UpdateRate // The core part of CADPC: update ipg; calculate rate according to the // CADPC formula: rate(t+1) = rate(t)*(r0+1-r0*rate(t)-traffic) // // our traffic and rates are normalized, r0=1 // this yields: rate(t+1)=rate(t)*(2-rate(t)-traffic) // // "sampleRtt" is the sample round trip time obtained from the // current ack packet. //---------------------------------------------------------------------- Seite 19 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser void CADPCAgent::updateRate(double traffic, double bottleneckBW, double sampleRtt, int priority) { if(traffic>1) { traffic=1; } /* ipg2rate conversion + normalization */ double currentRate = (size_ / ipg_) / bottleneckBW; /* act like how many flows? */ currentRate /= rateMultiplier_; /* "x(t+1) = x(t) + x(t) * a * (1-x(t) - lambda(t))" */ double newRate = currentRate + currentRate*smoothness_*(1.0-currentRate-traffic); /* startup mechanism */ if(startup_) { /* if first time or traffic decreased*/ if(firstTime_ || ((traffic-currentRate)<=convTraffic_)) { /* "lambda = lambda(t) - x(t)" */ convTraffic_ = traffic-currentRate; if(traffic>0.5) { /* "n = lambda / (1 - x(t) - lambda)" special form of 4.12 */ convUsers_ = convTraffic_ / (1.0-currentRate-convTraffic_); /* "x = 1 / (n + 1 + m)" see 4.14 */ convRate_ = (1.0)/(convUsers_+1.0+addUsers_); } else { /* special case: total system startup "n = 0", "x = 0,5" */ convUsers_ = 0; convRate_ = 0.5; } firstTime_ = FALSE; } /* not firsttime, traffic not decreased, other new users (m) */ else { /* no update if system is overloaded */ if(traffic < 1.0) { /* addTraffic = additional traffic (without me) */ double addTraffic = traffic - currentRate - convTraffic_; if(addTraffic > 0) { /* "ny = lambda", "ny = (n * (1 - x(t) - lambda(t)) / (n + 1)" see 4.13 */ double supConvTraffic = traffic < 0.5 ? convTraffic_ : convUsers_*(1.0-currentRate-addTraffic)/(convUsers_+1.0); /* update if m incrases - this is sure! */ Seite 20 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser if ((traffic-supConvTraffic)/currentRate > addUsers_) { /* addUsers_ includes me "m = (lambda(t) - ny) / x(t)" */ addUsers_ = (traffic-supConvTraffic)/currentRate; } /* "x = 1 / (n + 1 + m)" see 4.14 */ convRate_ = (1.0)/(convUsers_+1.0+addUsers_); } } } /* rate update */ if((traffic < 1.0) && (traffic > 0.5)) /* "k = (1 - x - x(t)) / x" "x(t + 1) = x(t) + x(t) * a * (1 - x(t) - k*lambda(t))" see 4.11 */ newRate = currentRate + currentRate*smoothness_* (1.0-currentRate-(1.0-(convRate_ - currentRate)/(convRate_))*traffic); else /* "x(t + 1) = x(t) + x(t) * a * (1 - x(t) - lambda(t))" see 4.11 */ newRate = currentRate + currentRate*smoothness_*(1.0-currentRate-traffic); /* when to end startup */ if (!firstTime_ && ( (newRate > convRate_) || (currentRate > convRate_) || (traffic < 0.5)) ) startup_ = FALSE; } /* end startup mechanism */ /* de-normalize rate */ newRate = newRate * bottleneckBW; if(newRate <= 0) { printf("error: calc. rate <= 0! setting rate to 1 pkt/rtt...\n"); newRate = size_/sampleRtt; } /* limit */ if((maxrate_ > 0.0)&&(newRate > maxrate_)) { newRate = maxrate_; } /* act like how many flows? */ newRate *= rateMultiplier_; /* rate2ipg conversion */ ipg_ = size_ / newRate; oldTraffic_ = traffic - currentRate; feedback_received_ = 1; } //---------------------------------------------------------------------void CADPCAgent::stop() Seite 21 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser { // SHOULD BE CORRECTED: ALWAYS ACTIVATES STARTUP startup_ = TRUE; firstTime_ = TRUE; convRate_ = 0; convTraffic_ = 0; convUsers_ = 0; addUsers_ = 1; oldTraffic_ = 0; feedback_received_ = 0; timeoutOccured_ = FALSE; running_ = 0; ipg_ = 2.0; // remember: don't update rtt // will be changed with the first PTP-ACK anyway // Cancel the timer only when there is one if (ipgTimer_.status() == TIMER_PENDING) ipgTimer_.cancel(); if (rttTimer_.status() == TIMER_PENDING) rttTimer_.cancel(); } //---------------------------------------------------------------------// CADPCAgent::command // Called when a Tcl command for the CADPC agent is executed. // Two commands are supported // $cadpcsource start // $cadpcsource stop //---------------------------------------------------------------------int CADPCAgent::command(int argc, const char*const* argv) { if (argc == 2) { if (strcmp(argv[1], "stop") == 0) { stop(); return (TCL_OK); } } if (argc == 3) { if (strcmp(argv[1], "updateSampleRTT") == 0) { // double pingRTT = atof(argv[2])/1000.0; double pingRTT = atof(argv[2]); UpdateTimeValues(pingRTT); // printf("parameter: %f\n", atof(argv[2])); ipg_ = pingRTT; feedback_received_ = 1; // no timeout at the beginning RttTimeout(); // don't cause PTP packet loss at the beginning... ipgTimer_.resched(pingRTT/2.0); running_=1; Seite 22 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser return (TCL_OK); } else if (strcmp(argv[1], "start") == 0) { ptpAgent_ = (PTPAgent*)TclObject::lookup(argv[2]); ptpAgent_->ptpinit_ = 1; feedback_received_ = 1; // no timeout at the beginning RttTimeout(); return (TCL_OK); } } else { if (strcmp(argv[1], "recvptp") == 0) { // argv[2] = normalized traffic, argv[3]=bottleneckBW, argv[3] = sampled rtt recvptp(atof(argv[2]), atof(argv[3]), atof(argv[4]), atoi(argv[5])); //if(!running_) { // IpgTimeout(); // running_=1; //} return (TCL_OK); } } // If the command hasn't been processed by CADPCAgent()::command, // call the command() function for the base class return (Agent::command(argc, argv)); } //---------------------------------------------------------------------// CADPCAgent::recv // Called when a packet is received. //---------------------------------------------------------------------void CADPCAgent::recv(Packet* pkt, Handler*) { hdr_cadpc* hdr = hdr_cadpc::access(pkt); // Access CADPC header // the receiver - maybe we want to do something with the packet? // shouldn't really be necessary in CADPC Packet::free(pkt); // Discard the packet } //---------------------------------------------------------------------// CADPCAgent::recvptp // Called when a ptp packet is received: // update rate & srtt, resched rtt-timeout //--------------------------------------------------------------------void CADPCAgent::recvptp(double normalizedTraffic, double bottleneckBW, double sampleRTT, int priority) { // only update rtt if there was no timeout Seite 23 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser if(!timeoutOccured_) UpdateTimeValues(sampleRTT); timeoutOccured_ = FALSE; // printf("sample rtt: %f ", sampleRTT); // printf("new timeout: %f\n", timeout_); updateRate(normalizedTraffic, bottleneckBW, sampleRTT, priority); if(priority==0) stop(); // RttTimeout(); } //---------------------------------------------------------------------// CADPCAgent::timeout // Called when a timer fires. // // "type" is the type of Timeout event //---------------------------------------------------------------------void CADPCAgent::timeout(int type) { if (type == CADPC_IPG_TIMEOUT) IpgTimeout(); else if (type == CADPC_RTT_TIMEOUT) RttTimeout(); else assert(FALSE); } //---------------------------------------------------------------------// CADPCAgent::IpgTimeout // Called when the ipgTimer_ fires. //---------------------------------------------------------------------void CADPCAgent::IpgTimeout() { Packet *pkt; pkt = allocpkt(); // nothing to be done about the header send(pkt, 0); ipgTimer_.resched(ipg_); } //---------------------------------------------------------------------// CADPCAgent::RttTimeout // Called when the rttTimer_ fires. //---------------------------------------------------------------------void CADPCAgent::RttTimeout() { if(!feedback_received_) { //printf("PTP timeout!\n"); timeoutOccured_ = TRUE; // ignore the next sampleRtt //ipg_ *= 2.0; //timeout_ *= 2.0; Seite 24 von 10 Aktualisierung des PTPPatch für Kernel 2.6.15 Martin Rabanser } if(running_) feedback_received_ = 0; ptpAgent_->sendit(); rttTimer_.resched(timeout_); } Seite 25 von 10