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 nœud 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.
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 ...
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 demaxburst
, 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 quandavgidle
est égal àmaxidle
, le nombre de paquets moyens peut être envoyé en rafale avant queavgidle
ne retombe à 0. Augmentez-le pour être plus tolérant vis à vis des rafales de données. Vous ne pouvez pas configurermaxidle
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 deminburst
.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 queavgidle
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 queavgidle
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ètreallot
est l'unité de base de cette quantité. Voir le paramètreweight
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 à prendrerate/10
semble fonctionner correctement. Le paramètreweight
normalisé est multiplié par le paramètreallot
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ètreisolated
. 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 égalementborrow
, qui agit à l'inverse debounded
.
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 bounded
Cette 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 nœud est un nœud 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 nœud 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é.