Die Quality-of-Service-Funktionen der großen Router von Cisco & Co. kennen die meisten Admins. Dass Linux Vergleichbares zu bieten hat, ist vielen jedoch nicht bewusst. Eine Ursache ist, dass der Traffic-Control-Befehl »tc« lange Zeit mangelhaft dokumentiert war. Die Lücke füllt inzwischen das LARTC- Howto[1] (Linux Advanced Routing and Traffic Control), seither steigt der Bekanntheitsgrad des Tools. Zudem erklärt ein Artikel zu QDisc in diesem Heft die Grundlagen und beschreibt den Einsatz von »tc« anhand einiger Bespiele.
Trotz aller Dokumentation ist »tc« unnötig kompliziert und folglich fehleranfällig. Um auch diese Hürde zu überwinden, hat Werner Almesberger mit dem Befehl »tcng« ein neues Framework für die Konfiguration der Bandbreitenkontrolle geschaffen[2]. Das Traffic Control Next Generation besteht im Wesentlichen aus den Befehlen »tcng« (ehemals »tcc«) und »tcsim«.
Das »tcng«-Programm arbeitet als Compiler, der eine eigens entwickelte Hochsprache zur Bandbreitenkonfiguration in die komplizierten Einzel-Konfigurationsschritte übersetzt. Das Kommando erzeugt auf Wunsch ein Skript mit »tc«-Befehlen oder direkt ein neues, in C implementiertes Linux-Kernelmodul.
Wer auf seinem Host die Konfiguration für andere Traffic-Shaping-Geräte entwickeln will, bekommt von TCng Unterstützung. Der Compiler vereinfacht die Konfiguration und übergibt sie als Zwischensprache an ein plattformspezifisches Programm, das die korrekte Syntax für die Zielhardware schreibt.
Nur simuliert
Der Simulator »tcsim« verarbeitet Skripte in den Sprachen von »tc« und »tcng«. Dabei setzt »tcsim« Originalcode aus dem Linux-Kernel und aus IProute2[3] ein, um näher am Original zu sein als dies mit allgemeinen Simulatoren gelingt. Mit TCsim lassen sich neue Konfigurationen virtuell testen, bevor sie im realen Einsatz Probleme verursachen. Traffic Shaping muss sich besonders in Grenzsituationen bewähren, die hoffentlich nicht täglich eintreten. Ein simulierter Test gibt dem Admin die nötige Gewissheit, dass sein TCng-Skript wie gewünscht arbeitet.
Das Übersetzen von TCng[2] ist wegen der komplizierten Architektur von TCsim recht aufwändig. Da der Simulator fremden Code einbindet, müssen die Kernel- und IProute2-Pakete im Quelltext zur Verfügung stehen. Dabei sollte es sich um einen Linux-Kernel 2.4.20 bis 2.4.27 handeln und das IProute2-Paket sollte mindestens die Versionsnummer 2.6.8-ss040730 tragen[3]. In älteren Paketen fehlt noch der HTB-Filter (Hierarchical Token Bucket).
Eine kleine Falle steckt in den Quellen von IProute2: Hier sind nach dem Herunterladen und Auspacken noch Rechte anzupassen. Das ist mit »chmod 644 iproute2-2.6.8/lib/* iproute2-2.6.8/tc/*« aber schnell erledigt. Danach folgt der Configure-Aufruf im Quellbaum von TCng: »./configure -k Kernelquellen -i IProute2-Quellen« gefolgt von »make && make test && make install«. Achtung: Die Kernelquellen müssen vor dem Übersetzen von TCng bereits konfiguriert sein (»make config«). Wer den Simulator »tcsim« nicht braucht, kommt auch ohne die zusätzlichen Quelltextbäume aus. Dann genügt der Configure-Aufruf »./configure --no-tcsim«.
|
Klassisches Traffic Shaping ordnet die zu sendenden Pakete mit einer Queueing Discipline. QDiscs sind Puffer, die Pakete annehmen und weitersenden. Um einzelne Pakete oder Verbindungen unterschiedlich zu priorisieren, richtet ein Algorithmus mehrere Warteschlangen unterschiedlicher Priorität ein.
Es gibt viele QDiscs mit verschiedenen Charakteristika. Am einfachsten ist das Fifo. Es nimmt die Pakete auf, speichert sie und schickt sie in derselben Reihenfolge weiter. Wird der Verkehr auf zwei Fifos mit unterschiedlicher Priorität aufgeteilt, behandelt der Kernel eine Hälfte bevorzugt. Der Nachteil: Innerhalb der Fifos erfolgt keine gleichmäßige Bearbeitung des Verkehrs. Es handelt sich trotzdem um die Default-QDisc unter Linux.
Sinnvoller ist der Einsatz einer SFQ-QDisc (Stochastic Fair Queueing). Sie verteilt den Verkehr auf 127 interne Fifo-Warteschlangen, die sie gleichmäßig abarbeitet. Das erzeugt eine stochastisch faire Verteilung.
Token Bucket
Ein Token Bucket dient dazu, die Bandbreite zu begrenzen. Es arbeitet ähnlich wie ein Eimer (Bucket), der sich mit konstanter Geschwindigkeit mit neuen Tokens füllt. Ist der Eimer voll, gehen ab diesem Zeitpunkt alle neuen Token verloren. Will der Kernel ein Paket senden, prüft er, ob im Eimer noch ausreichend Tokens übrig sind. Wenn ja, sendet er das Paket und entnimmt die entsprechende Anzahl Tokens. Andernfalls verzögert er das Paket.
Treffen Pakete und Tokens mit gleicher Geschwindigkeit ein, können alle Pakete sofort gesendet werden. Erreichen die Pakete den Bucket schneller als die Tokens, verzögert sich der Versand. Eine besondere Variante ist der Hierarchical Token Bucket. Damit lässt sich die Netzwerkbandbreite hierarchisch immer weiter unterteilen.
Engpass
Traffic Shaping ist nur am Nadelöhr einer Verbindung sinnvoll. Es setzt voraus, dass sich die Pakete auf keinem anderen System nennenswert lange in Warteschlangen aufhalten und dass kein Paket die Warteschlange vor dem Nadelöhr umgeht.
Wenn es sich bei dem Gerät nicht um den Flaschenhals handelt, muss das Traffic Shaping den Engpass künstlich erzeugen. Ist das TC-Gerät mit 100 MBit/s an ein Netzwerk angebunden, das nur über eine DSL-Leitung am Internet hängt, kann Traffic Shaping auch lediglich die Bandbreite der DSL-Leitung aufteilen und nicht die vollen 100 MBit/s. Sobald sich weiter in Richtung Upstream ein engerer Flaschenhals befindet, muss es auch diesen berücksichtigen.
|
Hochsprache
Die TCng-Hochsprache erlaubt es, in einer C-ähnlichen Syntax die Bandbreiten und Filter übersichtlich und hierarchisch strukturiert zu definieren. Das folgende einfache TCng-Skript befördert alle Pakete, die über die erste Netzwerkkarte »dev eth0« das System verlassen (im Beispiel ein »egress«-Filter) in einen Fifo-Buffer (First in, first out):
dev eth0 {
egress {
fifo;
}
}
Trägt dieses Skript den Namen »example .tcng«, dann übersetzt »tcng -r example .tcng« es in ein TC-Skript. Die Ausgabe ist in Listing 1 dargestellt. Die Option »-r« sorgt dafür, dass der Compiler einen Befehl hinzufügt, der zu Beginn alle eventuell vorhandenen QDiscs (Queueing Disciplines) entfernt. Die Syntax des TC-Befehls beschreibt der QDisc-Artikel in diesem Heft.
01 tc qdisc del dev eth0 root
02
03 # ================= Device eth0 ==================
04
05 tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0
06 tc qdisc add dev eth0 handle 2:0 parent 1:0 pfifo
|
Ein aufwändigeres Beispiel priorisiert den Netzwerkverkehr. Das TCng-Skript in Listing 2 bevorzugt gezielt den (meist interaktiven) SSH-Verkehr. In einer C-ähnlichen Syntax lädt das Skript in den Zeilen 1 und 2 die beiden Dateien »ports .tc« und »fields.tc«. Erstere enthält Platzhalter für viele bekannte und übliche TCP- und UDP-Ports (etwa »PORT_ SMTP« statt Nummer 25), während »fields.tc« den verschiedenen Feldern in den TCP/IP-Headern einfachere Namen gibt. Statt »tcp_hdr[0].ns« darf der Admin nun wesentlich lesbarer »tcp_sport« schreiben. Das Skript muss die Dateien nicht explizit laden, TCng erledigt das per Default automatisch.
01 #include <ports.tc>
02 #include <fields.tc>
03
04 dev eth0 {
05 egress {
06 class (<$smtp>) if tcp_hdr[2].ns == 25;
07 class (<$ssh>) if tcp_dport == PORT_SSH;
08 class (<$other>) if 1;
09 prio {
10 $smtp = class {fifo (limit 10kB);};
11 $ssh = class {fifo (limit 10kB);};
12 $other = class {fifo;};
13 }
14 }
15 }
|
In Zeile 4 folgt das Interface »eth0«, auf das sich die folgenden Filter und QDiscs in den geschweiften Klammern beziehen. Für jedes Interface dürfen eine Egress (das Netz verlassend) und eine Ingress Queueing Discipline definiert sein (für hereinkommende Daten, siehe Kasten "Ingress Shaping"). Das Listing begnügt sich mit einer Egress-QDisc.
|
Ingress Shaping war lange Zeit mit Linux nicht möglich. Inzwischen gibt es mit dem Linux Intermediate Queueing Device (IMQ,[4]) eine Möglichkeit, HTB, SFQ und andere QDiscs im Ingress Queueing mit Egress-QDiscs einzusetzen. Derzeit benötigt IMQ eigene Patches für den Linux-Kernel und für das IPtables-Kommando.
Für die Bandbreitenkontrolle des eingehenden Verkehrs sind die virtuellen Netzwerkkarten »imq0« und »imq1« zuständig, an die der Administrator Egress-QDiscs bindet. Mit IPtables kann er in den »PREROUTING«- und »POSTROUTING«-Mangle-Ketten definieren, welche Pakete davon betroffen sein sollen. So ist es möglich, den Verkehr, der auf einem System ankommt, zu shapen.
Ein Gateway kann den Datenstrom auch ohne IMQ in beiden Richtungen shapen. Auf der externen Karte regelt es den Verkehr mit Ziel Internet, auf der internen Karte den Verkehr, der für das lokale LAN gedacht ist.
|