#server-performance

Linux Traffic Control (tc): een praktische gids

12 min lezen - 5 juni 2026

hero section cover

Beheer bandbreedte, geef prioriteit aan verkeer en beheer inkomend en uitgaand verkeer op Linux met tc. Werkende HTB-, IFB-, DSCP- en fq_codel-configuraties voor echte servers.

Linux Traffic Control (tc): een praktische gids

Met het tc commando geeft je directe controle over hoe je server het netwerkverkeer afhandelt. U kunt de bandbreedte per dienst beperken, interactieve sessies zoals SSH responsief houden wanneer er pieken in bulkoverdracht optreden, en zowel uitgaande als inkomende datastromen regelen vanuit één enkele tool. Deze gids behandelt de kernconcepten, een werkende HTB-configuratie, ingangsherstructurering met IFB, op DSCP gebaseerde prioritering, en hoe u fouten kunt opsporen wanneer er iets misgaat.


 

Hoe tc werkt

Elke tc configuratie bestaat uit vier onderdelen:

  • qdisc (queuing discipline). De scheduler die aan een netwerkinterface is gekoppeld. Deze bepaalt hoe pakketten in de wachtrij worden geplaatst en eruit worden gehaald.
  • Class. Een onderverdeling binnen een classful qdisc. Zie het als een rijstrook met een eigen snelheidslimiet.
  • Filter. Controleert pakketheaders (IP-adressen, poorten, markeringen) en wijst elk pakket aan een klasse toe.
  • Actie. Wat er met een pakket gebeurt zodra het aan de criteria voldoet: doorsturen, verwijderen, omleiden.

Deze vormen een boomstructuur. Pakketten komen binnen bij de root-qdisc, passeren filters, worden door een major:minor handle en komen uiteindelijk in de wachtrij van een leaf-qdisc terecht voor verzending.

Voor alles wat complexer is dan op poorten gebaseerde matching, markeer je pakketten met iptables of nftables in de mangle-tabel, en gebruik je vervolgens het fw filter in tc om op markering te classificeren. Dit schaalt veel beter dan het koppelen van ruwe u32 regels aan elkaar te koppelen voor elk type verkeer.

Uitgaand versus inkomend

De richting is van belang. De kernel kan uitgaande pakketten in de buffer opslaan en vertragen, wat echte shaping mogelijk maakt. Inkomende pakketten zijn al via de verbinding binnengekomen tegen de tijd dat je ze ziet, dus je kunt ze alleen controleren (weggooien boven een drempelwaarde) tenzij je ze eerst omleidt naar een IFB-apparaat.

FunctieUitgaandIngang
RichtingUitgaandInkomend
ShapingNativeVereist IFB
PolicingOndersteundOndersteund
Typisch gebruikQoS, bandbreedteverdeling, pacingSnelheidsbeperking, basisbescherming tegen DDoS-aanvallen

De qdiscs die u daadwerkelijk zult gebruiken

  • HTB (Hierarchical Token Bucket). Met klassen. Gebruik deze als je gegarandeerde minimale bandbreedte per service wilt, met de mogelijkheid om ongebruikte capaciteit van andere klassen te lenen.
  • TBF (Token Bucket Filter). Klassevrij. Gebruik dit wanneer je gewoon een hele interface op één snelheid wilt begrenzen.
  • fq_codel (Fair Queuing Controlled Delay). Combineert eerlijkheid per datastroom met actief wachtrijbeheer om bufferbloat te voorkomen. Dit is sinds systemd 217 de standaard qdisc in de meeste Linux-distributies en wordt standaard meegeleverd met RHEL 9. Koppel deze altijd als een leaf-qdisc onder HTB-klassen, anders kan één enkele gulzige datastroom een hele klasse in beslag nemen.

tc instellen op een Linux-server

tc wordt meegeleverd met het iproute2-pakket. Op Debian en Ubuntu installeer je het met apt-get install iproute2. Op RHEL en afgeleide distributies yum install iproute. Je hebt root-rechten of sudo nodig.

Zorg eerst dat je de juiste interfacenaam hebt. Een verkeerde naam voor de interface is de meest voorkomende reden waarom een configuratie stilletjes niets doet:

ip link show

Controleer wat er al op de interface staat, inclusief de actuele tellers:

