Skripte/Traffic-Shaping

Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:

Dieser Artikel ist größtenteils für alle Ubuntu-Versionen gültig.

Artikel für fortgeschrittene Anwender

Dieser Artikel erfordert mehr Erfahrung im Umgang mit Linux und ist daher nur für fortgeschrittene Benutzer gedacht.

Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:

  1. ⚓︎ Einen Editor öffnen

Inhaltsverzeichnis
  1. Installation
  2. Beispiel: DSL
    1. Initialisierung
    2. Bandbreiten
    3. Zuweisung
    4. Management
  3. Dauerhafte Aktivierung
  4. Fertige Skripte
    1. DSL mit 192kbit Upstream
    2. DSL mit 640kbit Upstream
    3. Gigabit LAN und 50MBit Uplink ins Intern...
  5. Links

Traffic-Shaping hat die Fähigkeit, verschiedene Netzwerk-Verbindungen unterschiedlich zu behandeln und somit Datenpaketen im Netzwerk unterschiedliche Prioritäten einzuräumen. Der Nutzen besteht zum Beispiel darin, dass eine bestehende Netzwerkverbindung, welche die verfügbare Bandbreite des Netzwerks vollständig ausschöpft, eine weitere Netzwerkverbindung nicht zur Gänze ausbremsen kann. Es lässt eine spezifische Bandbreitenverteilung der unterschiedlichen Netzwerk-Protokolle zu. Falls man es in einem Router einsetzt, kann man damit auch die Netzwerk-Nutzung der angeschlossenen Rechner reglementieren. Insgesamt sorgt es für eine optimierte Abarbeitung der Datenpakete und stellt eine effiziente Ausnutzung der verfügbaren Bandbreite sicher.

Hinweis:

Wer ein etwas einfacher zu verstehendes Programm bevorzugt, kann sich Trickle anschauen.

Installation

Die nötigen Programme und Pakete sind bei jeder Ubuntu-Installation bereits installiert. Man muss sie nur noch mittels eines Scripts, das man selbst anlegt [1], konfigurieren und aktivieren. Dazu bedient man sich folgender Programme:

Beispiel: DSL

Ein einfaches, aber sehr nützliches Einsatzszenario für Traffic-Shaping ist die Beeinflussung des Netzwerktraffics des DSL-Anschlusses. Da bei DSL der Upstream geringer als der Downstream ist, kann der Upstream schnell "verstopfen". Dies geschieht, weil bei TCP-Verbindungen jedes empfangene Paket mit einer "Empfangsbestätigung" beantwortet werden muss. Die Lage verschlimmert sich noch, wenn andere Netzwerkverbindungen den Upstream gleichfalls benutzen wollen. Genaueres dazu findet man bei TCP/IP. Um den Traffic zu beeinflussen, werden sogenannte "Regeln" angelegt, welche vom Kernel abgearbeitet werden.

Initialisierung

Der DSL-Anschluss mittels Modem läuft in der Regel über das Netzwerkgerät ppp0. Ist man über einen Router mit dem Internet verbunden, so ist heißt das zuständige Netzwerkgerät oft eth0. Das zuständige Netzwerkgerät wird mit dem Variablennamen DEV in der ersten Zeile übergeben.

DEV=ppp0
IPT=/sbin/iptables
TC=/sbin/tc
$IPT -t mangle -F
$TC qdisc del dev $DEV ingress > /dev/null 2>&1
$TC qdisc del dev $DEV root > /dev/null 2>&1
$TC qdisc del dev lo root > /dev/null 2>&1

Die letzten vier Zeilen säubern das System von eventuell zuvor angelegten Regeln.

Bandbreiten

Tatsächlich interessiert nur der verfügbare Upstream des DSL-Anschlusses. Die Datenpakete im Downstream kommen sowieso so schnell herein, wie sie eben ankommen. In diesem Beispiel gehen wir von einem Anschluss mit einem Upstream von 192kbit aus.

$TC qdisc add dev $DEV root handle 1:0 htb default 12 r2q 6
$TC class add dev $DEV parent 1:0 classid 1:1 htb rate 190kbit ceil 190kbit

In Zeile eins wird das Traffic-Shaping aktiviert. Mit dem Eintrag default 12 wird der Kanal 12 als derjenige festgelegt, der benutzt wird, wenn keine Regel zutrifft. In Zeile zwei wird die maximal verfügbare Bandbreite des Upstreams festgelegt. Hier wählt man sinnvollerweise einen Wert, der geringfügig unter dem tatsächlich höchstmöglichen Wert liegt, damit auf der Empfängerseite (beim Provider) kein Stau entsteht.

