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 doivent être traités différemment. L'un d'entre eux est appelé CBQ, pour Class Based Queueing. 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.
Nous évoquerons bientôt, plus à propos, CBQ et ses alternatives.
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 éléments 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 autrement !
Les filtres attachés à ce gestionnaire renvoient alors une décision que le gestionnaire utilise pour mettre en file d'attente le paquet vers 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éalisent é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.
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 et classe est 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 : <major>:<minor>.
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. Le nombre majeur doit être unique à l'intérieur d'une configuration egress ou ingress. Le nombre mineur doit être unique à l'intérieur d'un gestionnaire de mise en file d'attente et de ses classes.
Pour récapituler, une hiérarchie typique pourrait ressembler à ceci :
1: Gestionnaire de mise en file d'attente racine | 1:1 classe enfant / | \ / | \ / | \ / | \ 1:10 1:11 1:12 classes enfants | | | | 11: | classe terminale | | 10: 12: Gestionnaire de mise en file d'attente / \ / \ 10:1 10:2 12:1 12:2 classes terminales
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
.
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 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 les paquets de leur file d'attente.
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 » parlent uniquement à leur gestionnaire de mise en file d'attente parent ; jamais à une interface. Seul la file d'attente du gestionnaire racine est vidée par le noyau !
Ceci a pour résultat que les classes ne retirent jamais les paquets d'une file d'attente plus vite que ce que leur parent 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 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 être retiré d'une file d'attente,
la classe :1
est d'abord testée.
Les classes plus élevées ne sont utilisées que si aucune des bandes plus
faibles n'a pas fourni de paquets.
Cette file d'attente est très utile dans le cas où vous voulez donner la
priorité à certains trafics en utilisant toute la puissance des filtres
tc et en ne se limitant pas seulement aux options du
champ TOS.
Vous pouvez également ajouter un autre gestionnaire de mise en file d'attente
aux trois classes prédéfinies, tandis que pfifo_fast
est limité aux
simples gestionnaires FIFO.
Puisqu'il ne met pas vraiment en forme, on applique le même avertissement que pour SFQ. Utilisez PRIO seulement 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éalisent la mise en forme. Ce dernier cas est valable pour pratiquement tous les modems-câbles et les périphériques DSL.
En termes formels, le gestionnaire de mise en file d'attente PRIO est un ordonnanceur Work-Conserving.
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.
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 ...
Nous allons créer cet arbre :
racine 1: prio 1: Gestionnaire racine / | \ / | \ / | \ 1:1 1:2 1:3 classes | | | 10: 20: 30: gestionnaire gestionnaire sfq tbf sfq bande 0 1 2
Le trafic de masse ira vers 30:
tandis que le
trafic interactif ira vers 20:
ou
10:
.
Les lignes de commande :
# tc qdisc add dev eth0 root handle 1: prio ## Ceci crée *instantanément* les classes 1:1, 1:2, 1:3 # tc qdisc add dev eth0 parent 1:1 handle 10: sfq # tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000 # tc qdisc add dev eth0 parent 1:3 handle 30: sfq
Regardons maintenant ce que nous avons créé :
# tc -s qdisc ls dev eth0 qdisc sfq 30: quantum 1514b Sent 0 bytes 0 pkts (dropped 0, overlimits 0) qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms Sent 0 bytes 0 pkts (dropped 0, overlimits 0) qdisc sfq 10: quantum 1514b Sent 132 bytes 2 pkts (dropped 0, overlimits 0) qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 174 bytes 3 pkts (dropped 0, overlimits 0)Comme vous pouvez le voir, la bande 0 a déjà reçu du trafic, et un paquet a été envoyé pendant l'exécution de cette commande !
Nous allons maintenant générer du trafic de masse avec un outil qui configure correctement les options TOS, et regarder de nouveau :
# scp tc ahu@10.0.0.11:./ ahu@10.0.0.11's password: tc 100% |*****************************| 353 KB 00:00 # tc -s qdisc ls dev eth0 qdisc sfq 30: quantum 1514b Sent 384228 bytes 274 pkts (dropped 0, overlimits 0) qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms Sent 2640 bytes 20 pkts (dropped 0, overlimits 0) qdisc sfq 10: quantum 1514b Sent 2230 bytes 31 pkts (dropped 0, overlimits 0) qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 389140 bytes 326 pkts (dropped 0, overlimits 0)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 :
# tc -s qdisc ls dev eth0 qdisc sfq 30: quantum 1514b Sent 384228 bytes 274 pkts (dropped 0, overlimits 0) qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms Sent 2640 bytes 20 pkts (dropped 0, overlimits 0) qdisc sfq 10: quantum 1514b Sent 14926 bytes 193 pkts (dropped 0, overlimits 0) qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 Sent 401836 bytes 488 pkts (dropped 0, overlimits 0)
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.
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é, qui est le moins compris et qui est 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 sert également à la mise 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 10mbit/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 c'est pour cette raison que CBQ déduit le temps d'inactivité du nombre de microsecondes qui s'écoulent entre les requêtes de la couche matérielle pour avoir plus de données. Cette combinaison peut être utilisée 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, qu'en est-il de la vitesse de liaison réelle d'une interface qui n'est pas capable de transmettre pleinement les données à 100mbit/s, 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, comment 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, très éloigné de la configuration.
Cependant, il marche bien dans de nombreuses circonstances. Avec la documentation fournie ici, vous devriez être capable de le configurer pour qu'il fonctionne bien dans la plupart des cas.
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é effectif (the effective idletime) est mesuré en utilisant l'algorithme EWMA (Exponential Weighted Moving Average), qui considère que les paquets récents sont exponentiellement plus nombreux que ceux passés. La charge moyenne UNIX (UNIX loadaverage) 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 se place
alors en dépassement de limite (overlimit).
Inversement, un lien inutilisé peut accumuler un
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, puis 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 de non utilisation (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 être transmis en exactement
autant de temps qu'un paquet de 806 octets.
Ceci détermine la granularité.
Cette valeur est généralement positionnée à 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
,
le nombre de paquets moyens peut être envoyé en rafale avant que
avgidle
ne retombe à 0.
Augmentez-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'inutilisation 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, il vaut donc mieux limiter le débit
pendant une période plus longue, puis envoyer
minburst
paquets d'un seul coup et dormir pendant une
durée 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 durée prolongée, avgidle
est remis à minidle
s'il atteint une valeur trop
basse.
La valeur minidle
est spécifiée en
microsecondes négatives : 10 signifie alors que
avgidle
est borné à -10µs.
mpu
Taille minumum d'un paquet. Nécessaire car même un paquet de taille nulle est encapsulé par 64 octets sur ethernet et il faut donc un certain temps pour le transmettre. CBQ doit connaître ce paramètre pour calculer précisément le temps d'inutilisation.
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 présentes 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é.
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.
Les priorités de plus faible valeur seront examinées avant celles de
valeurs plus élevées.
Chaque fois qu'un paquet est demandé 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 numéros.
Celles-ci sont regroupées et interrogées si elles ont des données disponibles. Après qu'une classe ait été autorisée à retirer de la file d'attente un nombre d'octets, la classe de priorité suivante est consulté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 suivant l'ordre du paramètre
priority
.
A chaque passage, une classe ne peut envoyer qu'une quantité limitée de
données.
Le paramètre 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 élevées sont consultées en premier et, aussi longtemps qu'elles ont du trafic, les autres classes ne sont pas examinées.
weight
Le paramètre weight
assiste 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 normalise.
La règle empirique qui consiste à prendre rate/10
semble fonctionner correctement.
Le paramètre weight
normalisé 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 !
En plus de purement limiter certains trafics, 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 soeurs.
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 agit à l'inverse du paramètre
isolated
.
bounded
/
borrow
Une classe peut aussi être bornée (bounded
),
ce qui signifie qu'elle n'essaiera pas d'emprunter de la bande passante à
ses classes enfants.
tc connait également borrow
, qui
agit à 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 sont autorisées à échanger leur bande passante.
1: gestionnaire de mise en file d'attente racine | 1:1 classe enfant / \ / \ 1:3 1:4 classes terminales | | 30: 40: gestionnares de mise en file d'attente (sfq) (sfq)
Cette configuration limite le trafic d'un serveur web à 5 mbit et le trafic SMTP à 3 mbit. Il est souhaitable qu'ils n'occupent pas plus de 6 mbit à eux deux. Nous avons une carte réseau à 100 mbit et les classes peuvent s'emprunter mutuellement de la bande passante.
# tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit \ avpkt 1000 cell 8 # tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit \ rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 \ avpkt 1000 boundedCette partie installe la racine et la classe
1:1
habituelle.
La classe 1:1
est bornée, la bande passante totale ne
pourra donc pas excéder 6 mbit.
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.
# tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit \ rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 \ avpkt 1000 # tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit \ rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 \ avpkt 1000
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 de l'ensemble des deux classes ne pourra jamais dépasser
6 mbit.
En fait, les identifieurs de classe (classid
) doivent
avoir le même numéro majeur que le gestionnaire de mise en file d'attente parent !
# tc qdisc add dev eth0 parent 1:3 handle 30: sfq # tc qdisc add dev eth0 parent 1:4 handle 40: sfq
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, et 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
classifié 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 le trafic SMTP+web tente de dépasser la limite de 6 mbit/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.
Comme précisé avant, un gestionnaire de mise en file d'attente basé sur des classes doit appeler 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 où
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 noeud d'aiguillage (split node). Si c'est le cas, un de ses sous-gestionnaires a indiqué son souhait de recevoir tous les paquets configurés avec une certaine priorité. Celle ci 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 ET logique avec le champ
defmap
pour voir si une correspondance existe.
En d'autres termes, c'est 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 hexadécimal) vérifiera
tout tandis qu'une valeur de 0
ne vérifiera rien.
Une configuration simple aidera peut-être à rendre les choses plus
claires :
# tc qdisc add dev eth1 root handle 1: cbq bandwidth 10Mbit allot 1514 \ cell 8 avpkt 1000 mpu 64 # tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit \ rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 \ avpkt 1000
Préambule standard de CBQ. Je n'ai jamais pris l'habitude de la quantité de nombres nécessaires !
Le paramètre 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_PRIO.. 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.
Maintenant, les classes interactive et de masse :
# tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit \ rate 1Mbit allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 \ avpkt 1000 split 1:0 defmap c0 # tc class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit \ rate 8Mbit allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 \ avpkt 1000 split 1:0 defmap 3f
La gestion de mise en file d'attente d'aiguillage
(split qdisc) est 1:0
et c'est
à ce niveau que le choix sera fait.
C0
correspond au nombre binaire
11000000
et 3F
au nombre binaire
00111111
.
Ces valeurs sont choisies de telle sorte qu'à elles deux, elles vérifient tous
les bits.
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 :
priorité envoyer à 0 1:3 1 1:3 2 1:3 3 1:3 4 1:3 5 1:3 6 1:2 7 1:2
Pour d'autres amusements, vous pouvez également donner un
« masque de changement » 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 :
priorité envoyer à 0 1:2 1 1:3 2 1:3 3 1:3 4 1:3 5 1:3 6 1:2 7 1:2
FIXME: tc class change
n'a pas été testé, mais
simplement vu dans les sources.
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 la quantité de bande passante qui pourra être empruntée.
HTB travaille juste comme CBQ, mais il n'a pas recourt à 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 même dans les cas simples ! HTB3 (voir sa page principale pour les détails des versions HTB) fait maintenant parti des sources officielles du noyau (à partir des versions 2.4.20-pre1 et 2.5.31 et supérieures). Il est encore cependant possible que vous soyez obligé de récupérer la version mise à jour de 'tc' pour HTB3. Les programmes de l'espace utilisateur et la partie HTB du noyau doivent avoir le même numéro majeur. Sans cela, 'tc' ne marchera pas avec HTB.
Si vous avez déjà un noyau récent ou si vous êtes sur le point de mettre à jour votre noyau, considérez HTB coûte que coûte.
Fonctionnellement presque identique à la configuration simple CBQ présentée ci-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
L'auteur recommande SFQ sous ces classes :
# tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10 # tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10 # tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
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é libre.
Puisque nous avons choisi SFQ en interne, on hérite
naturellement de l'équité.