HOWTO du routage avancé et du contrôle de trafic sous Linux:
Gestionnaires de mise en file d'attente pour l'administration de la
bande passantePage suivantePage précédenteTable des matières
Quand je l'ai découvert, cela m'a vraiment soufflé.
Linux 2.2 contient toutes les fonctionnalités pour la gestion de la
bande passante, de manière comparable à un système dédié de haut
niveau.
Linux dépasse même ce que l'ATM et le Frame peuvent fournir.
Afin d'éviter toute confusion, voici les règles utilisées par tc
pour la spécification de la bande passante :
Avec la mise en file d'attente, nous déterminons la manière dont
les données sont envoyées. Il est important de comprendre
que nous ne pouvons mettre en forme que les données que nous
transmettons.
Avec la manière dont Internet travaille, nous n'avons pas de
contrôle direct de ce que les personnes nous envoient. C'est un peu
comme votre boîte aux lettres (physique !) chez vous. Il n'y a
pas de façon d'influencer le nombre de lettres que vous recevez, à
moins de contacter tout le monde.
Cependant, l'Internet est principalement basé sur TCP/IP qui
possède quelques fonctionnalités qui vont pouvoir nous aider.
TCP/IP n'a pas d'aptitude à connaître les performances d'un réseau
entre deux hôtes. Il envoie donc simplement des paquets de plus en
plus rapidement ('slow start') et quand des paquets commencent à se
perdre, il ralentit car il n'a plus la possibilité de les envoyer.
En fait, c'est un peu plus élégant que cela, mais nous en dirons
plus par la suite.
C'est comme si vous ne lisiez que la moitié de votre courrier en
espérant que vos correspondants arrêteront de vous en envoyer. À la
différence que ça marche sur Internet :-)
Si vous avez un routeur et que vous souhaitez éviter que
certains hôtes de votre réseau aient des vitesses de téléchargement
trop grandes, vous aurez besoin de mettre en place de la mise en
forme de trafic sur l'interface *interne* de votre routeur, celle
qui envoie les données vers vos propres ordinateurs.
Vous devez également être sûr que vous contrôlez le goulot
d'étranglement de la liaison. Si vous avez une carte réseau à
100Mbit et un routeur avec un lien à 256kbit, vous devez vous
assurer que vous n'envoyiez pas plus de données que ce que le
routeur peut manipuler. Autrement, ce sera le routeur qui
contrôlera le lien et qui mettra en forme la bande passante
disponible. Nous devons pour ainsi dire 'être le propriétaire de la
file d'attente' et être le lien le plus lent de la chaîne.
Heureusement, ceci est facilement réalisable.
Comme nous l'avons déjà dit, la gestion de mise en file
d'attente permet de modifier la façon dont les données sont
envoyées. Les gestionnaires de mise en file d'attente sans classes
sont ceux qui, en gros, acceptent les données et qui ne font que
les réordonnancer, les retarder ou les jeter.
Ils peuvent être utilisés pour mettre en forme le trafic d'une
interface, sans aucune subdivision. Il est primordial que vous
compreniez cet aspect de la mise en file d'attente avant de
continuer sur les gestionnaires de mise en files d'attente basés
sur des classes contenant d'autres gestionnaires de mise en file
d'attente.
Le gestionnaire le plus largement utilisé est de loin
pfifo_fast, qui est celui par défaut. Ceci explique aussi pourquoi
ces fonctionnalités avancées sont si robustes. Elles ne sont rien
de plus 'qu'une autre file d'attente'.
Chacune de ces files d'attente a ses forces et ses faiblesses.
Toutes n'ont peut-être pas été bien testées.
pfifo_fast
Cette file d'attente, comme son nom l'indique, First In First
Out (fifo = premier entré, premier sorti), signifie que les paquets
ne subissent pas de traitements spéciaux. En fait, ce n'est pas
tout à fait vrai. Cette file d'attente a trois 'bandes'. A
l'intérieur de chacune de ces bandes, des règles FIFO s'appliquent.
Cependant, tant qu'il y a un paquet en attente dans la bande 0, la
bande 1 ne sera pas traitée. Il en va de même pour la bande 1 et la
bande 2.
Le noyau prend en compte la valeur du champ Type de Service des
paquets et prend soin d'insérer dans la bande 0 les paquets ayant
le bit 'délai minimum' activé.
Ne pas confondre ce gestionnaire de mise en file d'attente sans
classes avec celui basé sur des classes PRIO ! Bien qu'ils
aient des comportements similaires, pfifo_fast ne possèdent pas de
classes et vous ne pourrez pas y ajouter de nouveaux gestionnaires
avec la commande tc.
Paramètres & usage
Vous ne pouvez pas configurer le gestionnaire pfifo_fast, dans
la mesure où c'est celui par défaut. Voici sa configuration par
défaut :
priomap
Détermine comment les priorités des paquets, comme définies par
le noyau, sont reliées aux bandes. La relation est établie en se
basant sur l'octet TOS du paquet, qui ressemble à ceci :
Les quatre bits TOS (le champ TOS) sont définis comme
suit :
Binaire Décimal Signification
-----------------------------------------
1000 8 Minimise le Délai (Minimize delay) (md)
0100 4 Maximalise le Débit (Maximize throughput) (mt)
0010 2 Maximalise la Fiabilité (Maximize reliability) (mr)
0001 1 Minimalise le Coût Monétaire (Minimize monetary cost) (mmc)
0000 0 Service Normal
Comme il y a 1 bit sur la droite de ces quatre bits, la valeur
réelle du champ TOS est le double de la valeur des bits TOS.
Tcpdump -v -v fournit la valeur de tout le champ TOS, et non pas
seulement la valeur des quatre bits. C'est la valeur que l'on peut
voir dans la première colonne du tableau suivant :
[NdT : par flux de masse (bulk flow), il faut entendre gros
flot de données, transmis en continu, comme un transfert FTP, par
opposition à un flux interactif (interactive flow), comme celui
généré par des requêtes SSH].
Beaucoup de nombres. La seconde colonne contient la valeur
correspondante des quatre bits TOS, suivi de leur signification.
Par exemple, 15 représente un paquet voulant un coût monétaire
minimal, une fiabilité maximum, un débit maximum ET un délai
Minimum. J'appellerai ceci un 'paquet Hollandais'.
La quatrième colonne liste la manière dont le noyau Linux
interprète les bits TOS, en indiquant à quelle priorité ils sont
reliés.
La dernière colonne montre la carte des priorités par défaut.
Sur la ligne de commande, la carte des priorités ressemble à
ceci :
1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1,
1
Ceci signifie , par exemple, que la priorité 4 sera reliée à la
bande numéro 1. La carte des priorités vous permet également de
lister des priorités plus grandes (> 7) qui ne correspondent pas
à une relation avec le champ TOS, mais qui sont configurées par
d'autres moyens.
Le tableau suivant provenant de la RFC 1349 (le lire pour plus
de détails) indique comment les applications devraient correctement
configurées leurs bits TOS :
TELNET 1000 (minimise le délai)
FTP
Contrôle 1000 (minimise le délai)
Données 0100 (maximalise le débit)
TFTP 1000 (minimise le délai)
SMTP
phase de commande 1000 (minimise le délai)
phase DATA 0100 (maximalise le débit)
Domain Name Service
requête UDP 1000 (minimise le délai)
requête TCP 0000
Transfert de Zone 0100 (maximalise le débit)
NNTP 0001 (minimise le coût monétaire)
ICMP
Erreurs 0000
Requêtes 0000 (presque)
Réponses <même chose que requête> (presque)
txqueuelen
La longueur de cette file d'attente est fournie par la
configuration de l'interface, que vous pouvez voir et configurer
avec ifconfig et ip. Pour configurer la longueur de la file
d'attente à 10, exécuter : ifconfig eth0 txqueuelen 10
Vous ne pouvez pas configurer ce paramètre avec tc !
Token Bucket Filter (Filtre à seau de jetons)
Le Token Bucket Filter (TBF) est un gestionnaire de mise en file
d'attente simple. Il ne fait que laisser passer les paquets
entrants avec un débit n'excédant pas une limite fixée
administrativement. L'envoi de courtes rafales de données avec un
débit dépassant cette limite est cependant possible.
TBF est très précis, et peu gourmand du point de vue réseau et
processeur. Considérez le en premier si vous voulez simplement
ralentir une interface !
L'implémentation TBF consiste en un tampon (seau), constamment
rempli par des éléments virtuels d'information appelés jetons, avec
un débit spécifique (débit de jeton). Le paramètre le plus
important du tampon est sa taille, qui est le nombre de jetons
qu'il peut stocker.
Chaque jeton entrant laisse sortir un paquet de données de la
file d'attente de données et ce jeton est alors supprimé du seau.
L'association de cet algorithme avec les deux flux de jetons et de
données, nous conduit à trois scénarios possibles :
Les données arrivent dans TBF avec un débit égal au
débit des jetons entrants. Dans ce cas, chaque paquet entrant a son
jeton correspondant et passe la file d'attente sans délai.
Les données arrivent dans TBF avec un débit plus petit
que le débit des jetons. Seule une partie des jetons est supprimée
au moment où les paquets de données sortent de la file d'attente,
de sorte que les jetons s'accumulent jusqu'à atteindre la taille du
tampon. Les jetons non utilisés peuvent être utilisés pour envoyer
des données avec un débit supérieur au débit des jetons standard,
si de courtes rafales de données arrivent.
Les données arrivent dans TBF avec un débit plus grand
que le débit des jetons. Ceci signifie que le seau sera bientôt
dépourvu de jetons, ce qui provoque l'arrêt de TBF pendant un
moment. Ceci s'appelle "une situation de dépassement de limite"
(overlimit situation). Si les paquets continuent à arriver, ils
commenceront à être éliminés.
Le dernier scénario est très important, car il autorise la mise
en forme administrative de la bande passante disponible pour les
données traversant le filtre.
L'accumulation de jetons autorise l'émission de courtes rafales
de données sans perte en situation de dépassement de limite, mais
toute surcharge prolongée causera systématiquement le retard des
paquets, puis leur rejet.
Notez que, dans l'implémentation réelle, les jetons
correspondent à des octets, et non des paquets.
Paramètres & usage
Même si vous n'aurez probablement pas besoin de les changer, tbf
a des paramètres. D'abord, ceux toujours disponibles
sont :
limit or latency
Limit est le nombre d'octets qui peuvent être mis en file
d'attente en attendant la disponibilité de jetons. Vous pouvez
également indiquer ceci d'une autre manière en configurant le
paramètre "latency", qui spécifie le temps maximal pendant lequel
un paquet peut rester dans TBF. Ce dernier paramètre prend en
compte la taille du seau, le débit, et, s'il est configuré, le
débit de crête (peakrate).
burst/buffer/maxburst
Taille du seau, en octets. C'est la quantité maximale en octets
pour laquelle on disposera de jetons en même temps. En général,
plus les débits de mise en forme sont importants, plus le tampon
doit être grand. Pour 10 Mbit/s sur plateforme Intel, vous avez
besoin d'un tampon d'au moins 10 kilo-octets si vous voulez
atteindre la limitation configurée !
Si votre tampon est trop petit, les paquets pourront être
rejetés car il arrive plus de jetons par top d'horloge que ne peut
en contenir le tampon.
mpu
Un paquet de taille nulle n'utilise pas une bande passante
nulle. Pour ethernet, la taille minimale d'un paquet est de 64
octets. L'Unité Minimale de Paquet (Minimun Packet Unit) détermine
le nombre minimal de jetons à utiliser pour un paquet.
rate
Le paramètre de la vitesse. Voir les remarques au-dessus à
propos des limites !
Si le seau contient des jetons et qu'il est autorisé à se vider,
alors, il le fait par défaut avec une vitesse infinie. Si ceci vous
semble inacceptable, utilisez les paramètres suivants :
peakrate
Si des jetons sont disponibles, et que des paquets arrivent, ils
sont, par défaut, immédiatement envoyés, et pour ainsi dire à "la
vitesse de la lumière". Cela peut ne pas vous convenir,
spécialement si vous avez un grand seau.
Le débit de crête (peakrate) peut être utilisé pour spécifier la
vitesse à laquelle le seau est autorisé à se vider. Si tout se
passe comme écrit dans les livres, ceci est réalisé en libérant un
packet, puis en attendant suffisamment longtemps, et en libérant le
paquet suivant. Le temps d'attente est calculé de manière à obtenir
un débit égal au débit de crête.
Cependant, étant donné que la résolution du minuteur (timer)
d'UNIX est de 10 ms et que les paquets ont une taille moyenne de 10
000 bits, nous sommes limités à un débit de crête de
1mbit/s !
mtu/minburst
Le débit de crête de 1Mb/s ne sert pas à grand chose si votre
débit habituel y est supérieur. Un débit de crête plus élevé peut
être atteint en émettant davantage de paquets par top du minuteur,
ce qui a pour effet de créer un second seau.
Ce second bucket ne prend par défaut qu'un seul paquet, et n'est
donc en aucun cas un seau.
Pour calculer le débit de crête maximum, multipliez le mtu que
vous avez configuré par 100 (ou plus exactement par HZ, qui est
égal à 100 sur Intel et égal à 1024 sur Alpha).
Configuration simple
Voici une configuration simple, mais *très* utile :
Ok, pourquoi est-ce utile ? Si vous avez un périphérique
réseau avec une grande file d'attente, comme un modem DSL ou un
modem câble, et que le dialogue se fasse à travers une interface
rapide, comme une interface ethernet, vous trouverez que
télécharger vers l'amont (uploading) détruit complètement
l'interactivité.
[NdT : uploading désigne une opération qui consiste à
transférer des données ou des programmes stockés dans un ordinateur
local vers un ordinateur distant à travers un réseau. La traduction
officielle pour ce terme est "téléchargement vers l'amont". On
parle alors de la voie montante. Downloading désigne l'opération
inverse (transfert d'un hôte distant vers l'ordinateur local) et
est traduit par "téléchargement" ou "téléchargement vers l'aval".
On parle alors de la voie descendante.]
Le téléchargement vers l'amont va en effet remplir la file
d'attente du modem. Celle-ci est probablement *énorme* car cela
aide vraiment à obtenir de bon débit de téléchargement vers
l'amont. Cependant, ceci n'est pas forcément ce que voulez. Vous ne
voulez pas forcément avoir une file d'attente importante de manière
à garder l'interactivité et pouvoir encore faire des choses pendant
que vous envoyiez des données.
La ligne de commande au-dessus ralentit l'envoi de données à un
débit qui ne conduit pas à une mise en file d'attente dans le
modem. La file d'attente sera dans Linux, où nous pouvons lui
imposer une taille limite.
Modifier 220kbit avec votre vitesse de lien *réelle*, moins un
petit pourcentage. Si vous avez un modem vraiment rapide, augmenter
un peu le paramètre 'burst'.
Stochastic Fairness Queueing (Mise en file d'attente
stochastiquement équitable)
Stochastic Fairness Queueing (SFQ) est une implémentation simple
de la famille des algorithmes de mise en file d'attente équitable.
Cette implémentation est moins précise que les autres, mais elle
nécessite aussi moins de calculs tout en étant presque parfaitement
équitable.
Le mot clé dans SFQ est conversation (ou flux), qui correspond
principalement à une session TCP ou un flux UDP. Le trafic est
alors divisé en un grand nombre de jolies files d'attente FIFO, une
par conversation. Le trafic est alors envoyé dans un tourniquet,
donnant une chance à chaque session d'envoyer leurs données tour à
tour.
Ceci conduit à un comportement très équitable et empêche qu'une
seule conversation n'étouffe le reste. SFQ est appelé 'Stochastic'
car il n'alloue pas vraiment une file d'attente par session, mais a
un algorithme qui divise le trafic à travers un nombre limité de
files d'attente en utilisant un algorithme de hachage.
A cause de ce hachage, plusieurs sessions peuvent finir dans le
même seau, ce qui peut réduire de moitié les chances d'une session
d'envoyer un paquet, donc réduire de moitié la vitesse effective
disponible. Pour empêcher que cette situation ne devienne
importante, SFQ change très souvent son algorithme de hachage pour
que deux sessions entrantes en collision ne le fassent que pendant
un nombre réduit de secondes.
Il est important de noter que SFQ n'est seulement utile que dans
le cas où votre interface de sortie est vraiment saturée ! Si
ce n'est pas le cas, il n'y aura pas de files d'attente sur votre
machine Linux et donc, pas d'effets. Plus tard, nous décrirons
comment combiner SFQ avec d'autres gestionnaires de mise en files
d'attente pour obtenir le meilleur des deux mondes.
Spécialement, configurer SFQ sur l'interface ethernet qui est en
relation avec votre modem câble ou votre routeur DSL est vain sans
d'autres mises en forme du trafic !
Paramètres & usage
SFQ est presque configuré de base :
perturb
Reconfigure le hachage une fois toutes les pertub secondes. S'il
n'est pas indiqué, le hachage se sera jamais reconfiguré. Non
recommandé. 10 secondes est probablement une bonne valeur.
quantum
Nombre d'octets qu'un flux est autorisé à retirer de la file
d'attente avant que la prochaine file d'attente ne prenne son tour.
Par défaut, égal la taille maximum d'un paquet (MTU). Ne le
configurer pas en-dessous du MTU !
Configuration simple
Si vous avez un périphérique qui a une vitesse identique à celle
du lien et un débit réel disponible, comme un modem téléphonique,
cette configuration aidera à promouvoir l'équité :
# tc qdisc add dev ppp0 root sfq perturb 10
# tc -s -d qdisc ls
qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec
Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)
Le nombre 800c est un descripteur (handle) automatiquement
assigné et 'limit' signifie que 128 paquets peuvent attendre dans
la file d'attente. Il y a 1024 "seaux de hachage" disponibles pour
la comptabilité, 128 pouvant être actifs à la fois (pas plus de
paquets ne conviennent dans la file d'attente). Le hachage est
reconfiguré toutes les 10 secondes.
Pour résumé, ces files d'attente simples gèrent le trafic en
réordonnant, en ralentissant ou en supprimant les paquets.
Les astuces suivantes peuvent vous aider à choisir la file
d'attente à utiliser. Elles mentionnent certaines files d'attente
décrites dans le chapitre 'Gestionnaires de mise en file d'attente
avancés & et moins communs'.
Pour simplement ralentir le trafic sortant, utilisez le Token
Bucket Filter. Convient bien pour les énormes bandes passantes, si
vous paramètrez en conséquence le seau.
Si votre lien est vraiment saturé, et que vous voulez être sûr
qu'aucune session ne va accaparer la bande passante vers
l'extérieur, utilisez Stochastical Fairness Queueing.
Si vous avez une grande dorsale, et que vous vouliez savoir ce
que vous faîtes, considérer Random Early Drop (Voir le chapitre sur
les gestionnaires avancés).
Pour 'mettre en forme' le trafic entrant qui n'est pas
transmis, utilisez la réglementation Ingress (Ingress Policier). La
mise en forme du flux entrant est appelée 'réglementation'
(policing) et non 'mise en forme' (shaping).
Si vous transmettez le trafic, utilisez TBF sur l'interface
vers laquelle vous transmettez les données. Si vous voulez mettre
en forme le trafic pouvant sortir par plusieurs interfaces, alors
le seul facteur commun est l'interface entrante. Dans ce cas,
utilisez la réglementation Ingress.
Si vous ne voulez pas mettre en forme le trafic, mais que vous
vouliez voir si votre interface est tellement chargée qu'elle a dû
mettre en file d'attente les données, utilisez la file d'attente
pfifo (pas pfifo_fast). Elle n'a pas de bandes internes, mais
assure le comptage de la taille de son accumulateur.
Finalement, vous pouvez aussi faire de la "mise en forme
sociale". La technologie n'est pas toujours capable de réaliser ce
que vous voulez. Les utilisateurs sont hostiles aux contraintes
techniques. Un mot aimable peut également vous aider à avoir votre
bande passante correctement divisée !
Pour comprendre correctement des configurations plus
compliquées, il est d'abord nécessaire d'expliquer quelques
concepts. A cause de la complexité et de la relative jeunesse du
sujet, beaucoup de mots différents sont utilisés par les personnes
mais qui, en fait, signifient la même chose.
Ce qui suit s'est lâchement inspiré du texte
draft-ietf-diffserv-model-06.txt, 'An Informal Management Model for
Diffserv Routers'. Il peut être trouvé à
http://www.ietf.org/internet-drafts/draft-ietf-diffserv-model-04.txt.
Lisez-le pour les définitions strictes des termes utilisés.
Gestionnaire de mise en file d'attente (Queueing
Discipline)
Un algorithme qui gère la file d'attente d'un périphérique, soit
pour les données entrantes (ingress), soit pour les données
sortantes (egress).
Gestionnaire de mise en file d'attente sans classes
(Classless qdisc)
Un gestionnaire de mise en file d'attente qui n'a pas de
subdivisions internes configurables.
Gestionnaire de mise en file d'attente basé sur des classes
(Classful qdisc)
Un gestionnaire de mise en file d'attente basé sur des classes
contient de multiples classes. Chacune de ces classes contient un
gestionnaire de mise en file d'attente supplémentaire, qui peut
encore être basé sur des classes, mais ce n'est pas obligatoire. Si
l'on s'en tient à la définition stricte, pfifo_fast *est* basé sur
des classes, dans la mesure où il contient trois bandes, qui sont
en fait des classes. Cependant, d'un point de vue des perspectives
de configuration pour l'utilisateur, il est sans classes dans la
mesure où ces classes ne peuvent être modifiées avec l'outil
tc.
Classes
Un gestionnaire de mise en file d'attente peut avoir beaucoup de
classes, chacune d'elles étant internes au gestionnaire. Chacune de
ces classes peut contenir un gestionnaire de mise en file d'attente
réel.
Classificateur (Classifier)
Chaque gestionnaire de mise en file d'attente basé sur des
classes a besoin de déterminer vers quelles classes il doit envoyé
un paquet. Ceci est réalisé en utilisant le classificateur.
Filtre (Filter)
La classification peut être réalisée en utilisant des filtres.
Un filtre est composé d'un certain nombre de conditions qui, si
elles sont toutes vérifiées, satisfait le filtre.
Ordonnancement (Scheduling)
Un gestionnaire de mise en file d'attente peut, avec l'aide d'un
classificateur, décider que des paquets doivent sortir plus tôt que
d'autres. Ce processus est appelé ordonnancement (scheduling), et
est réalisé par exemple par le gestionnaire pfifo_fast mentionné
plus tôt. L'ordonnancement est aussi appelé 'réordonnage'
(reordering), ce qui peut prêter à confusion.
Mise en forme (Shaping)
Le processus qui consiste à retarder l'émission des paquets
sortants pour avoir un trafic conforme à un débit maximum
configuré. La mise en forme est réalisée sur egress. Familièrement,
rejeter des paquets pour ralentir le trafic est également souvent
appelé Mise en forme.
Réglementation (Policing)
Retarder ou jeter des paquets dans le but d'avoir un trafic
restant en dessous d'une bande passante configurée. Dans Linux, la
réglementation ne peut que jeter un paquet, et non le retarder dans
la mesure où il n'y a pas de 'file d'attente d'entrée ('ingress
queue')'.
Work-Conserving
Un gestionnaire de mise en file d'attente "work-conserving"
délivre toujours un paquet s'il y en a un de disponible. En
d'autres termes, il ne retarde jamais un paquet si l'adaptateur
réseau est prêt à l'envoyer (dans le cas du gestionnaire
egress).
non-Work-Conserving
Quelques files d'attente, comme par exemple le Token Bucket
Filter, peuvent avoir besoin de maintenir un paquet pendant un
certain temps pour limiter la bande passante. Ceci signifie qu'ils
refusent parfois de libérer un paquet, bien qu'il en aient un de
disponible.
Maintenant que nous avons défini notre terminologie, voyons où
tous ces élements sont.
Programmes Utilisateurs
^
|
+---------------+-------------------------------------------+
| Y |
| -------> Pile IP |
| | | |
| | Y |
| | Y |
| ^ | |
| | / ----------> Transmission -> |
| ^ / | |
| |/ Y |
| | | |
| ^ Y /-qdisc1-\ |
| | Classificateur /--qdisc2--\ |
--->->Gestionnaire de mise de sortie ---qdisc3---- | ->
| en file d'attente (Egress) \__qdisc4__/ |
| d'entrée (Ingress) \-qdiscN_/ |
| |
+-----------------------------------------------------------+
Merci à Jamal Hadi Salim pour cette représentation ascii.
Le grand rectangle représente le noyau. La flèche la plus à
gauche représente le trafic du réseau entrant dans votre machine.
Celui-ci alimente alors le gestionnaire de mise en file d'attente
Ingress qui peut appliquer des filtres à un paquet, et décider de
le supprimer. Ceci est appelé 'réglementation' ('Policing').
Ceci a lieu très tôt, avant d'avoir vu beaucoup de choses du
noyau. C'est par conséquent un très bon endroit pour rejeter au
plus tôt du trafic, sans pour autant consommer beaucoup de
ressources CPU.
Si le paquet est autorisé à continuer, il peut être destiné à
une application locale et, dans ce cas, il entre dans la couche IP
pour être traité et délivré à un programme utilisateur. Le paquet
peut également être transmis sans entrer dans une application et,
dans ce cas, il est destiné à "egress". Les programmes utilisateurs
peuvent également délivrer des données, qui sont alors transmises
et examinées par le classificateur Egress.
Là, il est examiné et mis en file d'attente vers un certain
nombre de gestionnaire de mise en file d'attente. Par défaut, il
n'y a qu'un seul gestionnaire egress installé, pfifo_fast, qui
reçoit tous les paquets. Ceci est appelé "la mise en file
d'attente" (enqueueing).
Le paquet réside maintenant dans le gestionnaire de mise en file
d'attente, attendant que le noyau le réclame pour le transmettre à
travers l'interface réseau. Ceci est appelé "dequeueing" (retirer
d'un file d'attente).
Le schéma ne montre que le cas où il n'y a qu'un adaptateur
réseau. Les flêches entrantes et sortantes du noyau ne doivent pas
être trop prises au pied de la lettre. Chaque adaptateur réseau a
un gestionnaire d'entrée et de sortie.
Les gestionnaires de mise en file d'attente basés sur des
classes sont très utiles si vous avez différentes sortes de trafic
qui devraient être traités différemment. L'un d'entre eux est
appelé 'CBQ', pour 'Class Based Queuing'. Il est si souvent
mentionné que les personnes identifient les gestionnaires de mise
en file d'attente basés sur des classes uniquement à CBQ, ce qui
n'est pas le cas.
CBQ est le mécanisme le plus ancien, ainsi que le plus
compliqué. Il n'aura pas forcément les effets que vous recherchez.
Ceci surprendra peut-être ceux qui sont sous l'emprise de "l'effet
Sendmail", qui nous enseigne qu'une technologie complexe, non
documentée est forcément meilleure que toute autre.
Bientôt, plus à propos de CBQ et de ses alternatives.
Flux à l'intérieur des gestionnaires basés sur des classes
& à l'intérieur des classes
Quand le trafic entre dans un gestionnaire de mise en file
d'attente basé sur des classes, il doit être envoyé vers l'une de
ses classes - il doit être 'classifié'. Pour déterminer que faire
d'un paquet, les élements appelés 'filtres' sont consultés. Il est
important de savoir que les filtres sont appelés de l'intérieur
d'un gestionnaire, et pas d'une autre manière !
Les filtres attachés à ce gestionnaire retournent alors une
décision, et le gestionnaire l'utilise pour mettre en file
d'attente le paquet dans l'une des classes. Chaque sous-classe peut
essayer d'autres filtres pour voir si de nouvelles instructions
s'appliquent. Si ce n'est pas le cas, la classe met le paquet en
file d'attente dans le gestionnaire de mise en file d'attente
qu'elle contient.
En plus de contenir d'autres gestionnaires, la plupart des
gestionnaires de mise en file d'attente basés sur des classes
réalise également de la mise en forme. Ceci est utile pour réaliser
à la fois l'ordonnancement (avec SFQ, par exemple) et le contrôle
de débit. Vous avez besoin de ceci dans les cas où vous avez une
interface à haut débit (ethernet, par exemple) connectée à un
périphérique plus lent (un modem câble).
Si vous n'utilisez que SFQ, rien ne devait se passer, dans la
mesure où les paquets entrent et sortent du routeur sans
délai : l'interface de sortie est de loin beaucoup plus rapide
que la vitesse réelle de votre liaison ; il n'y a alors pas de
files d'attente à réordonnancer.
La famille des gestionnaires de mise en file d'attente :
racines,descripteurs, descendances et parents
Chaque interface à 'un gestionnaire de mise en file d'attente
racine' de sortie (egress root qdisc), par défaut le gestionnaire
de mise en file d'attente sans classes mentionné plus tôt
pfifo_fast. Chaque gestionnaire peut être repéré par un descripteur
(handle), qui pourra être utilisé par les prochaines déclarations
de configuration pour se référer à ce gestionnaire. En plus du
gestionnaire de sortie, une interface peut également avoir un
gestionnaire d'entrée (ingress), qui réglemente le trafic
entrant.
Ces descripteurs sont constitués de deux parties : un nombre
majeur et un nombre mineur. Il est habituel de nommer le
gestionnaire racine 1:, ce qui est équivalent à 1:0. Le nombre
mineur d'un gestionnaire de mise en file d'attente est toujours
0.
Les classes doivent avoir le même nombre majeur que leur
parent.
Comment les filtres sont utilisés pour classifier le
trafic
Pour récapituler, une hiérarchie typique pourrait ressembler à
ceci :
Mais ne laissez pas cet arbre vous abuser ! Vous ne devriez
*pas* imaginer le noyau être au sommet de l'arbre et le réseau
en-dessous, ce qui n'est justement pas le cas. Les paquets sont mis
et retirés de la file d'attente à la racine du gestionnaire, qui
est le seul élément avec lequel le noyau dialogue.
Un paquet pourrait être classifié à travers une chaîne
suivante :
1: -> 1:1 -> 12: -> 12:2
Le paquet réside maintenant dans la file d'attente du
gestionnaire attaché à la classe 12:2. Dans cet exemple, un filtre
a été attaché à chaque noeud de l'arbre, chacun choisissant la
prochaine branche à prendre. Cela est réalisable. Cependant, ceci
est également possible :
1: -> 12:2
Dans ce cas, un filtre attaché à la racine a décidé d'envoyer le
paquet directement à 12:2.
Comment les paquets sont retirés de la file d'attente et
envoyés vers lematériel
Quand le noyau décide qu'il doit extraire des paquets pour les
envoyer vers l'interface, le gestionnaire racine 1: reçoit une
requête de "dequeue", qui est transmise à 1:1 et qui, à son tour,
est passée à 10:, 11: et 12:, chacune interrogeant leurs
descendances qui essaient de retirer de leur file d'attente les
paquets. Dans ce cas, le noyau doit parcourir l'ensemble de
l'arbre, car seul 12:2 contient un paquet.
En résumé, les classes "emboîtées" ne parlent SEULEMENT qu'à
leur gestionnaire de mise en file d'attente parent, jamais à une
interface. Seul le gestionnaire racine a sa file d'attente vidée
par le noyau !
Le résultat de ceci est que les classes ne retirent jamais d'une
file d'attente plus vite que ce que leur parent n'autorise. Et
c'est exactement ce que nous voulons : de cette manière, nous
pouvons avoir SFQ dans une classe interne qui ne fait pas de mise
en forme, mais seulement de l'ordonnancement, et avoir un
gestionnaire de mise en file d'attente extérieur qui met en forme
le trafic.
Le gestionnaire de mise en file d'attente PRIO
Le gestionnaire de mise en file d'attente ne met pas vraiment en
forme le trafic ; il ne fait que le subdiviser en se basant
sur la manière dont vous avez configuré vos filtres. Vous pouvez
considérer les gestionnaires PRIO comme une sorte de super
pfifo_fast dopé, où chaque bande est une classe séparée au lieu
d'une simple FIFO.
Quand un paquet est mis en file d'attente dans le gestionnaire
PRIO, une classe est choisie en fonction des filtres que vous avez
donnés. Par défaut, trois classes sont créées. Ces classes
contiennent par défaut de purs gestionnaires de mise en file
d'attente FIFO sans structure interne, mais vous pouvez les
remplacer par n'importe quels gestionnaires disponibles.
Chaque fois qu'un paquet doit d'être retiré d'une file
d'attente, la classe :1 est d'abord essayée. Les classes plus
élevées ne sont utilisées que si aucune des bandes plus faibles n'a
fourni de paquets.
Cette file d'attente est très utile dans le cas où vous voulez
donner la priorité à certain trafic en utilisant toute la puissance
des filtres tc et en ne se limitant pas seulemenent aux options du
champ TOS. Il peut également contenir n'importe quel gestionnaire
de mise en file d'attente, tandis que pfifo_fast est limité aux
gestionnaires simples fifo.
Puisque il ne met pas vraiment en forme, il y a le même
avertissement que pour SFQ. N'utilisez PRIO seulement que si votre
lien physique est vraiment saturé ou intégrez-le à l'intérieur d'un
gestionnaire de mise en file d'attente basé sur des classes qui
réalise la mise en forme. Ce dernier cas est valable pour
pratiquement tous les modems-câbles et les périphériques DSL.
En terme formel, le gestionnaire de mise en file d'attente PRIO
est un ordonnanceur "Work-Conserving".
paramètres PRIO & usage
Les paramètres suivants sont reconnus par tc :
bands
Nombre de bandes à créer. Chaque bande est en fait une classe.
Si vous changez ce nombre, vous devez également changer :
priomap
Si vous ne fournissez pas de filtres tc pour classifier le
trafic, le gestionnaire PRIO regarde la priorité TC_PRIO pour
décider comment mettre en file d'attente le trafic.
Ceci fonctionne comme le gestionnaire de mise en file d'attente
pfifo_fast mentionné plus tôt. Voir la section correspondante pour
plus de détails.
Les bandes sont des classes et sont appelées par défaut majeur:1 à
majeur:3. Donc, si votre gestionnaire de mise en file d'attente est
appelé 12:, tc filtre le trafic vers 12:1 pour lui accorder une
plus grande priorité.
Par itération, la bande 0 correspond au nombre mineur 1, la
bande 1 au nombre mineur 2, etc ...
Comme vous pouvez le voir, tout le trafic a été envoyé comme prévu
vers le descripteur 30:, qui est la bande de plus faible priorité.
Maintenant, pour vérifier que le trafic interactif va vers les
bandes de plus grande priorité, nous générons du trafic
interactif :
Ca a marché. Tout le trafic supplémentaire a été vers 10:, qui
est notre gestionnaire de plus grande priorité. Aucun trafic n'a
été envoyé vers les priorités les plus faibles, qui avaient reçu au
préalable tout le trafic venant de notre scp.
Le célèbre gestionnaire de mise en file d'attente CBQ
Comme dit avant, CBQ est le gestionnaire de mise en file
d'attente disponible le plus complexe, celui qui a eu le plus de
publicité, le moins compris et probablement le plus farceur lors de
sa mise au point. Ce n'est pas parce que les auteurs sont mauvais
ou incompétents, loin de là, mais l'algorithme CBQ n'est pas
remarquablement précis et il ne correspond pas vraiment à la façon
dont Linux fonctionne.
En plus d'être basé sur des classes, CBQ est également un
metteur en forme de trafic et c'est sur cet aspect qu'il ne
fonctionne pas très bien. Il travaille comme ceci : si vous
essayez de mettre en forme une connexion de 10 mbit/s à 1mbits/s,
le lien doit être inactif 90% du temps. Si ce n'est pas le cas,
nous devons limiter le taux de sorte qu'il SOIT inactif 90% du
temps.
Ceci est assez dur à mesurer et, au lieu de cela, CBQ déduit le
temps d'inactivité du nombre de microsecondes qui s'écoule entre
des requêtes de la couche matérielle pour avoir plus de données.
Combiné, ceci peut être utilisé pour évaluer si le lien est chargé
ou non.
Ceci est plutôt léger et l'on arrive pas toujours à des
résultats convenables. Par exemple, quelle est la vitesse de
liaison réelle d'une interface qui n'est pas capable de transmettre
pleinement 100mbit/s de données, peut-être à cause d'un mauvais
pilote de périphérique ? Une carte réseau PCMCIA ne pourra
jamais atteindre 100mbit/s à cause de la conception du bus. De
nouveau, comme calculons-nous le temps d'inactivité ?
Cela devient même pire quand on considère un périphérique réseau
"pas-vraiment-réel" comme PPP Over Ethernet ou PPTP over TCP/IP. La
largeur de bande effective est, dans ce cas, probablement
déterminée par l'efficacité des tubes vers l'espace utilisateur,
qui est énorme.
Les personnes qui ont effectué des mesures ont découvert que CBQ
n'est pas toujours très exact et, parfois même, est très éloigné de
la configuration.
Cependant, il marche bien dans de nombreuses circonstances. Avec
la documentation fournie ici, vous devriez être capables de le
configurer pour qu'il fonctionne bien dans la plupart des cas.
Mise en forme CBQ en détail
Comme dit précédemment, CBQ fonctionne en s'assurant que le lien
est inactif juste assez longtemps pour abaisser la bande passante
réelle au débit configuré. Pour réaliser cela, il calcule le temps
qui devrait s'écouler entre des paquets de taille moyennne.
En cours de fonctionnement, le temps d'inactivité effective (the
effective idletime) est mesuré en utilisant l'algorithme EWMA
(Exponential Weighted Moving Average), qui considère les paquets
récents être exponentiellement plus importants que ceux passés. La
charge moyenne (loadaverage) UNIX est calculée de la même
manière.
Le temps d'inactivité calculé est soustrait à celui mesuré par
EWMA et le nombre résultant est appelé "avgidle". Un lien
parfaitement chargé a un "avgidle" nul : un paquet arrive à
chaque intervalle calculé.
Une liaison surchargée a un avgidle négatif et s'il devient trop
négatif, CBQ s'arrête un moment et est alors en 'overlimit'
(dépassement de limite).
Inversement, un lien inoccupé peut amasser une avgidle énorme,
qui autoriserait alors des bandes passantes infinies après quelques
heures d'inactivité. Pour éviter cela, avgidle est borné à
maxidle.
En situation de dépassement de limite, CBQ peut, en théorie,
bloquer le débit pour une durée équivalente au temps qui doit
s'écouler entre deux paquets moyens, plus laisser passer un paquet,
et bloquer de nouveau le débit. Regardez cependant le paramètre
'minburst' ci-dessous.
Voici les paramètres que vous pouvez spécifier pour configurer
la mise en forme :
avpkt
Taille moyenne d'un paquet, mesurée en octets. Nécessaire pour
calculer maxidle, qui dérive de maxburst, qui est spécifié en
paquets.
bandwidth
La bande passante physique de votre périphérique, nécessaire
pour les calculs du temps d'inoccupation (idle time).
cell
La durée de transmission d'un paquet n'augmente pas
nécessairement de manière linéaire en fonction de sa taille. Par
exemple, un paquet de 800 octets peut mettre exactement autant de
temps à transmettre qu'un paquet de 806 octets. Ceci détermine la
granularité. Cette valeur est généralement positionné à 8, et doit
être une puissance de deux.
maxburst
Ce nombre de paquets est utilisé pour calculer maxidle de telle
sorte que quand avgidle est égal à maxidle, ce nombre de paquets
moyens peut être envoyé en rafale avant que avgidle ne retombe à 0.
Augmenter le pour être plus tolérant vis à vis des rafales de
données. Vous ne pouvez pas configurer maxidle directement, mais
seulement via ce paramètre.
minburst
Comme nous l'avons déjà indiqué, CBQ doit bloquer le débit dans
le cas d'un dépassement de limite. La solution idéale est de le
faire pendant exactement le temps d'inoccupation calculé, puis de
laisser passer un paquet. Cependant, les noyaux UNIX ont
généralement du mal à prévoir des événements plus courts que 10 ms,
et il est donc meilleur de limiter le débit pendant une période
plus longue, puis d'envoyer minburst paquets d'un seul coup, et de
dormir pendant une période de minburst.
Le temps d'attente est appelé "offtime". De plus grandes valeurs
de minburst mènent à une mise en forme plus précise dans le long
terme, mais provoquent de plus grandes rafales de données pendant
des périodes de quelques millisecondes.
minidle
Si avgidle est inférieur à 0, nous sommes en dépassement de
limite et nous devons attendre jusqu'à ce que avgidle devienne
suffisamment important pour envoyer un paquet. Pour éviter qu'une
brusque rafale de données n'empêche le lien de fonctionner pendant
une période prolongée, avgidle est remis à minidle s'il atteint une
valeur trop basse.
Minidle est spécifié en microsecondes négatives : 10
signifie alors que avgidle est borné à -10us.
mpu
Taille minumum d'un paquet. Nécessaire car même un paquet de
taille nulle est encapsulé par 64 octets sur ethernet et cela prend
donc un certain temps pour le transmettre. CBQ doit connaître ceci
pour calculer précisément le temps d'inoccupation.
rate
Débit du trafic sortant du gestionnaire. Ceci est le 'paramètre
de vitesse' !
En interne, CBQ est finement optimisé. Par exemple, les classes
qui sont connues pour ne pas avoir de données mises dans leur file
d'attente ne sont pas interrogées. Les classes en situation de
dépassement de limite sont pénalisées par la diminution de leur
priorité effective. Tout ceci est très habile et compliqué.
Comportement de CBQ classful
En plus de la mise en forme, en utilisant les approximations
idletime mentionnées ci-dessus, CBQ peut également agir comme une
file d'attente PRIO dans le sens où les classes peuvent avoir
différentes priorités et que les nombres de priorité les plus
faibles seront examinés avant ceux plus élevés.
Chaque fois qu'un paquet est requis par la couche matérielle
pour être envoyé sur le réseau, un processus "weighted round robin"
('WRR') démarre, en commençant par les classes de plus faibles
priorités.
Celles-ci sont regroupées et interrogées si elles ont des
données disponibles. Après qu'une classe a été autorisée à retirer
de la file d'attente un nombre d'octets, la classe de priorité
suivante est essayée.
Les paramètres suivants contrôlent le processus WRR :
allot
Quand le cbq racine reçoit une demande d'envoi de paquets sur
une interface, il va essayer tous les gestionnaires internes (dans
les classes) tour à tour, dans l'ordre du paramètre 'priority'. A
chaque passage, une classe ne peut envoyer qu'une quantité limitée
de données. 'Allot' est l'unité de base de cette quantité. Voir le
paramètre 'weight' pour plus d'informations.
prio
CBQ peut également agir comme un périphérique PRIO. Les classes
internes avec les priorités les plus faibles sont essayées en
premier et, aussi longtemps qu'elles ont du trafic, les autres
classes ne sont pas examinées.
weight
Weight aide le processus Weighted Round Robin. Chaque classe a
tour à tour la possibilité d'envoyer ses données. Si vous avez des
classes avec des bandes passantes significativement plus
importantes, il est logique de les autoriser à envoyer plus de
données à chaque tour que les autres.
Vous pouvez utiliser des nombres arbitraires dans la mesure où
CBQ additionne tous les paramètres 'weight' présents sous une
classe et les normalisent. La règle empirique qui consiste à
prendre 'rate/10' semble marcher correctement. Le "weight"
renormalisé est multiplié par le paramètre 'allot' pour déterminer
la quantité de données à envoyer à chaque tour.
Notez, s'il vous plaît, que toutes les classes à l'intérieur
d'une hiérarchie CBQ doivent avoir le même nombre majeur !
Paramêtres CBQ qui déterminent le partage & le prêt du
lien
En plus de purement limiter certain trafic, il est également
possible de spécifier quelles classes peuvent emprunter de la bande
passante aux autres classes ou, réciproquement, prêter sa bande
passante.
Isolated/sharing
Une classe qui est configurée avec 'isolated' ne prêtera pas sa
bande passante à ses classes enfants. Utilisez ceci si vous avez
sur votre lien deux agences concurrentes ou qui ne s'apprécient pas
et qui ne veulent pas se prêter gratuitement de la bande
passante.
Le programme de contrôle tc connait également 'sharing', qui est
l'inverse de 'isolated'.
bounded/borrow
Une classe peut aussi être 'bounded' (bornée), ce qui signifie
qu'elle n'essaiera pas d'emprunter de la bande passante à ses
classes enfants. tc connait également 'borrow', qui est l'inverse
de 'bounded'.
Une situation typique pourrait être le cas où vous avez deux
agences présentes sur votre lien qui sont à la fois 'isolated' et
'bounded'. Ceci signifie qu'elles sont strictement limitées à leur
débit et qu'elles ne prêteront pas aux autres leur bande
passante.
A l'intérieur de ces classes d'agence, il pourrait y avoir
d'autres classes qui soient autorisée à échanger leur bande
passante.
Configuration simple
Cette configuration limite le trafic d'un serveur web à 5mbit et
le trafic smtp à 3mbit. Il est souhaitable qu'ils n'occupent pas
plus de 6 mbit à eux deux. Nous avons une carte réseau à 100mbit et
les classes peuvent s'emprunter mutuellement de la bande
passante.
Cette partie installe la racine et la classe 1:0 habituelle. La
classe 1:1 est bornée, la bande passante totale ne pourra donc pas
excéder 6mbit.
Comme dit avant, CBQ a besoin de *nombreux* paramètres. Tous ces
paramètres sont cependant expliqués au-dessus. La configuration HTB
correspondante est beaucoup plus simple.
Ce sont nos deux classes. Notez comment nous avons configuré la
valeur du paramètre "weight" en fonction du paramètre "rate". La
bande passante des deux classes ensemble ne pourra jamais dépasser
6mbit. Au fait, les identifieurs de classe (classid) doivent avoir
le même numéro majeur que le parent CBQ !
Les deux classes ont par défaut un gestionnaire de mise en file
d'attente FIFO. Nous les remplaçons par une file d'attente SFQ de
telle sorte que chaque flux de données soit traité de manière
égale.
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
sport 80 0xffff flowid 1:3
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \
sport 25 0xffff flowid 1:4
Ces commandes, directement attachées à la racine, envoient le
trafic vers le bon gestionnaire de mise en file d'attente.
Notez que nous utilisons 'tc class add' pour CREER des classes à
l'intérieur d'un gestionnaire de mise en file d'attente, mais que
nous utilisons 'tc qdisc add' pour véritablement configurer ces
classes.
Vous vous demandez peut-être ce qui arrive au trafic qui n'est
classifier par aucune des deux règles. Dans ce cas, les données
seront traitées à l'intérieur de 1:0, et le débit ne sera pas
limité.
Si smtp+web tente de dépasser la limite de 6mbit/s, la bande
passante sera divisée selon le paramètre "weight", donnant 5/8 du
trafic au serveur web et 3/8 au serveur smtp.
Avec cette configuration, vous pouvez également dire que le
trafic du serveur web sera au minimum de 5/8 * 6 mbit = 3.75
mbit.
D'autres paramètres CBQ : split & defmap
Comme précisé avant, un gestionnaire de mise en file d'attente
basé sur des classes doit appelé des filtres pour déterminer dans
quelle classe un paquet sera mis en file d'attente.
En plus d'appeler les filtres, CBQ offre d'autres options :
defmap & split. C'est plutôt compliqué à comprendre et, de
plus, ce n'est pas vital. Mais, étant donné que ceci est le seul
endroit connu ou defmap & split sont correctement expliqués, je
vais faire de mon mieux.
Etant donné que nous voulons le plus souvent réaliser le
filtrage en ne considérant que le champ TOS, une syntaxe spéciale
est fournie. Chaque fois que CBQ doit trouver où le paquet doit
être mis en file d'attente, il vérifie si le noeud est un 'split
node'. Si c'est le cas, un de ses sous-gestionnaire a indiqué son
souhait de recevoir tous les paquets configurés avec une certaine
priorité, qui peut être dérivée du champ TOS ou des options des
sockets positionnées par les applications.
Les bits de priorités des paquets subissent un OU logique avec
le champ defmap pour voir si une correspondance existe. En d'autres
termes, ceci un moyen pratique de créer un filtre très rapide, qui
ne sera actif que pour certaines priorités. Un defmap de ff (en
hexa) vérifiera tout tandis qu'une valeur de 0 ne vérifiera rien.
Une configuration simple aidera peut-être à rendre les choses plus
claires :
Préambule standard de CBQ. Je n'ai jamais pris l'habitude de la
quantité de nombres nécessaires !
Defmap se réfère aux bits TC_PRIO qui sont définis comme
suit :
TC_PRIO.. Num Correspond à TOS
-------------------------------------------------
BESTEFFORT 0 Maximalise la Fiabilité
FILLER 1 Minimalise le Coût
BULK 2 Maximalise le Débit (0x8)
INTERACTIVE_BULK 4
INTERACTIVE 6 Minimise le Délai (0x10)
CONTROL 7
Les nombres TC_PTIO.. correspondent aux bits comptés à partir de
la droite. Voir la section pfifo_fast pour plus de détails sur la
façon dont les bits TOS sont convertis en priorités.
La 'split qdisc' est 1:0 et c'est à ce niveau que le choix sera
fait. C0 représente le nombre binaire 11000000, et 3F le nombre
binaire 00111111, de telle sorte qu'à eux deux, ils vérifient tout.
La première classe correspond aux bits 6 & 7, ce qui est
équivalent aux trafics 'interactif' et de 'contrôle'. La seconde
classe correspond au reste.
Le noeud 1:0 possède maintenant la table suivante :
Pour d'autres amusements, vous pouvez également donner un
'masque de change' qui indique exactement les priorités que vous
souhaitez changer. N'utilisez ceci qu'avec la commande 'tc class
change'. Par exemple, pour ajouter le trafic "best effort" à la
classe 1:2, nous devrons exécuter ceci :
# tc class change dev eth1 classid 1:2 cbq defmap 01/01
La carte des priorités au niveau de 1:0 ressemble maintenant à
ceci :
FIXME: 'tc class change' n'a pas été testé, mais simplement vu
dans les sources.
Hierarchical Token Bucket (Seau à jetons hiérarchique)
Martin devera(<devik>) réalisa à juste titre que CBQ est
complexe et qu'il ne semble pas optimisé pour de nombreuses
situations classiques. Son approche hiérarchique est bien adaptée
dans le cas de configurations où il y a une largeur de bande
passante fixée à diviser entre différents éléments. Chacun de ces
éléments aura une bande passante garantie, avec la possibilité de
spécifier combien de bande passante pourront être empruntée.
HTB travaille juste comme CBQ, mais il ne recourt pas à des
calculs de temps d'inoccupation pour la mise en forme. A la place,
c'est un Token Bucket Filter basé sur des classes, d'où son nom. Il
n'a que quelques paramètres, qui sont bien documentés sur ce site.
Au fur et à mesure que votre configuration HTB se complexifie,
votre configuration s'adapte bien. Avec CBQ, elle est déjà complexe
meme dans les cas simples ! HTB ne fait pas encore partie du
noyau standard, mais cela devrait bientôt être le cas !
Si vous êtes sur le point de mettre à jour votre noyau,
considérez coûte que coûte HTB.
Configuration simple
Fonctionnellement presque identique à la configuration simple
CBQ présentée au-dessus :
# tc qdisc add dev eth0 root handle 1: htb default 30
# tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k
# tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k
# tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k
# tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k
Ajouter les filtres qui dirigent le trafic vers les bonnes
classes :
# U32="tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32"
# $U32 match ip dport 80 0xffff flowid 1:10
# $U32 match ip sport 25 0xffff flowid 1:20
Et, c'est tout. Pas de vilains nombres non expliqués, pas de
paramètres non documentés.
HTB semble vraiment merveilleux. Si 10: et 20: ont atteint tous
les deux leur bande passante garantie et qu'il en reste à partager,
ils l'empruntent avec un rapport de 5:3, comme attendu.
Le trafic non classifié est acheminé vers 30:, qui a une petite
bande passante, mais qui peut emprunter tout ce qui est laissé.
Puisque nous avons choisi SFQ en interne, on hérite naturellement
de l'équité.
Pour déterminer quelle classe traitera un paquet, la "chaîne de
classificateurs" est appelée chaque fois qu'un choix a besoin
d'être fait. Cette chaîne est constituée de tous les filtres
attachés aux gestionnaires de mise en file d'attente basés sur des
classes qui doivent prendre une décision.
Quand un paquet est mis en file d'attente, l'instruction
appropriée de la chaîne de filtre est consultée à chaque branche.
Une configuration typique devrait avoir un filtre en 1:1 qui dirige
le paquet vers 12: et un filtre en 12: qui l'envoie vers 12:2.
Vous pourriez également avoir ce dernier filtre en 1:1, mais
vous pouvez gagner en efficacité en ayant des tests plus
spécifiques plus bas dans la chaîne.
A propos, vous ne pouvez pas filtrer un paquet 'vers le haut'.
Donc, avec HTB, vous devrez attacher tous les filtres à la
racine !
Encore une fois, les paquets ne sont mis en file d'attente que
vers le bas ! Quand ils sont retirés de la file d'attente, ils
montent de nouveau, vers l'interface. Ils ne tombent PAS vers
l'extrémité de l'arbre en direction de l'adaptateur
réseau !
Quelques exemples simples de filtrage
Comme expliqué dans le chapitre des Classificateurs, vous pouvez
vraiment analyser n'importe quoi en utilisant une syntaxe très
compliquée. Pour commencer, nous allons montrer comment réaliser
les choses évidentes, ce qui heureusement est plutôt facile.
Disons que nous avons un gestionnaire de mise en file d'attente
PRIO appelé '10:' qui contient trois classes, et que nous voulons
assigner à la bande de plus haute priorité tout le trafic allant et
venant du port 22. Les filtres seraient les suivants :
# tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match \
ip dport 22 0xffff flowid 10:1
# tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match \
ip sport 80 0xffff flowid 10:1
# tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2
Que cela dit-il ? Cela dit : attacher à eth0, au noeud
10: un filtre u32 de priorité 1 qui analyse le port de destination
IP 22 et qui l'envoie vers la bande 10:1. La même chose est répétée
avec le port source 80. La dernière commande indique que si aucune
correspondance n'est trouvée, alors le trafic devra aller vers la
bande 10:2, la plus grande priorité suivante.
Vous devez ajouter 'eth0' ou n'importe laquelle de vos
interfaces, car chaque interface à un espace de nommage de ces
descripteurs qui lui est propre.
Pour sélectionner une adresse IP, utilisez ceci :
# tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 \
match ip dst 4.3.2.1/32 flowid 10:1
# tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 \
match ip src 1.2.3.4/32 flowid 10:1
# tc filter add dev eth0 protocol ip parent 10: prio 2 \
flowid 10:2
Ceci dirige le trafic allant vers 4.3.2.1 et venant de 1.2.3.4
vers la file d'attente de plus haute priorité, tandis que le reste
ira vers la prochaine plus haute priorité.
Vous pouvez rassembler ces deux vérifications pour récupérer le
trafic venant de 1.2.3.4 avec le port source 80 :
# tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 4.3.2.1/32
match ip sport 80 0xffff flowid 10:1
Toutes les commandes de filtres dont vous aurez normalement
besoin
La plupart des commandes présentées ici commencent avec le
préambule suivant :
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 ..
Ils sont appelés filtres 'u32' qui analysent N'IMPORTE QUELLE
partie d'un paquet.
Sur l'adresse source/destination
Masque pour la source 'match ip src 1.2.3.0/24', masque pour la
destination 'match ip dst 4.3.2.0/24'. Pour analyser un hôte
simple, employez /32 ou omettez le masque.
Sur le port source/destination, tous les protocoles
IP
Source: 'match ip sport 80 0xffff', 'match ip dport 0xffff'
Sur le protocole ip (tcp, udp, icmp, gre, ipsec)
Utilisez les nombres définis dans /etc/protocols, par exemple 1
pour icmp : 'match ip protocol 1 0xff'.
Sur fwmark
Vous pouvez marquer les paquets avec, par exemple ipchains, et
avoir cette marque qui survit au routage à travers les interfaces.
Ceci est vraiment utile pour, par exemple, seulement mettre en
forme le trafic sur eth1 et venant de eth0. La syntaxe est la
suivante :
# tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6
fw classid 1:1 Notez que ce n'est pas une correspondance
u32 !
Vous pouvez positionner une marque comme ceci :
# iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6
Le nombre 6 est arbitraire.
Si vous ne voulez pas comprendre la syntaxe complète de "tc
filter", utilisez juste iptables et n'apprenez seulement que la
sélection en se basant sur fwmark.
Sur le champ TOS
Pour sélectionner le trafic interactif, délai minimum :
# tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 \
match ip tos 0x10 0xff \
flowid 1:4
Utilisez 0x08 0xff pour le trafic de masse.
Pour plus de commandes de filtrage, voir le chapitre des Filtres
Avancés.