tc -s qdisc show dev eth0

Verwijder eventuele bestaande root-qdiscs voordat je een nieuwe configuratie toepast, om RTNETLINK answers: File exists fouten te voorkomen:

tc qdisc del dev eth0 root 2>/dev/null || true

Als je een bestaande regel bijwerkt in plaats van helemaal opnieuw te beginnen, gebruik dan replace in plaats van add voor een atomaire omwisseling.

Hardware-offloading zoals TSO en GSO bundelt pakketten op een manier die shaping verstoort. Schakel deze functies uit op de interface waarop shaping wordt toegepast:

sudo ethtool -K eth0 tso off gso off

Stel fq_codel in als de systeembrede standaard-qdisc voor nieuwe interfaces:

sysctl -w net.core.default_qdisc=fq_codel

Combineer dit bij drukke servers met het BBR-congestiebeheersingsalgoritme (kernel 4.9+). BBR houdt de doorvoer hoog zonder dat de wachtrijen groeien:

sysctl -w net.ipv4.tcp_congestion_control=bbr

Een veilige gewoonte als je een externe machine via SSH configureert: open een tweede sessie en zorg dat tc qdisc del dev eth0 root klaar om te plakken. Een verkeerde filterregel kan je onmiddellijk buitensluiten.

Uitgaand verkeer vormgeven met HTB

Met HTB kunt u elke dienst een gegarandeerd minimum (rate) en een maximum (ceil). Ongebruikte bandbreedte gaat naar degene die deze nodig heeft, in volgorde van prioriteit. Hier volgt een werkende opzet met drie niveaus voor een uplink van 1 Gbps.

Maak de root-HTB-qdisc aan. De default 30 stuurt elk niet-geclassificeerd pakket naar klasse 1:30 in plaats van het je regels te laten omzeilen:

tc qdisc add dev eth0 root handle 1: htb default 30

Beperk de totale doorvoer tot 900 Mbps. Stel de shaping altijd iets lager in dan de werkelijke linkcapaciteit, anders ontstaat er een wachtrij op een upstream-router of -modem waarover je geen controle hebt:

tc class add dev eth0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit

Definieer de serviceniveaus. Lagere prio waarden krijgen als eerste ongebruikte bandbreedte:

# High priority: web and API traffic
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1
 
# Medium priority: database replication
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 300mbit ceil 900mbit prio 2
 
# Low priority: bulk and backup traffic
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 100mbit ceil 900mbit prio 3

Voeg fq_codel als leaf-qdisc aan elke klasse, zodat één enkele stroom zijn niveau niet kan domineren:

tc qdisc add dev eth0 parent 1:10 handle 10: fq_codel
tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel
tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel

Classificeer nu het verkeer. Voor eenvoudige poortmatching u32 is dit het snelst:

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip dport 443 0xffff flowid 1:10

Voor alles wat stateful is, markeer je in iptables en koppel je de markering aan fw:

iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 2
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20

Inkomend verkeer vormgeven met IFB

Je kunt inkomend verkeer niet standaard vormgeven, omdat het pakket op het moment dat het aankomt al je bandbreedte heeft gebruikt. De oplossing is om inkomend verkeer om te leiden naar een virtuele interface van het Intermediate Functional Block (IFB), waar de kernel het behandelt als uitgaand verkeer en je classful qdiscs kunt toepassen.

Laad de module en schakel de interface in:

modprobe ifb numifbs=1
ip link set dev ifb0 up

Voeg een ingangs-qdisc toe aan de fysieke interface en leid alles om naar ifb0:

tc qdisc add dev eth0 ingress handle ffff:
tc filter add dev eth0 parent ffff: protocol all u32 \
  match u32 0 0 action mirred egress redirect dev ifb0

Vanaf hier ifb0 gedraagt de interface zich net als elke andere interface. Pas je HTB-boom erop toe, precies zoals je dat bij uitgaand verkeer zou doen:

tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:1 htb rate 900mbit ceil 900mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 500mbit ceil 900mbit prio 1

Verkeer prioriteren met DSCP