Nun werden die eigentlichen Regeln festgelegt, die den Kanälen verschiedene Bandbreiten und Prioritäten zuweisen:

$TC class add dev $DEV parent 1:1 classid 1:10 htb rate  30kbit ceil 190kbit prio 0
$TC class add dev $DEV parent 1:1 classid 1:11 htb rate  60kbit ceil 190kbit prio 1
$TC class add dev $DEV parent 1:1 classid 1:12 htb rate 100kbit ceil 190kbit prio 2

In Zeile eins wird der Kanal 10 definiert (classid 1:10). Er bekommt immer mindestens 30kbit Bandbreite (rate 30kbit) und darf maximal 190kbit nutzen (ceil 190kbit). Zeile zwei und drei legen die Werte für Kanal 11 und 12 analog fest. Die Summe aller rate-Werte darf die höchstmögliche Bandbreite nicht überschreiten.

Zuweisung

Nun muss man den verschiedenen Datenpaketen ihre Kanäle zuweisen. Dazu werden sie markiert:

$IPT -A POSTROUTING -t mangle -o $DEV -p tcp -m length --length :64 -j MARK --set-mark 10
$IPT -A POSTROUTING -t mangle -o $DEV -p udp --dport 53 -j MARK --set-mark 10

In Zeile eins werden alle Pakete mit einer Länge bis zu 64 Byte mit dem Kanal 10 verknüpft. Dies ist ein einfacher Trick, um alle Pakete zu erfassen, die für einen schnellen Verbindungsaufbau nötig sind. Zeile zwei markiert alle Pakete, die für den DNS nötig sind.

Um auch bei großen Downloads per FTP noch schnell surfen zu können, werden nun die Pakete von HTTP-Verbindungen mit dem Kanal 11 verknüpft:

$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --dport 80 -j MARK --set-mark 11

Die Regeln werden nacheinander durchlaufen. Das bedeutet, dass ein Paket auch mehrmals ummarkiert werden kann, falls mehrere Bedingungen zutreffen. Nicht markierte Pakete landen automatisch im default-Kanal.

Management

Nun muss dem Kernel noch mitgeteilt werden, wie er die verschiedenen Kanäle zu behandeln hat:

$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 11 fw flowid 1:11
$TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $DEV parent 1:11 handle 11: sfq perturb 10
$TC qdisc add dev $DEV parent 1:12 handle 12: sfq perturb 10

Wer wissen will, was hiermit festgelegt wird, der sehe in der Manpage zu tc nach.

Dauerhafte Aktivierung

Um das Script automatisch bei jedem Systemstart auszuführen, legt man es zum Beispiel unter dem Namen shaper im Verzeichnis /usr/local/sbin/ ab, und lässt es vom Init-System systemd als selbst erstellte Unit starten.

Fertige Skripte

DSL mit 192kbit Upstream

Verbindungen für TCP-Antwortpakete, DNS, SSH (ein- und ausgehend) und HTTP werden bevorzugt.

#!/bin/sh
DEV=ppp0
IPT=/sbin/iptables
TC=/sbin/tc
$IPT -t mangle -F
$TC qdisc del dev $DEV ingress > /dev/null 2>&1
$TC qdisc del dev $DEV root > /dev/null 2>&1
$TC qdisc del dev lo root > /dev/null 2>&1
$TC qdisc add dev $DEV root handle 1:0 htb default 12 r2q 6
$TC class add dev $DEV parent 1:0 classid 1:1 htb rate 190kbit ceil 190kbit
$TC class add dev $DEV parent 1:1 classid 1:10 htb rate  20kbit ceil 190kbit prio 0
$TC class add dev $DEV parent 1:1 classid 1:11 htb rate  20kbit ceil 190kbit prio 1
$TC class add dev $DEV parent 1:1 classid 1:12 htb rate 150kbit ceil 190kbit prio 2
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp -m length --length :64 -j MARK --set-mark 10
$IPT -A POSTROUTING -t mangle -o $DEV -p udp --dport 53 -j MARK --set-mark 10
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --dport 22 -j MARK --set-mark 11
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --sport 22 -j MARK --set-mark 11
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --dport 80 -j MARK --set-mark 11
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 11 fw flowid 1:11
$TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $DEV parent 1:11 handle 11: sfq perturb 10
$TC qdisc add dev $DEV parent 1:12 handle 12: sfq perturb 10

DSL mit 640kbit Upstream

Verbindungen für TCP-Antwortpakete, DNS und SSH (ein- und ausgehend) werden bevorzugt. Zudem werden Pakete zu den Ports 6881 bis 6889 (zum Beispiel für Bittorrent) auf einen maximalen Durchsatz von 250kbit beschränkt.

