logo
 Accueil  Articles  Cours  Guides  Formation  Téléchargement  Source
 
Contactmail
 Carnet de bord
 Notice légale
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 passante Page suivante Page précédente Table des matières

9. Gestionnaires de mise en file d'attente pour l'administration de la bande passante

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 :

 
mbps = 1024 kbps = 1024 * 1024 bps => byte/s (octets/s)
mbit = 1024 kbit => kilo bit/s.
mb = 1024 kb = 1024 * 1024 b => byte (octet)
mbit = 1024 kbit => kilo bit.
En interne, les nombres sont stockés en bps et b.

Mais tc utilise l'unité suivante lors de l'affichage des débits :

1Mbit = 1024 Kbit = 1024 * 1024 bps => bit/s


9.1 Explication des files d'attente et de la gestion de la mise en file d'attente

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.

9.2 Gestionnaires de mise en file d'attente simples, sans classes

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 :

   0     1     2     3     4     5     6     7
+-----+-----+-----+-----+-----+-----+-----+-----+
|                 |                       |     |
|   PRECEDENCE    |          TOS          | MBZ |
|                 |                       |     |
+-----+-----+-----+-----+-----+-----+-----+-----+



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 :

TOS     Bits  Signification                     Priorité Linux    Bande
------------------------------------------------------------------------
0x0     0     Service Normal                    0 Best Effort     1
0x2     1     Minimise le Coût Monétaire (mmc)  1 Filler          2
0x4     2     Maximalise la Fiabilité (mr)      0 Best Effort     1
0x6     3     mmc+mr                            0 Best Effort     1
0x8     4     Maximalise le Débit (mt)          2 Masse           2
0xa     5     mmc+mt                            2 Masse           2
0xc     6     mr+mt                             2 Masse           2
0xe     7     mmc+mr+mt                         2 Masse           2
0x10    8     Minimise le Délai (md)            6 Interactive     0
0x12    9     mmc+md                            6 Interactive     0
0x14    10    mr+md                             6 Interactive     0
0x16    11    mmc+mr+md                         6 Interactive     0
0x18    12    mt+md                             4 Int. Masse      1
0x1a    13    mmc+mt+md                         4 Int. Masse      1
0x1c    14    mr+mt+md                          4 Int. Masse      1
0x1e    15    mmc+mr+mt+md                      4 Int. Masse      1


[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 :

# tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540


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.

9.3 Conseils pour le choix de la file d'attente

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 !


9.4 Terminologie

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.

9.5 Gestionnaires de file d'attente basés sur les classes

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 :

                  racine 1:
                      |
                    _1:1_
                   /  |  \
                  /   |   \
                 /    |    \
               10:   11:   12:
              /   \       /   \
           10:1  10:2   12:1  12:2


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 ...

Configuration simple

Nous allons créer cet arbre :

     racine 1: prio
         /   |   \
       1:1  1:2  1:3
        |    |    |
       10:  20:  30:
       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.

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.

# 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: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.

# 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 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 !

# 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, 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 :

# 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 !

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.

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 '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 :

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 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 :

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.

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



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é. Puisque nous avons choisi SFQ en interne, on hérite naturellement de l'équité.

9.6 Classifier des paquets avec des filtres

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.

Réitérer l'arbre, qui n'est pas un arbre :

                    root 1:
                      |
                    _1:1_
                   /  |  \
                  /   |   \
                 /    |    \
               10:   11:   12:
              /   \       /   \
           10:1  10:2   12:1  12:2


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.


Page suivante Page précédente Table des matières
Dernière modification le : 4 March 2002 12:04
php logo    debian logo