| Historique des versions | ||
|---|---|---|
| Version $Revision: 1.1.1.1 $ | $Date: 2003/01/03 02:38:54 $ | |
| DocBook Edition | ||
Ce document est dédié à beaucoup de gens ; dans ma tentative de tous me les rappeler, je peux en citer quelques-uns :
Rusty Russell
Alexey N. Kuznetsov
La fine équipe de Google
L'équipe de Casema Internet
Bienvenue, cher lecteur.
Ce document a pour but de vous éclairer sur la manière de faire du routage avancé avec Linux 2.2/2.4. Méconnus par les utilisateurs, les outils standard de ces noyaux permettent de faire des choses spectaculaires. Les commandes comme route et ifconfig sont des interfaces vraiment pauvres par rapport à la grande puissance potentielle d'iproute2.
J'espère que ce HOWTO deviendra aussi lisible que ceux de Rusty Russell, très réputé (parmi d'autres choses) pour son netfilter.
Vous pouvez nous contacter en nous écrivant à l'équipe HOWTO. Cependant, postez, s'il vous plaît, vos questions sur la liste de diffusion (voir la section correspondante) pour celles qui ne sont pas directement liées à ce HOWTO.
Avant de vous perdre dans ce HOWTO, si la seule chose que vous souhaitez faire est de la simple mise en forme de trafic, allez directement au chapitre Autres possibilités, et lisez ce qui concerne CBQ.init.
Ce document est distribué dans l'espoir qu'il sera utile et utilisé, mais SANS AUCUNE GARANTIE ; sans même une garantie implicite de qualité légale et marchande ni aptitude à un quelconque usage.
En un mot, si votre dorsale STM-64 est tombée ou distribue de la pornographie à vos estimés clients, cela n'est pas de notre faute. Désolé.
Copyright (c) 2001 par Bert Hubert, Gregory Maxwell et Martijn van Oosterhout, Remco van Mook, Paul B. Schroeder et autres. Ce document ne peut être distribué qu'en respectant les termes et les conditions exposés dans la Open Publication License, v1.0 ou supérieure (la dernière version est actuellement disponible sur http://www.opencontent.org/openpub/).
Copiez et distribuez (vendez ou donnez) librement ce document, dans n'importe quel format. Les demandes de corrections et/ou de commentaires sont à adresser à la personne qui maintient ce document.
Il est aussi demandé que, si vous publiez cet HOWTO sur un support papier, vous en envoyiez des exemplaires aux auteurs pour une << relecture critique >> :-)
Comme le titre l'implique, ceci est un HOWTO << avancé >>. Bien qu'il ne soit pas besoin d'être un expert réseau, certains pré-requis sont nécessaires.
Voici d'autres références qui pourront vous aider à en apprendre plus :
Très bonne introduction, expliquant ce qu'est un réseau, et comment on le connecte à d'autres réseaux.
Excellent document, bien que très bavard. Il vous apprendra beaucoup de choses qui sont déjà configurées si vous êtes capable de vous connecter à Internet. Il peut éventuellement être situé à /usr/doc/HOWTO/NET-HOWTO.txt, mais peut également être trouvé en ligne
Une petite liste des choses qui sont possibles :
Limiter la bande passante pour certains ordinateurs
Limiter la bande passante VERS certains ordinateurs
Vous aider à partager équitablement votre bande passante
Protéger votre réseau des attaques de type Déni de Service
Protéger Internet de vos clients
Multiplexer plusieurs serveurs en un seul, pour l'équilibrage de charge ou une disponibilité améliorée
Restreindre l'accès à vos ordinateurs
Limiter l'accès de vos utilisateurs vers d'autres hôtes
Faire du routage basé sur l'ID utilisateur (eh oui !), l'adresse MAC, l'adresse IP source, le port, le type de service, l'heure ou le contenu.
Peu de personnes utilisent couramment ces fonctionnalités avancées. Il y a plusieurs raisons à cela. Bien que la documentation soit fournie, la prise en main est difficile. Les commandes de contrôle du trafic ne sont pratiquement pas documentées.
Il y a plusieurs choses qui doivent être notées au sujet de ce document. Bien que j'en ai écrit la majeure partie, je ne veux vraiment pas qu'il reste tel quel. Je crois beaucoup à l'Open Source, je vous encourage donc à envoyer des remarques, des mises à jour, des corrections, etc. N'hésitez pas à m'avertir des coquilles ou d'erreurs pures et simples. Si mon anglais vous paraît parfois peu naturel, ayez en tête, s'il vous plaît, que l'anglais n'est pas ma langue natale. N'hésitez pas à m'envoyer vos suggestions [NdT : en anglais !]
Si vous pensez que vous êtes plus qualifié que moi pour maintenir une section ou si vous pensez que vous pouvez écrire et maintenir de nouvelles sections, vous êtes le bienvenu. La version SGML de ce HOWTO est disponible via CVS. J'envisage que d'autre personnes puissent travailler dessus.
Pour vous aider, vous trouverez beaucoup de mentions FIXME (NdT : A CORRIGER). Les corrections sont toujours les bienvenues. Si vous trouvez une mention FIXME, vous saurez que vous êtes en territoire inconnu. Cela ne veut pas dire qu'il n'y a pas d'erreurs ailleurs, faites donc très attention. Si vous avez validé quelque chose, faites-nous le savoir, ce qui nous permettra de retirer la mention FIXME.
Je prendrai quelques libertés tout au long de cet HOWTO. Par exemple, je pars de l'hypothèse d'une connexion Internet à 10 Mbits, bien que je sache très bien que cela ne soit pas vraiment courant.
L'adresse canonique de cet HOWTO est Ici.
Nous avons maintenant un CVS en accès anonyme disponible depuis le monde entier. Cela est intéressant pour plusieurs raisons. Vous pouvez facilement télécharger les nouvelles versions de ce HOWTO et soumettre des mises à jour.
En outre, cela permet aux auteurs de travailler sur la source de façon indépendante, ce qui est une bonne chose aussi.
$ export CVSROOT=:pserver:anon@outpost.ds9a.nl:/var/cvsroot $ cvs login CVS password: [enter 'cvs' (sans les caractères ')] $ cvs co 2.4routing cvs server: Updating 2.4routing U 2.4routing/2.4routing.sgml |
Si vous repérez une erreur ou voulez ajouter quelque chose, faites le en local, exécutez cvs diff -u, et envoyez-nous le résultat.
Un fichier Makefile est fourni pour vous aider à créer des fichiers PostScript, dvi, pdf, html et texte. Vous pouvez avoir à installer les docbook, docbook-utils, ghostscript et tetex pour obtenir tous les formats de sortie.
Les auteurs reçoivent de plus en plus de courriers électroniques à propos de cet HOWTO. Vu l'intérêt de la communauté, il a été décidé la mise en place d'une liste de diffusion où les personnes pourront discuter du routage avancé et du contrôle de trafic. Vous pouvez vous abonner à la liste ici.
Il devra être noté que les auteurs sont très hésitants à répondre à des questions qui n'ont pas été posées sur la liste. Nous aimerions que la liste devienne une sorte de base de connaissance. Si vous avez une question, recherchez, s'il vous plaît, d'abord dans l'archive, et ensuite postez-là dans la liste de diffusion.
Nous allons essayer de faire des manipulations intéressantes dès le début, ce qui veut dire que tout ne sera pas expliqué en détail tout de suite. Veuillez passer sur ces détails, et accepter de considérer qu'ils deviendront clairs par la suite.
Le routage et le filtrage sont deux choses distinctes. Le filtrage est très bien documenté dans le HOWTO de Rusty, disponible ici :
Nous nous focaliserons principalement sur ce qu'il est possible de faire en combinant netfilter et iproute2.
La plupart des distributions Linux et des UNIX utilisent couramment les vénérables commandes arp, ifconfig et route. Bien que ces outils fonctionnent, ils montrent quelques comportements inattendus avec les noyaux Linux des séries 2.2 et plus. Par exemple, les tunnels GRE font partie intégrante du routage de nos jours, mais ils nécessitent des outils complètement différents.
Avec iproute2, les tunnels font partie intégrante des outils.
Les noyaux Linux des séries 2.2 et plus ont un sous-système réseau complètement réécrit. Ce nouveau codage de la partie réseau apporte à Linux des performances et des fonctionnalités qui n'ont pratiquement pas d'équivalent parmi les autres systèmes d'exploitation. En fait, le nouveau logiciel de filtrage, routage et de classification possède plus de fonctionnalités que les logiciels fournis sur beaucoup de routeurs dédiés, de pare-feu et de produits de mise en forme (shaping) du trafic.
Dans les systèmes d'exploitation existants, au fur et à mesure que de nouveaux concepts réseau apparaissaient, les développeurs sont parvenus à les greffer sur les structures existantes. Ce travail constant d'empilage de couches a conduit à des codes réseau aux comportements étranges, un peu comme les langues humaines. Dans le passé, Linux émulait le mode de fonctionnement de SunOS, ce qui n'était pas l'idéal.
La nouvelle structure d'iproute2 a permis de formuler clairement des fonctionnalités impossibles à implémenter dans le sous-système réseau précédent.
Linux possède un système sophistiqué d'allocation de bande passante appelé Contrôle de trafic (Traffic Control). Ce système supporte différentes méthodes pour classer, ranger par ordre de priorité, partager et limiter le trafic entrant et sortant.
Nous commencerons par un petit tour d'horizon des possibilités d'iproute2.
Vous devez être sûr que vous avez installé les outils utilisateur (NdT : userland tools, par opposition à la partie << noyau >> d'iproute2). Le paquet concerné s'appelle iproute sur RedHat et Debian. Autrement, il peut être trouvé à ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss??????.tar.gz.
Vous pouvez aussi essayer iproute2-current.tar.gz pour la dernière version.
Certains éléments d'iproute vous imposent l'activation de certaines options du noyau. Il devra également être noté que toutes les versions de RedHat jusqu'à la version 6.2 incluse n'ont pas les fonctionnalités du contrôle de trafic dans le noyau par défaut.
RedHat 7.2 contient tous les éléments par défaut.
Soyez également sûr que vous avez le support netlink, même si vous devez choisir de compiler votre propre noyau ; iproute2 en a besoin.
Cela peut vous paraître surprenant, mais iproute2 est déjà configuré ! Les commandes courantes ifconfig et route utilisent déjà les appels système avancés d'iproute2, mais essentiellement avec les options par défaut (c'est-à-dire ennuyeuses).
L'outil ip est central, et nous allons lui demander de nous montrer les interfaces.
[ahu@home ahu]$ ip link list
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
link/ppp |
La sortie peut varier, mais voici ce qui est affiché pour mon routeur NAT (NdT : translation d'adresse) chez moi. J'expliquerai seulement une partie de la sortie, dans la mesure où tout n'est pas directement pertinent.
La première interface que nous voyons est l'interface loopback. Bien que votre ordinateur puisse fonctionner sans, je vous le déconseille. La taille de MTU (unité maximum de transmission) est de 3924 octets, et loopback n'est pas supposé être mis en file d'attente, ce qui prend tout son sens dans la mesure où cette interface est le fruit de l'imagination de votre noyau.
Je vais passer sur l'interface dummy pour l'instant, et il se peut qu'elle ne soit pas présente sur votre ordinateur. Il y a ensuite mes deux interfaces physiques, l'une du côté de mon modem câble, l'autre servant mon segment ethernet à la maison. De plus, nous voyons une interface ppp0.
Notons l'absence d'adresses IP. Iproute déconnecte les concepts de << liens >> et << d'adresses IP >>. Avec l'IP aliasing, le concept de l'adresse IP canonique est devenu, de toute façon, sans signification.
ip nous montre bien, cependant, l'adresse MAC, l'identifiant matériel de nos interfaces ethernet.
[ahu@home ahu]$ ip address show
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
link/ppp
inet 212.64.94.251 peer 212.64.94.1/32 scope global ppp0 |
Cela contient plus d'informations : ip montre toutes nos adresses, et à quelles cartes elles appartiennent. inet signifie Internet (IPv4). Il y a beaucoup d'autres familles d'adresses, mais elles ne nous concernent pas pour le moment.
Examinons l'interface eth0 de plus près. Il est dit qu'elle est reliée à l'adresse internet 10.0.0.1/8. Qu'est-ce que cela signifie ? Le /8 désigne le nombre de bits réservés à l'adresse réseau. Il y a 32 bits, donc il reste 24 bits pour désigner une partie de notre réseau. Les 8 premiers bits de 10.0.0.1 correspondent à 10.0.0.0, notre adresse réseau, et notre masque de sous-réseau est 255.0.0.0.
Les autres bits repèrent des machines directement connectées à cette interface. Donc, 10.250.3.13 est directement disponible sur eth0, comme l'est 10.0.0.1 dans notre exemple.
Avec ppp0, le même concept existe, bien que les nombres soient différents. Son adresse est 212.64.94.251, sans masque de sous-réseau. Cela signifie que vous avez une liaison point à point et que toutes les adresses, à l'exception de 212.64.94.251, sont distantes. Il y a cependant plus d'informations. En effet, on nous dit que de l'autre côté du lien, il n'y a encore qu'une seule adresse, 212.64.94.1. Le /32 nous précise qu'il n'y a pas de << bits réseau >>.
Il est absolument vital que vous compreniez ces concepts. Référez-vous à la documentation mentionnée au début de ce HOWTO si vous avez des doutes.
Vous pouvez aussi noter qdisc, qui désigne la gestion de la mise en file d'attente (Queueing Discipline). Cela deviendra vital plus tard.
Nous savons maintenant comment trouver les adresses 10.x.y.z, et nous sommes capables d'atteindre 212.64.94.1. Cela n'est cependant pas suffisant, et nous avons besoin d'instructions pour atteindre le monde. L'Internet est disponible via notre connexion PPP, et il se trouve que 212.64.94.1 est prêt à propager nos paquets à travers le monde, et à nous renvoyer le résultat.
[ahu@home ahu]$ ip route show 212.64.94.1 dev ppp0 proto kernel scope link src 212.64.94.251 10.0.0.0/8 dev eth0 proto kernel scope link src 10.0.0.1 127.0.0.0/8 dev lo scope link default via 212.64.94.1 dev ppp0 |
Cela se comprend de soi-même. Les 4 premières lignes donnent explicitement ce qui était sous-entendu par ip address show, la dernière ligne nous indiquant que le reste du monde peut être trouvé via 212.64.94.1, notre passerelle par défaut. Nous pouvons voir que c'est une passerelle à cause du mot << via >>, qui nous indique que nous avons besoin d'envoyer les paquets vers 212.64.94.1, et que c'est elle qui se chargera de tout.
En référence, voici ce que l'ancien utilitaire route nous propose :
[ahu@home ahu]$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 212.64.94.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0 10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 eth0 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo 0.0.0.0 212.64.94.1 0.0.0.0 UG 0 0 0 ppp0 |
ARP est le Protocole de Résolution d'Adresse (Address Resolution Protocol). Il est décrit dans le RFC 826. ARP est utilisé par une machine d'un réseau local pour retrouver l'adresse matérielle (la localisation) d'une autre machine sur le même réseau. Les machines sur Internet sont généralement connues par leur nom auquel correspond une adresse IP. C'est ainsi qu'une machine sur le réseau foo.com est capable de communiquer avec une autre machine qui est sur le réseau bar.net. Une adresse IP, cependant, ne peut pas vous indiquer la localisation physique de la machine. C'est ici que le protocole ARP entre en jeu.
Prenons un exemple très simple. Supposons que j'aie un réseau composé de plusieurs machines, dont la machine foo d'adresse IP 10.0.0.1 et la machine bar qui a l'adresse IP 10.0.0.2. Maintenant, foo veut envoyer un ping vers bar pour voir s'il est actif, mais foo n'a aucune indication sur la localisation de bar. Donc, si foo décide d'envoyer un ping vers bar, il a besoin d'envoyer une requête ARP. Cette requête ARP est une façon pour foo de crier sur le réseau << Bar (10.0.0.2) ! Où es-tu ? >>. Par conséquent, toutes les machines sur le réseau entendront foo crier, mais seul bar (10.0.0.2) répondra. Bar enverra une réponse ARP directement à foo ; ce qui revient à dire : << Foo (10.0.0.1) ! je suis ici, à l'adresse 00:60:94:E:08:12 >>. Après cette simple transaction utilisée pour localiser son ami sur le réseau, foo est capable de communiquer avec bar jusqu'à ce qu'il (le cache ARP de foo) oublie où bar est situé (typiquement au bout de 15 minutes sur Unix).
Maintenant, voyons comment cela fonctionne. Vous pouvez consulter votre cache (table) ARP (neighbor) comme ceci :
[root@espa041 /home/src/iputils]# ip neigh show 9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable 9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable |
Comme vous pouvez le voir, ma machine espa041 (9.3.76.41) sait où trouver espa042 (9.3.76.42) et espagate (9.3.76.1). Maintenant, ajoutons une autre machine dans le cache ARP.
[root@espa041 /home/paulsch/.gnome-desktop]# ping -c 1 espa043 PING espa043.austin.ibm.com (9.3.76.43) from 9.3.76.41 : 56(84) bytes of data. 64 bytes from 9.3.76.43: icmp_seq=0 ttl=255 time=0.9 ms 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max = 0.9/0.9/0.9 ms [root@espa041 /home/src/iputils]# ip neigh show 9.3.76.43 dev eth0 lladdr 00:06:29:21:80:20 nud reachable 9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable 9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable |
Par conséquent, lorsque espa041 a essayé de contacter espa043, l'adresse matérielle de espa043 (sa localisation) a alors été ajoutée dans le cache ARP. Donc, tant que la durée de vie de l'entrée correspondant à espa043 dans le cache ARP n'est pas dépassée, espa041 sait localiser espa043 et n'a plus besoin d'envoyer de requête ARP.
Maintenant, effaçons espa043 de notre cache ARP.
[root@espa041 /home/src/iputils]# ip neigh delete 9.3.76.43 dev eth0 [root@espa041 /home/src/iputils]# ip neigh show 9.3.76.43 dev eth0 nud failed 9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable 9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud stale |
Maintenant, espa041 a à nouveau oublié la localisation d'espa043 et aura besoin d'envoyer une autre requête ARP la prochaine fois qu'il voudra communiquer avec lui. Vous pouvez aussi voir ci-dessus que l'état d'espagate (9.3.76.1) est passé en stale. Cela signifie que la localisation connue est encore valide, mais qu'elle devra être confirmée à la première transaction avec cette machine.
Si vous avez un routeur important, il se peut que vous vouliez satisfaire les besoins de différentes personnes, qui peuvent être traitées différemment. Les bases de données des politiques de routage vous aident à faire cela, en gérant plusieurs ensembles de tables de routage.
Si vous voulez utiliser cette fonctionnalité, assurez-vous que le noyau est compilé avec les options IP : Advanced router et IP : policy routing.
Quand le noyau doit prendre une décision de routage, il recherche quelle table consulter. Par défaut, il y a trois tables. L'ancien outil route modifie les tables principale (main) et locale (local), comme le fait l'outil ip (par défaut).
Les règles par défaut :
[ahu@home ahu]$ ip rule list 0: from all lookup local 32766: from all lookup main 32767: from all lookup default |
Ceci liste la priorité de toutes les règles. Nous voyons que toutes les règles sont appliquées à tous les paquets (from all). Nous avons vu la table main précédemment, sa sortie s'effectuant avec ip route ls, mais les tables local et default sont nouvelles.
Si nous voulons faire des choses fantaisistes, nous pouvons créer des règles qui pointent vers des tables différentes et qui nous permettent de redéfinir les règles de routage du système.
Pour savoir exactement ce que fait le noyau en présence d'un assortiment de règles plus complet, référez-vous à la documentation ip-cref d'Alexey [NdT : dans le paquetage iproute2 de votre distribution].
Prenons encore une fois un exemple réel. J'ai 2 modems câble, connectés à un routeur Linux NAT (masquerading). Les personnes habitant avec moi me paient pour avoir accès à Internet. Supposons qu'un de mes co-locataires consulte seulement hotmail et veuille payer moins. C'est d'accord pour moi, mais il utilisera le modem le plus lent.
Le modem câble << rapide >> est connu sous 212.64.94.251 et est en liaison PPP avec 212.64.94.1. Le modem câble << lent >> est connu sous diverses adresses IP : 212.64.78.148 dans notre exemple avec un lien vers 195.96.98.253.
La table locale :
[ahu@home ahu]$ ip route list table local broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 local 10.0.0.1 dev eth0 proto kernel scope host src 10.0.0.1 broadcast 10.0.0.0 dev eth0 proto kernel scope link src 10.0.0.1 local 212.64.94.251 dev ppp0 proto kernel scope host src 212.64.94.251 broadcast 10.255.255.255 dev eth0 proto kernel scope link src 10.0.0.1 broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 local 212.64.78.148 dev ppp2 proto kernel scope host src 212.64.78.148 local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1 |
Il y a beaucoup de choses évidentes, mais aussi des choses qui ont besoin d'être précisées quelque peu, ce que nous allons faire. La table de routage par défaut est vide.
Regardons la table principale (main) :
[ahu@home ahu]$ ip route list table main 195.96.98.253 dev ppp2 proto kernel scope link src 212.64.78.148 212.64.94.1 dev ppp0 proto kernel scope link src 212.64.94.251 10.0.0.0/8 dev eth0 proto kernel scope link src 10.0.0.1 127.0.0.0/8 dev lo scope link default via 212.64.94.1 dev ppp0 |
Maintenant, nous générons une nouvelle règle que nous appellerons John, pour notre hypothétique co-locataire. Bien que nous puissions travailler avec des nombres IP purs, il est plus facile d'ajouter notre table dans le fichier /etc/iproute2/rt_tables.
# echo 200 John >> /etc/iproute2/rt_tables # ip rule add from 10.0.0.10 table John # ip rule ls 0: from all lookup local 32765: from 10.0.0.10 lookup John 32766: from all lookup main 32767: from all lookup default |
Maintenant, tout ce qu'il reste à faire est de générer la table John, et de vider le cache des routes :
# ip route add default via 195.96.98.253 dev ppp2 table John # ip route flush cache |
Et voilà qui est fait. Il ne reste plus, comme exercice laissé au lecteur, qu'à implémenter cela dans ip-up.
Il y a trois sortes de tunnels sous Linux : l'IP dans un tunnel IP, le tunnel GRE et les tunnels qui existent en dehors du noyau (comme PPTP, par exemple).
Les tunnels peuvent faire des choses très inhabituelles et vraiment sympas. Ils peuvent aussi absolument tout détraquer si vous ne les avez pas configurés correctement. Ne définissez pas votre route par défaut sur un tunnel, à moins que vous ne sachiez EXACTEMENT ce que vous faites.
De plus, le passage par un tunnel augmente le poids des en-têtes (overhead), puisqu'un en-tête IP supplémentaire est nécessaire. Typiquement, ce surcoût est de 20 octets par paquet. Donc, si la taille maximum de votre paquet sur votre réseau (MTU) est de 1500 octets, un paquet qui est envoyé à travers un tunnel sera limité à une taille de 1480 octets. Ce n'est pas nécessairement un problème, mais soyez sûr d'avoir bien étudié la fragmentation et le réassemblage des paquets IP quand vous prévoyez de relier des réseaux de grande taille par des tunnels. Et bien sûr, la manière la plus rapide de creuser un tunnel est de creuser des deux côtés.
Ce type de tunnel est disponible dans Linux depuis un long moment. Il nécessite deux modules, ipip.o et new_tunnel.o.
Disons que vous avez trois réseaux : 2 réseaux internes A et B, et un réseau intermédiaire C (ou disons Internet). Les caractéristiques du réseau A sont :
réseau 10.0.1.0 masque de sous-réseau 255.255.255.0 routeur 10.0.1.1 |
Le routeur a l'adresse 172.16.17.18 sur le réseau C.
et le réseau B :
réseau 10.0.2.0 masque de sous-réseau 255.255.255.0 routeur 10.0.2.1 |
Le routeur a l'adresse 172.19.20.21 sur le réseau C.
En ce qui concerne le réseau C, nous supposerons qu'il transmettra n'importe quel paquet de A vers B et vice-versa. Il est également possible d'utiliser l'Internet pour cela.
Voici ce qu'il faut faire :
Premièrement, assurez-vous que les modules soient installés :
insmod ipip.o insmod new_tunnel.o |
Ensuite, sur le routeur du réseau A, faites la chose suivante :
ifconfig tunl0 10.0.1.1 pointopoint 172.19.20.21 route add -net 10.0.2.0 netmask 255.255.255.0 dev tunl0 |
et sur le routeur du réseau B :
ifconfig tunl0 10.0.2.1 pointopoint 172.16.17.18 route add -net 10.0.1.0 netmask 255.255.255.0 dev tunl0 |
Et quand vous aurez terminé avec votre tunnel :
ifconfig tunl0 down |
Vite fait, bien fait. Vous ne pouvez pas transmettre les paquets de diffusion (broadcast), ni le trafic IPv6 à travers un tunnel IP-IP. Vous ne pouvez connecter que deux réseaux IPv4 qui, normalement, ne seraient pas capables de se << parler >>, c'est tout. Dans la mesure où la compatibilité a été conservée, ce code tourne depuis un bon moment, et il reste compatible depuis les noyaux 1.3. Le tunnel Linux IP dans IP ne fonctionne pas avec d'autres systèmes d'exploitation ou routeurs, pour autant que je sache. C'est simple, ça marche. Utilisez-le si vous le pouvez, autrement utilisez GRE.
GRE est un protocole de tunnel qui a été à l'origine développé par Cisco, et qui peut réaliser plus de choses que le tunnel IP dans IP. Par exemple, vous pouvez aussi transporter du trafic multi-diffusion (multicast) et de l'IPv6 à travers un tunnel GRE.
Dans Linux, vous aurez besoin du module ip_gre.o.
Dans un premier temps, intéressons-nous au tunnel IPv4 :
Disons que vous avez trois réseaux : 2 réseaux internes A et B, et un réseau intermédiaire C (ou disons internet).
Les caractéristiques du réseau A sont :
réseau 10.0.1.0 masque de sous-réseau 255.255.255.0 routeur 10.0.1.1 |
Le routeur a l'adresse 172.16.17.18 sur le réseau C. Appelons ce réseau neta.
Et pour le réseau B :
réseau 10.0.2.0 masque de sous-réseau 255.255.255.0 routeur 10.0.2.1 |
Le routeur a l'adresse 172.19.20.21 sur le réseau C. Appelons ce réseau netb.
En ce qui concerne le réseau C, nous supposerons qu'il transmettra n'importe quels paquets de A vers B et vice-versa. Comment et pourquoi, on s'en moque.
Sur le routeur du réseau A, nous faisons la chose suivante :
ip tunnel add netb mode gre remote 172.19.20.21 local 172.16.17.18 ttl 255 ip link set netb up ip addr add 10.0.1.1 dev netb ip route add 10.0.2.0/24 dev netb |
Discutons un peu de cela. Sur la ligne 1, nous avons ajouté un périphérique tunnel, que nous avons appelé netb (ce qui est évident, dans la mesure où c'est là que nous voulons aller). De plus, nous lui avons dit d'utiliser le protocole GRE (mode gre), que l'adresse distante est 172.19.20.21 (le routeur de l'autre côté), que nos paquets << tunnelés >> devront être générés à partir de 172.16.17.18 (ce qui autorise votre serveur à avoir plusieurs adresses IP sur le réseau C et ainsi vous permet de choisir laquelle sera utilisée pour votre tunnel) et que le champ TTL de vos paquets sera fixé à 255 (ttl 255).
La deuxième ligne active le périphérique.
Sur la troisième ligne, nous avons donné à cette nouvelle interface l'adresse 10.0.1.1. C'est bon pour de petits réseaux, mais quand vous commencez une exploitation minière (BEAUCOUP de tunnels !), vous pouvez utiliser une autre gamme d'adresses IP pour vos interfaces << tunnel >> (dans cet exemple, vous pourriez utiliser 10.0.3.0).
Sur la quatrième ligne, nous positionnons une route pour le réseau B. Notez la notation différente pour le masque de sous-réseau. Si vous n'êtes pas familiarisé avec cette notation, voici comment ça marche : vous écrivez le masque de sous-réseau sous sa forme binaire, et vous comptez tous les 1. Si vous ne savez pas comment faire cela, rappelez-vous juste que 255.0.0.0 est /8, 255.255.0.0 est /16 et 255.255.255.0 est /24. Et 255.255.254.0 est /23, au cas où ça vous intéresserait.
Mais arrêtons ici, et continuons avec le routeur du réseau B.
ip tunnel add neta mode gre remote 172.16.17.18 local 172.19.20.21 ttl 255 ip link set neta up ip addr add 10.0.2.1 dev neta ip route add 10.0.1.0/24 dev neta |
Et quand vous voudrez retirer le tunnel sur le routeur A :
ip link set netb down ip tunnel del netb |
Bien sûr, vous pouvez remplacer netb par neta pour le routeur B.
Voir la section 6 pour une courte description des adresses IPv6.
À propos des tunnels.
Supposons que vous ayez le réseau IPv6 suivant, et que vous vouliez le connecter à une dorsale IPv6 (6bone) ou à un ami.
Réseau 3ffe:406:5:1:5:a:2:1/96 |
ip tunnel add sixbone mode sit remote 172.22.23.24 local 172.16.17.18 ttl 255 ip link set sixbone up ip addr add 3ffe:406:5:1:5:a:2:1/96 dev sixbone ip route add 3ffe::/15 dev sixbone |
Voyons cela de plus près. Sur la première ligne, nous avons créé un périphérique tunnel appelé sixbone. Nous lui avons affecté le mode sit (qui est le tunnel IPv6 sur IPv4) et lui avons dit où l'on va (remote) et d'où l'on vient (local). TTL est configuré à son maximum : 255. Ensuite, nous avons rendu le périphérique actif (up). Puis, nous avons ajouté notre propre adresse réseau et configuré une route pour 3ffe::/15 à travers le tunnel.
Les tunnels GRE constituent actuellement le type de tunnel préféré. C'est un standard qui est largement adopté, même à l'extérieur de la communauté Linux, ce qui constitue une bonne raison de l'utiliser.
Il y a des dizaines d'implémentations de tunnels à l'extérieur du noyau. Les plus connues sont bien sûr PPP et PPTP, mais il y en a bien plus (certaines propriétaires, certaines sécurisés, d'autres qui n'utilisent pas IP), qui dépassent le cadre de ce HOWTO.
Par Marco Davids <marco@sara.nl>
NOTE au mainteneur :
En ce qui me concerne, ce tunnel IPv6-IPv4 n'est pas, par définition, un tunnel GRE. Vous pouvez réaliser un tunnel IPv6 sur IPv4 au moyen des périphériques tunnels GRE (tunnels GRE N'IMPORTE QUOI vers IPv4), mais le périphérique utilisé ici (sit) ne permet que des tunnels IPv6 sur IPv4, ce qui est quelque chose de différent.
Voici une autre application des possibilités de tunnels de Linux. Celle-ci est populaire parmi les premiers adeptes d'IPv6 ou les pionniers si vous préférez. L'exemple pratique décrit ci-dessous n'est certainement pas la seule manière de réaliser un tunnel IPv6. Cependant, c'est la méthode qui est souvent utilisée pour réaliser un tunnel entre Linux et un routeur Cisco IPv6 et l'expérience m'a appris que c'est ce type d'équipement que beaucoup de personnes ont. Dix contre un que ceci s'appliquera aussi pour vous ;-).
De petites choses à propos des adresses IPv6 :
Les adresses IPv6 sont, en comparaison avec les adresses IPv4, vraiment grandes : 128 bits contre 32 bits. Et ceci nous fournit la chose dont nous avons besoin : beaucoup, beaucoup d'adresses IP : 340,282,266,920,938,463,463,374,607,431,768,211,465 pour être précis. A part ceci, IPv6 (ou IPng génération suivante (Next Generation)) est supposé fournir des tables de routage plus petites sur les routeurs des dorsales Internet, une configuration plus simple des équipements, une meilleure sécurité au niveau IP et un meilleur support pour la Qualité de Service (QoS).
Un exemple : 2002:836b:9820:0000:0000:0000:836b:9886
Ecrire les adresses IPv6 peut être un peu lourd. Il existe donc des règles qui rendent la vie plus facile :
Ne pas utiliser les zéros de tête, comme dans IPv4 ;
Utiliser des double-points de séparation tous les 16 bits ou 2 octets ;
Quand vous avez beaucoup de zéros consécutifs, vous pouvez écrire ::. Vous ne pouvez, cependant, faire cela qu'une seule fois par adresse et seulement pour une longueur de 16 bits.
L'adresse 2002:836b:9820:0000:0000:0000:836b:9886 peut être écrite 2002:836b:9820::836b:9886, ce qui est plus amical.
Un autre exemple : l'adresse 3ffe:0000:0000:0000:0000:0000:34A1:F32C peut être écrite 3ffe::20:34A1:F32C, ce qui est beaucoup plus court.
IPv6 a pour but d'être le successeur de l'actuel IPv4. Dans la mesure où cette technologie est relativement récente, il n'y a pas encore de réseau natif IPv6 à l'échelle mondiale. Pour permettre un développement rapide, la dorsale IPv6 (6bone) a été introduite.
Les réseaux natifs IPv6 sont interconnectés grâce à l'encapsulation du protocole IPv6 dans des paquets IPv4, qui sont envoyés à travers l'infrastructure IPv4 existante, d'un site IPv6 à un autre.
C'est dans cette situation que l'on monte un tunnel.
Pour être capable d'utiliser IPv6, vous devrez avoir un noyau qui le supporte. Il y a beaucoup de bons documents qui expliquent la manière de réaliser cela. Mais, tout se résume à quelques étapes :
Récupérer une distribution Linux récente, avec une glibc convenable.
Récupérer alors les sources à jour du noyau.
Aller dans /usr/src/linux et tapez :
make menuconfig
Choisir Networking Options
Sélectionner The IPv6 protocol, IPv6: enable EUI-64 token format, IPv6: disable provider based addresses
ASTUCE :Ne compiler pas ces options en tant que module. Ceci ne marchera souvent pas bien.
En d'autres termes, compilez IPv6 directement dans votre noyau. Vous pouvez alors sauvegarder votre configuration comme d'habitude et entreprendre la compilation de votre noyau.
ASTUCE: Avant de faire cela, modifier votre Makefile comme suit : EXTRAVERSION = -x ; --> ; EXTRAVERSION = -x-IPv6
Il y a beaucoup de bonnes documentations sur la compilation et l'installation d'un noyau. Cependant, ce document ne traite pas de ce sujet. Si vous rencontrez des problèmes à ce niveau, allez et recherchez dans la documentation des renseignements sur la compilation du noyau Linux correspondant à vos propres spécifications.
Le fichier /usr/src/linux/README peut constituer un bon départ. Après avoir réalisé tout ceci, et redémarré avec votre nouveau noyau flambant neuf, vous pouvez lancer la commande /sbin/ifconfig -a et noter un nouveau périphérique sit0. SIT signifie Transition Simple d'Internet (Simple Internet Transition). Vous pouvez vous auto-complimenter : vous avez maintenant franchi une étape importante vers IP, la prochaine génération ;-)
Passons maintenant à l'étape suivante. Vous voulez connecter votre hôte ou peut-être même tout votre réseau LAN à d'autres réseaux IPv6. Cela pourrait être la dorsale IPv6 << 6bone >> qui a été spécialement mise en place dans ce but particulier.
Supposons que vous avez le réseau IPv6 suivant : 3ffe:604:6:8::/64 et que vous vouliez le connecter à une dorsale IPv6 ou à un ami. Notez, s'il vous plaît, que la notation sous-réseau /64 est similaire à celle des adresses IPv4.
Votre adresse IPv4 est 145.100.24.181 et le routeur 6bone a l'adresse IPv4 145.100.1.5.
# ip tunnel add sixbone mode sit remote 145.100.1.5 [local 145.100.24.181 ttl 225] # ip link set sixbone up # ip addr add 3FFE:604:6:7::2/96 dev sixbone # ip route add 3ffe::0/15 dev sixbone |
Discutons de ceci. Dans la première ligne, nous avons créé un périphérique appelé sixbone. Nous lui avons donné l'attribut sit (mode sit) (qui est le tunnel IPv6 dans IPv4) et nous lui avons dit où aller (remote) et d'où nous venions (local). TTL est configuré à son maximum, 255.
Ensuite, nous avons rendu le périphérique actif (up). Après cela, nous avons ajouté notre propre adresse réseau et configuré une route pour 3ffe::/15 (qui est actuellement la totalité du 6bone) à travers le tunnel. Si la machine sur laquelle vous mettez en place tout ceci est votre passerelle IPv6, ajoutez alors les lignes suivantes :
# echo 1 >/proc/sys/net/ipv6/conf/all/forwarding # /usr/local/sbin/radvd |
En dernière instruction, radvd est un démon d'annonce comme zebra qui permet de supporter les fonctionnalités d'autoconfiguration d'IPv6. Recherchez le avec votre moteur de recherche favori. Vous pouvez vérifier les choses comme ceci :
# /sbin/ip -f inet6 addr |
Si vous arrivez à avoir radvd tournant sur votre passerelle IPv6 et que vous démarrez une machine avec IPv6 sur votre réseau local, vous serez ravi de voir les bénéfices de l'autoconfiguration IPv6 :
# /sbin/ip -f inet6 addr 1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue inet6 ::1/128 scope host 3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100 inet6 3ffe:604:6:8:5054:4cff:fe01:e3d6/64 scope global dynamic valid_lft forever preferred_lft 604646sec inet6 fe80::5054:4cff:fe01:e3d6/10 scope link |
Vous pouvez maintenant configurer votre serveur de noms pour les adresses IPv6. Le type A a un équivalent pour IPv6 : AAAA. L'équivalent de in-addr.arpa est : ip6.int. Il y a beaucoup d'informations disponibles sur ce sujet.
Il y a un nombre croissant d'applications IPv6 disponibles, comme le shell sécurisé, telnet, inetd, le navigateur Mozilla, le serveur web Apache et beaucoup d'autres. Mais ceci est en dehors du sujet de ce document de routage ;-).
Du côté Cisco, la configuration ressemblera à ceci :
! interface Tunnel1 description IPv6 tunnel no ip address no ip directed-broadcast ipv6 enable ipv6 address 3FFE:604:6:7::1/96 tunnel source Serial0 tunnel destination 145.100.24.181 tunnel mode ipv6ip ! ipv6 route 3FFE:604:6:8::/64 Tunnel1 |
Si vous n'avez pas un Cisco à votre disposition, essayez un des prestataires de tunnel IPv6 disponible sur Internet. Ils sont prêts à configurer leur Cisco avec un tunnel supplémentaire pour vous, le plus souvent au moyen d'une agréable interface web. Cherchez ipv6 tunnel broker avec votre moteur de recherche favori.
FIXME: Pas de rédacteur. En attendant, voir: Le projet FreeS/WAN. Cerberus du NIST est une autre implémentation de IPSec pour Linux. Cependant, leurs pages web n'ont pas été mis à jour depuis plus d'un an et leur version a tendance à être très nettement à la traîne par rapport aux dernières versions du noyau. USAGI, une implémentation alternative d'IPv6 pour Linux, inclue également une partie IPSec, mais qui n'est que pour IPv6.
FIXME: Pas de rédacteur !
Le Multicast-HOWTO est (relativement) ancien. De ce fait, il peut être imprécis ou induire en erreur à certains endroits.
Avant que vous ne puissiez faire du routage multidistribution, le noyau Linux a besoin d'être configuré pour supporter le type de routage multidistribution que vous voulez faire. Ceci, à son tour, exige une décision quant au choix du protocole de routage multidistribution que vous vous préparez à utiliser. Il y a essentiellement quatre types << communs >> de protocoles : DVMRP (la version multidistribution du protocole RIP unicast), MOSPF (la même chose, mais pour OSPF), PIM-SM (Protocol Independant Multicasting - Sparse Mode) qui suppose que les utilisateurs de n'importe quel groupe de multidistribution sont dispersés plutôt que regroupés) et PIM-DM (le même, mais Dense Mode) qui suppose qu'il y aura un regroupement significatif des utilisateurs d'un même groupe de multidistribution.
On pourra noter que ces options n'apparaissent pas dans le noyau Linux. Ceci s'explique par le fait que le protocole lui-même est géré par une application de routage, comme Zebra, mrouted ou pind. Cependant, vous devez avoir une bonne idée de ce que vous allez utiliser, de manière à sélectionner les bonnes options dans le noyau.
Pour tout routage multidistribution, vous avez forcément besoin de sélectionner les options multicasting et multicasting routing. Ceci est suffisant pour DVMRP et MOSPF. Dans le cas de PIM, vous devez également valider les options PIMv1 ou PIMv2 suivant que le réseau que vous connectez utilise la version 1 ou 2 du protocole PIM.
Une fois que tout cela a été réalisé, et que votre nouveau noyau a été compilé, vous verrez au démarrage que IGMP est inclus dans la liste des protocoles IP. Celui-ci est un protocole permettant de gérer les groupes multidistribution. Au moment de la rédaction, Linux ne supportait que les versions 1 et 2 de IGMP, bien que la version 3 existe et ait été documentée. Ceci ne va pas vraiment nous affecter dans la mesure où IGMPv3 est encore trop récent pour que ses fonctionnalités supplémentaires soient largement utilisées. Puisque IGMP s'occupe des groupes, seules les fonctionnalités présentes dans la plus simple version de IGMP gérant un groupe entier seront utilisées. IGMPv2 sera utilisé dans la plupart des cas, bien que IGMPv1 puisse encore être rencontré.
Jusque-là, c'est bon. Nous avons activé la multidistribution. Nous devons dire au noyau de l'utiliser concrètement. Nous allons donc démarrer le routage. Ceci signifie que nous ajoutons un réseau virtuel de multidistribution à la table du routeur :
ip route add 224.0.0.0/4 dev eth0 |
(En supposant bien sûr, que vous diffusez à travers eth0 ! Remplacez-le par le périphérique de votre choix, si nécessaire.)
Maintenant, dire à Linux de transmettre les paquets...
echo 1 > /proc/sys/net/ipv4/ip_forward |
Arrivé ici, il se peut que vous vous demandiez si ceci va faire quelque chose. Donc, pour tester notre connexion, nous pinguons le groupe par défaut, 224.0.0.1, pour voir si des machines sont présentes. Toutes les machines du réseau local avec la multidistribution activée DEVRAIENT répondre, et aucune autre. Vous remarquerez qu'aucune des machines qui répondent ne le fait avec l'adresse IP 224.0.0.1. Quelle surprise ! :) Ceci est une adresse de groupe (une << diffusion >> pour les abonnés) et tous les membres du groupe répondront avec leur propre adresse, et non celle du groupe.
ping -c 2 224.0.0.1 |
Maintenant, vous êtes prêt à faire du vrai routage multidistribution. Bien, en supposant que vous ayez deux réseaux à router l'un vers l'autre.
(A continuer !)
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. |
Mais tc utilise l'unité suivante lors de l'affichage des débits :
1Mbit = 1024 Kbit = 1024 * 1024 bps => bit/s |
Avec la mise en file d'attente, nous déterminons la manière dont les données sont ENVOYEES. 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 sur 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'envoyez 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, c'est facilement réalisable.
Comme nous l'avons déjà dit, la gestion de mise en file d'attente permet de modifier la façon dont les données sont envoyées. Les gestionnaires de mise en file d'attente sans classes sont ceux qui, en gros, acceptent les données et qui ne font que les réordonner, 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.
Cette file d'attente, comme son nom l'indique : premier entré, premier sorti (First In First Out), 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ède pas de classes et vous ne pourrez pas y ajouter de nouveaux gestionnaires avec la commande tc.
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 :
Détermine comment les priorités des paquets sont reliées aux bandes, telles que définies par le noyau. 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 transmises en continu >> comme un transfert FTP. A l'opposé, un flux interactif (interactive flow), correspond à 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 (à lire pour plus de détails) indique comment les applications devraient configurer leurs bits TOS pour fonctionner correctement :
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) |
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 !
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 correspond au 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 EGAL 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 libres 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.
Même si vous n'aurez probablement pas besoin de les changer, TBF a des paramètres. D'abord, ceux toujours disponibles sont :
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).
Taille du seau, en octets. C'est la quantité maximale, en octets, de jetons dont on disposera simultanément. 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.
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.
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 :
Si des jetons sont disponibles et que des paquets arrivent, ils sont immédiatement envoyés par défaut ; 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 (peak rate) 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 paquet, puis en attendant suffisamment longtemps, pour libérer 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 !
Le débit de crête de 1Mb/s ne sert pas à grand chose si votre débit habituel est supérieur à cette valeur. 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 à 1024 sur Alpha).
Voici une configuration simple, mais très utile :
# tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540 |
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 observerez que télécharger vers l'amont (uploading) dégrade 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 voie montante. Le 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 ENORME 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 envoyez 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 réside dans le noyau Linux, où nous pouvons lui imposer une taille limite.
Modifier la valeur 220kbit avec votre vitesse de lien REELLE moins un petit pourcentage. Si vous avez un modem vraiment rapide, augmenter un peu le paramètre burst.
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 étouffe les autres. 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 et 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.
Configurer spécialement 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 !
SFQ est presque configuré de base :
Reconfigure le hachage une fois toutes les pertub secondes. S'il n'est pas indiqué, le hachage se sera jamais reconfiguré. Ce n'est pas recommandé. 10 secondes est probablement une bonne valeur.
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 configurez pas en-dessous du MTU !
Si vous avez un périphérique qui a une vitesse identique à celle du lien et un débit réel disponible, comme un modem téléphonique, cette configuration aidera à promouvoir l'équité :
# tc qdisc add dev ppp0 root sfq perturb 10 # tc -s -d qdisc ls qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec Sent 4812 bytes 62 pkts (dropped 0, overlimits 0) |
Le nombre 800c est un descripteur (handle) automatiquement assigné et limit signifie que 128 paquets peuvent attendre dans la file d'attente. Il y a 1024 << seaux de hachage >> disponibles pour la comptabilité, 128 pouvant être actifs à la fois (pas plus de paquets ne conviennent dans la file d'attente). Le hachage est reconfiguré toutes les 10 secondes.
Pour résumer, 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.
Pour simplement ralentir le trafic sortant, utilisez le Token Bucket Filter. Il 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 le Stochastical Fairness Queueing.
Si vous avez une grande dorsale et que vous voulez savoir ce que vous faîtes, considérez Random Early Drop (voir le chapitre Gestionnaires de mise en file d'attente 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 un trafic pouvant sortir par plusieurs interfaces, alors le seul facteur commun est l'interface entrante. Dans ce cas, utilisez la réglementation Ingress.
Si vous ne voulez pas mettre en forme le trafic, mais que vous vouliez voir si votre interface est tellement chargée qu'elle a dû mettre en file d'attente les données, utilisez la file d'attente pfifo (pas pfifo_fast). Elle n'a pas de bandes internes, mais assure le comptage de la taille de son accumulateur.
Finalement, vous pouvez aussi faire de la << mise en forme sociale >>. La technologie n'est pas toujours capable de réaliser ce que vous voulez. Les utilisateurs sont hostiles aux contraintes techniques. Un mot aimable peut également vous aider à avoir votre bande passante correctement divisée !
Pour comprendre correctement des configurations plus compliquées, il est d'abord nécessaire d'expliquer quelques concepts. A cause de la complexité et de la relative jeunesse du sujet, beaucoup de mots différents sont utilisés par les personnes mais ils signifient en fait la même chose.
Ce qui suit est lâchement inspiré du texte draft-ietf-diffserv-model-06.txt, An Informal Management Model for Diffserv Routers. Il peut être trouvé à l'adresse http://www.ietf.org/internet-drafts/draft-ietf-diffserv-model-04.txt.
Lisez-le pour les définitions strictes des termes utilisés.
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).
Un gestionnaire de mise en file d'attente qui n'a pas de subdivisions internes configurables.
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.
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.
Chaque gestionnaire de mise en file d'attente basé sur des classes a besoin de déterminer vers quelles classes il doit envoyer un paquet. Ceci est réalisé en utilisant le classificateur.
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.
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é << reclassement >> (reordering), ce qui peut prêter à confusion.
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.
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).
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).
Quelques gestionnaire de mise en 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'ils en aient un de disponible.
Maintenant que nous avons défini notre terminologie, voyons où tous ces élements sont situés.
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_/ |
| |
+-----------------------------------------------------------+ |
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).
Ce processus a lieu très tôt, avant d'avoir beaucoup parcouru le 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, être 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 correspond à << 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 correspond au << retrait de la file d'attente >> (dequeueing).
Le schéma ne montre que le cas d'un seul adaptateur réseau. Les flèches entrantes et sortantes du noyau ne doivent pas être trop prises au pied de la lettre. Chaque adaptateur réseau a un gestionnaire d'entrée et de sortie.
Les gestionnaires de mise en file d'attente basés sur des classes sont très utiles si vous avez différentes sortes de trafic qui 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 é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 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 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.
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.
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 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.
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 :
Nombre de bandes à créer. Chaque bande est en fait une classe. Si vous changez ce nombre, vous devez également changer :
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.
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: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) |
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) |
# 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 qua