#!/bin/sh
DEV=ppp0
IPT=/sbin/iptables
TC=/sbin/tc
$IPT -t mangle -F
$TC qdisc del dev $DEV ingress > /dev/null 2>&1
$TC qdisc del dev $DEV root > /dev/null 2>&1
$TC qdisc del dev lo root > /dev/null 2>&1
$TC qdisc add dev $DEV root handle 1:0 htb default 12 r2q 6
$TC class add dev $DEV parent 1:0 classid 1:1  htb rate 635kbit ceil 635kbit
$TC class add dev $DEV parent 1:1 classid 1:10 htb rate  40kbit ceil 635kbit prio 0
$TC class add dev $DEV parent 1:1 classid 1:11 htb rate  60kbit ceil 635kbit prio 1
$TC class add dev $DEV parent 1:1 classid 1:12 htb rate 500kbit ceil 635kbit prio 2
$TC class add dev $DEV parent 1:1 classid 1:13 htb rate  35kbit ceil 250kbit prio 3
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp -m length --length :64 -j MARK --set-mark 10
$IPT -A POSTROUTING -t mangle -o $DEV -p udp --dport 53 -j MARK --set-mark 10
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --dport 22 -j MARK --set-mark 11
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --sport 22 -j MARK --set-mark 11
$IPT -A POSTROUTING -t mangle -o $DEV -p tcp --dport 6881:6889 -j MARK --set-mark 13
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 11 fw flowid 1:11
$TC filter add dev $DEV parent 1:0 prio 0 protocol ip handle 13 fw flowid 1:13
$TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $DEV parent 1:11 handle 11: sfq perturb 10
$TC qdisc add dev $DEV parent 1:12 handle 12: sfq perturb 10
$TC qdisc add dev $DEV parent 1:13 handle 13: sfq perturb 10

Bei dieser Variante wird der HFSC-Scheduler und nftables verwendet (Vorsicht: entweder iptables oder nftables, beides zusammen geht nicht!).

#!/bin/sh
DEV=eth0
TC=/sbin/tc

$TC qdisc del dev lo root 2> /dev/null
$TC qdisc del dev $DEV root 2> /dev/null
$TC qdisc del dev $DEV ingress 2> /dev/null

$TC qdisc add dev $DEV root handle 1: hfsc default 10
$TC class add dev $DEV parent 1: classid 1:1 hfsc ls rate 975mbit ul rate 975mbit

$TC class add dev $DEV parent 1:1 classid 1:10 hfsc ls rate 850mbit ul rate 975mbit # lan default 
$TC class add dev $DEV parent 1:1 classid 1:11 hfsc ls rate  75mbit ul rate 975mbit # lan prio
$TC class add dev $DEV parent 1:1 classid 1:20 hfsc ls rate  40mbit ul rate  50mbit # wan default
$TC class add dev $DEV parent 1:1 classid 1:21 hfsc ls rate  10mbit ul rate  50mbit # wan prio

$TC filter add dev $DEV parent 1:1 prio 1 protocol ip handle 10 fw flowid 1:10
$TC filter add dev $DEV parent 1:1 prio 2 protocol ip handle 11 fw flowid 1:11
$TC filter add dev $DEV parent 1:1 prio 3 protocol ip handle 20 fw flowid 1:20
$TC filter add dev $DEV parent 1:1 prio 4 protocol ip handle 21 fw flowid 1:21

$TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $DEV parent 1:11 handle 11: sfq perturb 10
$TC qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
$TC qdisc add dev $DEV parent 1:21 handle 21: sfq perturb 10

Die nftables rules dazu:

#!/usr/sbin/nft -f

define lan4 = 192.168.1.0/24
define lan6 = { fd00::/8, fe80::/10 }

table inet tcnat {

  chain postrouting {
    type route hook output priority -150; policy accept;
    ip daddr != $lan4 jump wan                               # leite nicht-LAN-traffic ipv4 um
    ip6 daddr != $lan6 jump wan                              # leite nicht-LAN-traffic ipv6 um
    ip daddr $lan4 tcp dport 22 meta priority set 1:11       # priorisiere SSH im LAN
    ip daddr $lan4 meta length 1-64 meta priority set 1:11   # priorisiere kleine Pakete im LAN
  }

  chain wan {
    tcp dport 22 meta priority set 1:21 return       # priorisiere SSH ins Internet
    meta length 1-64 meta priority set 1:21 return   # priorisiere kleine Pakete ins Internet
    meta priority set 1:20 counter                   # default ins Internet
  }

}