DSCP (Differentiated Services Code Point) markeert pakketten met een waarde van 6 bits in de TOS-byte, zodat uw tc filters op tag kunnen classificeren in plaats van poorten door de regelset te moeten doorzoeken. Bij het matchen van DSCP in tc, verschuif je de waarde 2 bits naar links. DSCP EF (46) wordt 0xb8. Het masker 0xfc scheidt de 6 DSCP-bits van de 2 ECN-bits.

Een verstandige standaardtoewijzing voor serverworkloads:

VerkeerstypeDSCPTOS hexVoorbeelden
InteractiefEF0xb8SSH, DNS, VoIP
ZakelijkAF410x88HTTP, HTTPS, API's
BulkCS10x20Back-ups, FTP, pakketupdates
Best effortCS00x00Al het overige

Markeer uitgaande pakketten in iptables voordat ze je tc filters:

iptables -t mangle -A OUTPUT -p tcp --dport 22 -j DSCP --set-dscp 46

Koppel vervolgens de tag in tc en routeer het naar de juiste HTB-klasse:

# EF (SSH, VoIP) goes to the high-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
  match ip tos 0xb8 0xfc flowid 1:10
 
# AF41 (web traffic) goes to the medium class
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 \
  match ip tos 0x88 0xfc flowid 1:20
 
# CS1 (bulk) goes to the low-priority class
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 \
  match ip tos 0x20 0xfc flowid 1:30

Monitoring en probleemoplossing

De drie commando’s die je voortdurend zult gebruiken:

tc -s qdisc show dev eth0
tc -s class show dev eth0
tc -s filter show dev eth0

Houd de dropped en overlimits tellers in de gaten. Verloren pakketten betekenen dat de wachtrij verzadigd is; overschrijdingen van limieten betekenen dat je het plafond van een klasse hebt bereikt en dat de kernel het verkeer moest vertragen of afwerpen. Voor een live overzicht:

watch -n 1 'tc -s class show dev eth0'

Voeg -d voor interne parameters (target, interval, quantum) en -j voor JSON-uitvoer als je de gegevens doorstuurt naar een metrics-stack. Combineer dit met ss -tin om RTT-schattingen en hertransmissies op de TCP-laag te bekijken.

De meeste storingen vallen onder een beperkt aantal oorzaken:

SymptoomWaarschijnlijke oorzaakOplossing
RTNETLINK answers: File existsRoot-qdisc is al geconfigureerdtc qdisc del dev eth0 root eerst
Regels zijn van toepassing, maar het verkeer wordt niet beperktVerkeerde interface, of TSO/GSO is nog steeds ingeschakeldControleer met ip link show, schakel offloads uit met ethtool -K
Filter komt nooit overeenOnjuiste poort-/IP-syntaxis of maskerafstemmingVoeg een tegenmaatregel toe en controleer het aantal treffers in tc -s filter show
Regels verdwenen na herstartDe configuratie staat alleen in het geheugenVerpak het in een script en roep het aan vanuit systemd of een NetworkManager-dispatcher
Hoge latentie bij prioritair verkeerGeen leaf-qdisc, of burst te laagKoppel fq_codel aan leaf-klassen, verhoog burst

Als je jezelf ooit buitensluit door een verkeerde configuratie, is het resetten eenvoudig:

tc qdisc del dev eth0 root

tc je kunt geen bandbreedte creëren die je niet hebt, maar op een goed uitgeruste uplink maakt het het verschil tussen voorspelbare prestaties en een server die instort zodra één tenant een grote overdracht start. Als je de ruwe bandbreedte nodig hebt en de vrijheid om deze naar eigen inzicht te vormgeven, kijk dan eens naar de dedicated servers van FDC.

Blog

Uitgelicht deze week

Meer artikelen
iperf3-handleiding: Netwerksnelheid testen op Linux en Windows
#bandwidth#server-performance

iperf3-handleiding: Netwerksnelheid testen op Linux en Windows

Installeer iperf3, voer bandbreedtetests uit en stem de TCP-buffers af voor nauwkeurige resultaten op Linux en Windows. Behandelt UDP-, bidirectionele en 10GbE+-tests

10 min lezen - 7 mei 2026

Meer artikelen
background image

Hebt u vragen of wilt u een oplossing op maat?

icon

Flexibele opties

icon

Wereldwijd bereik

icon

Directe inzet

icon

Flexibele opties

icon

Wereldwijd bereik

icon

Directe inzet