<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> <article lang="fr"> <articleinfo> <title>Guide pratique du multicast sur les réseaux TCP/IP</title> <subtitle>Adaptation française du <foreignphrase>Multicast over TCP/IP HOWTO</foreignphrase></subtitle> <author> <firstname>Juan-Mariano</firstname> <surname>de Goyeneche</surname> <affiliation> <address> <email>jmseyas CHEZ dit POINT upm POINT es</email> </address> </affiliation> </author> <othercredit role="traduction"> <firstname>Antoine</firstname> <surname>Duval</surname> <affiliation> <address> <email>aduval CHEZ altern POINT org</email> </address> </affiliation> <contrib>Adaptation française</contrib> </othercredit> <othercredit role="relecture"> <firstname>Fabrice</firstname> <surname>Gadaud</surname> <affiliation> <address> <email>fabrice CHEZ gadaud POINT org</email> </address> </affiliation> <contrib>Relecture de la version française</contrib> </othercredit> <othercredit role="publication"> <firstname>Jean-Philippe</firstname> <surname>Guérard</surname> <affiliation> <address> <email>jean TIRET philippe POINT guerard CHEZ corbeaunoir POINT org</email> </address> </affiliation> <contrib>Préparation de la publication de la v.f.</contrib> </othercredit> <releaseinfo>Version : 1.0.fr.1.1</releaseinfo> <pubdate>14 octobre 2003</pubdate> <revhistory> <revision> <revnumber>v1.0.fr.1.1</revnumber> <date>2003-10-14</date> <authorinitials>JPG</authorinitials> <revremark> Ajout de titres aux renvois inclus dans le texte. Reformatage des exemples de code. </revremark> </revision> <revision> <revnumber>v1.0.fr.1.0</revnumber> <date>2003-09-30</date> <authorinitials>AD,FG,JPG</authorinitials> <revremark>Première version française.</revremark> </revision> <revision> <revnumber>v1.0</revnumber> <date>1998-03-20</date> <authorinitials>JMdG</authorinitials> </revision> </revhistory> <abstract> <para> Ce guide pratique couvre les principaux aspects relatifs au multicast sur les réseaux TCP/IP. De nombreuses informations contenues dans ce document ne sont pas spécifiques à Linux (au cas où vous n'utiliserez pas encore le système Linux/GNU…). Le multicast est encore un domaine de recherche et les standards ne sont encore que des brouillons. Gardez cela à l'esprit à la lecture des lignes qui suivent. </para> </abstract> </articleinfo> <sect1> <title>Introduction</title> <para> Dans ce document, je vais essayer de vous donner des informations les plus à jour possible sur le multicast au travers des réseaux TCP/IP. Tout retour est le bienvenu. Si vous trouvez des erreurs dans ce document, si vous avez des commentaires ou des mises à jour à faire quant à son contenu, n'hésitez pas à m'en faire part à l'adresse que vous trouverez dans l'entête du document. </para> <sect2> <title>Qu'est ce que le multicast ?</title> <para> Le multicast est… un besoin. Ou du moins dans certains cas. Si vous avez des informations (beaucoup d'informations, le plus souvent) qui doivent être transmises à un ensemble de machines (mais le plus souvent pas toutes) au travers d'internet, alors le multicast est une bonne solution. Un cas typique d'utilisation du multicast, est la diffusion audio ou vidéo temps réel à un ensemble de machines donné qui ont précédemment rejoint une conférence distribuée. </para> <para> Il est à noter que le multicast ressemble à la radio ou à la télévision, en ce sens que seuls les utilisateurs qui ont réglé leur récepteur (en sélectionnant une fréquence particulière) reçoivent l'information. De ce fait, vous n'entendez que le canal qui vous intéresse, pas les autres. </para> </sect2> <sect2> <title>Le problème d'unicast</title> <para> Unicast est tout ce qui n'est ni du broadcast ni du multicast. Bien sûr, cette définition n'est pas vraiment claire… Expliquons nous : lorsque vous envoyez un paquet et qu'il y a seulement un émetteur (vous) et un récepteur (la personne à qui vous envoyez le paquet), alors il s'agit d'un mode de transmission unicast. TCP est par nature orienté unicast. UDP est déclinable selon plus de modèles, mais si vous envoyez des paquets UDP et qu'il n'y a qu'une personne qui est censée les recevoir, alors il s'agit aussi d'une transmission unicast. </para> <para> Pendant des années les transmissions unicast ont semblé être suffisantes pour Internet. Cela fut le cas jusqu'en 1993 où la première mise en œuvre du multicast vit le jour à l'occasion de la parution de la distribution BSD 4.4. Apparemment personne n'en avait jamais eu besoin avant cette date. Quels sont donc les nouveaux problèmes liés au multicast ? </para> <para> Il n'est peut-être pas nécessaire de dire ici, qu'internet a beaucoup changé depuis ses « premiers jours ». Particulièrement, l'apparition du web a considérablement transformé la situation : les personnes ne voulaient plus seulement se connecter à des hôtes distants, serveurs de mails ou encore FTP. Ils voulaient maintenant voir les images des personnes qu'ils côtoient sur les pages de leurs sites web personnels, et plus tard les voir et les entendre. </para> <para> Avec la technologie d'aujourd'hui il est possible de supporter le coût d'établissement d'une connexion avec ceux qui veulent voir votre page web personnelle. Cependant, si vous diffusez de l'audio et de la vidéo, vous aurez besoin d'un volume de bande passante énorme comparé aux applications web. Vous avez alors -ou vous aviez, si vous utilisez déjà le multicast- deux solutions : établir une connexion unicast avec chacun de vos destinataires, ou utiliser le broadcast. La première solution n'est pas envisageable : si nous nous accordons sur le fait qu'une seule connexion audio/vidéo consomme énormément de bande passante, imaginez alors le volume consommé par une centaine ou un millier de ces connections. Aussi bien l'ordinateur, émetteur des données, que le réseau lui étant lié succomberait [ndt : dans une grande souffrance]. </para> <para> Le broadcast, ou envoi par diffusion, semble être une solution, mais pas nécessairement la solution. Si vous souhaitez que toutes les machines de votre réseau écoutent la conférence, vous pouvez utiliser le broadcast. Dans ce cas, les paquets ne sont émis qu'une seule fois et chaque hôte les reçoit sur une adresse de broadcast ; adresse sur laquelle ils pourront, de la même manière, émettre. Cependant, il se peut que seulement peu d'utilisateurs soient intéressés par ces paquets. Plus encore, il se peut que certains utilisateurs soient vraiment intéressés par votre conférence, mais qu'ils se trouvent en dehors de votre réseau local, à seulement quelques routeurs de là. Vous n'êtes pas sans savoir que si le broadcast fonctionne bien à l'intérieur d'un réseau local, des problèmes surviennent lorsque vous désirez diffuser des paquets qui doivent être routés au travers de différents réseaux locaux. </para> <para>La meilleure solution serait alors d'émettre des paquets à une adresse spéciale, telle une fréquence donnée comme dans le cas d'une transmission radio ou de télévision. Dans ce cas, tous les hôtes qui ont décidé de joindre la conférence seront demandeurs des paquets portant cette adresse de destination ; ils les lisent lorsqu'ils passent sur le réseau et les transmettent à la couche IP pour qu'ils soient démultiplexés. Cette technique est similaire au broadcast en ce sens que vous n'émettez qu'un seul paquet en diffusion et que tous les hôtes du réseau peuvent le reconnaître et le lire ; elle est différente en ce sens que tous les paquets multicast ne sont pas lus et traités, mais seulement ceux qui ont été précédemment enregistrés dans le noyau comme étant intéressants. </para> <para>Ces paquets spéciaux sont routés au niveau du noyau comme tout autre paquet car il s'agit de paquets IP. L'unique différence réside dans l'algorithme de routage qui indique au noyau qui doit être routé et que faire des paquets à router. </para> </sect2> </sect1> <sect1> <title>Explications relatives au multicast</title> <sect2> <title>Adresses multicast</title> <para> Comme vous le savez probablement, les adresses IP sont divisées en « classes ». Ces classes sont basées sur l'ordre des bits de poids fort de l'adresse IP : </para> <para> <informaltable> <tgroup cols="8" colsep="1" rowsep="1"> <colspec colname="col0" align="center"/> <colspec colname="col1" align="left"/> <colspec colname="col2" align="center"/> <colspec colname="col3" align="center"/> <colspec colname="col4" align="center"/> <colspec colname="col5" align="center"/> <colspec colname="col6" align="right"/> <colspec colname="col7" align="center"/> <tbody> <row> <entry align="center" valign="top">Bit -></entry> <entry align="left" valign="top">0</entry> <entry align="center" valign="top"></entry> <entry align="center" valign="top"></entry> <entry align="center" valign="top"></entry> <entry align="center" valign="top"></entry> <entry align="right" valign="top">31</entry> <entry align="center" valign="top">Plage d'adresses :</entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col0"></entry> <entry align="left" valign="top" namest="col1" nameend="col1">0</entry> <entry align="right" valign="top" namest="col2" nameend="col6">Adresses de classe A</entry> <entry align="center" valign="top" namest="col7" nameend="col7">0.0.0.0 - 127.255.255.255</entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col0"></entry> <entry align="left" valign="top" namest="col1" nameend="col1">1</entry> <entry align="left" valign="top" namest="col2" nameend="col2">0</entry> <entry align="right" valign="top" namest="col3" nameend="col6">Adresses de classe B</entry> <entry align="center" valign="top" namest="col7" nameend="col7">128.0.0.0 - 191.255.255.255</entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col0"></entry> <entry align="left" valign="top" namest="col1" nameend="col1">1</entry> <entry align="left" valign="top" namest="col2" nameend="col2">1</entry> <entry align="left" valign="top" namest="col3" nameend="col3">0</entry> <entry align="right" valign="top" namest="col4" nameend="col6">Adresses de classe C</entry> <entry align="center" valign="top" namest="col7" nameend="col7">192.0.0.0 - 223.255.255.255</entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col0"></entry> <entry align="left" valign="top" namest="col1" nameend="col1">1</entry> <entry align="left" valign="top" namest="col2" nameend="col2">1</entry> <entry align="left" valign="top" namest="col3" nameend="col3">1</entry> <entry align="left" valign="top" namest="col4" nameend="col4">0</entry> <entry align="right" valign="top" namest="col5" nameend="col6">Adresses multicast</entry> <entry align="center" valign="top" namest="col7" nameend="col7">224.0.0.0 - 239.255.255.255</entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col0"></entry> <entry align="left" valign="top" namest="col1" nameend="col1">1</entry> <entry align="left" valign="top" namest="col2" nameend="col2">1</entry> <entry align="left" valign="top" namest="col3" nameend="col3">1</entry> <entry align="left" valign="top" namest="col4" nameend="col4">1</entry> <entry align="left" valign="top" namest="col5" nameend="col5">0</entry> <entry align="right" valign="top" namest="col6" nameend="col6">Réservé</entry> <entry align="center" valign="top" namest="col7" nameend="col7">240.0.0.0 - 247.255.255.255</entry> </row> </tbody> </tgroup> </informaltable> </para> <para> La classe qui nous intéresse est la classe D. Chaque datagramme dont l'adresse de destination (codée sur 32 bits) commence par « 1110 » est un datagramme IP Multicast. </para> <para> Les 28 autres bits identifient le <emphasis>groupe</emphasis> auquel le datagramme est envoyé. Poursuivant avec la précédente analogie, il est nécessaire de régler sa radio pour entendre un programme qui est retransmis sur une fréquence donnée. Dans notre cas, il convient de procéder de la même façon : vous devez « régler » votre noyau pour qu'il reçoive les paquets qui sont émis à destination d'un groupe multicast donné. Lorsque cette opération est effectuée, il est dit que l'hôte a <emphasis>joint</emphasis> ce groupe ; ceci sur une interface spécifiée : vous trouverez plus d'informations sur ce propos par la suite. </para> <para> Il existe des groupes multicast spéciaux, dits « groupes multicast bien connus », vous ne devez pas les utiliser pour vos applications, du fait de l'usage bien spécifique auquel ils sont destinés : </para> <variablelist> <varlistentry> <term>224.0.0.1</term> <listitem> <para> est le groupe <emphasis>all-hosts</emphasis>. Si vous pingez ce groupe, tous les hôtes sur le réseau capables d'émettre en multicast répondront, car tout hôte gérant le multicast <emphasis>doit</emphasis> joindre ce groupe au démarrage sur toutes ses interfaces. </para> </listitem> </varlistentry> <varlistentry> <term>224.0.0.2</term> <listitem> <para> est le groupe <emphasis>all-routers</emphasis>. Tous les routeurs multicast joignent ce groupe sur toutes leurs interfaces multicast. </para> </listitem> </varlistentry> <varlistentry> <term>224.0.0.4</term> <listitem> <para>est le groupe de tous les routeurs DVMRP.</para> </listitem> </varlistentry> <varlistentry> <term>224.0.0.5</term> <listitem> <para>est le groupe de tous les routeurs OSPF.</para> </listitem> </varlistentry> <varlistentry> <term>224.0.0.13</term> <listitem> <para>est le groupe de tous les routeurs PIM, etc.</para> </listitem> </varlistentry> </variablelist> <para> Tous ces groupes multicast spéciaux sont régulièrement publiés dans le RFC « Assigned Numbers » </para> <para> Dans tous les cas, l'intervalle allant de 224.0.0.0 à 224.0.0.255 est reservé pour les contenus locaux (comme des tâches administratives ou de maintenance) et les datagrammes destinés à ces adresses ne sont jamais retransmis par les routeurs multicast. De la même manière, l'intervalle allant de 239.0.0.0 à 239.255.255.255 est reservé pour des raisons d'administration (cf section 2.3.1 pour de plus amples imformations à ce propos). </para> </sect2> <sect2> <title>Niveaux de conformité</title> <para> Il existe trois niveaux de conformité différents, que les hôtes peuvent implémenter, en accord avec la spécification multicast, permettant de gérer les différents services mis en commun. </para> <variablelist> <varlistentry> <term>Niveau 0</term> <listitem> <para> signifie « qu'aucun support n'est disponible pour l'IP multicast ». Beaucoup d'hôtes et de routeurs sur Internet sont dans cet état, car le support multicast n'est pas exigé pour l'IPv4 (il l'est cependant pour l'IPv6). Ainsi, les hôtes qui sont dans cet état ne peuvent ni émettre, ni recevoir de paquets multicast. Ils ignorent donc les paquets émis par les autres hôtes pouvant émettre en multicast. </para> </listitem> </varlistentry> <varlistentry> <term>Niveau 1</term> <listitem> <para> signifie « qu'il existe un support pour envoyer mais pas pour recevoir des datagrammes IP multicast ». Dans ce cas, il n'est pas nécessaire de joindre un quelconque groupe multicast pour envoyer des datagrammes. Peu d'ajouts sont nécessaires à un module IP pour passer un hôte du « niveau 0 » au « compatible niveau 1 », comme on pourra le voir dans la section 2.3. </para> </listitem> </varlistentry> <varlistentry> <term>Niveau 2</term> <listitem> <para> signifie qu'un « support complet est disponible pour l'IP multicast ». Les hôtes de niveau 2 sont aussi bien capables d'émettre, que de recevoir du trafic multicast. Ils savent comment joindre et quitter les groupes multicast, ainsi que propager cette information aux routeurs multicasts. De même, ils incluent une implémentation de IGMP (Internet Group Management Protocol) dans leur pile de protocoles TCP/IP. </para> </listitem> </varlistentry> </variablelist> </sect2> <sect2> <title>Envoyer des datagrammes multicast.</title> <para> Il est évident que le trafic multicast doit être encapsulé par une couche transport comme UDP. En effet, TCP fournit des connections point-à-point, ce qui n'est pas envisageable pour du trafic multicast. Il est à noter que des recherches sont effectuées dans ce domaine pour définir et implémenter un nouveau protocole de transport orienté multicast. Consultez la <xref linkend="Proto-transport-multicast"/> pour plus de détails. </para> <para> En principe, une application nécessite seulement l'ouverture d'une prise réseau UDP qu'elle remplit de données, qui seront envoyées à destination d'une adresse multicast (classe D). Cependant, certaines opérations doivent être contrôlées lors du processus d'envoi. </para> <sect3> <title>TTL</title> <para> Le champ <emphasis>TTL</emphasis> (<emphasis>Time To Live</emphasis>, ou temps restant à vivre) de l'entête IP a une double signification pour le multicast. Comme toujours, il contrôle le temps restant à vivre pour un datagramme empêchant ainsi les boucles infinies dues aux erreurs de routage. Chaque routeur décrémente le TTL de tout datagramme le traversant et lorsque cette valeur devient égale à 0 le paquet est détruit. </para> <para>Le TTL dans notre cas (sur IPv4) a aussi une signification de « seuil ». Éclairons son utilisation à l'aide d'un exemple : supposez que vous fassiez une longue conférence vidéo (consommant beaucoup de bande passante) entre tous les hôtes de votre département. Vous désirez que tout ce trafic puisse être supporté par votre réseau local. Peut-être que votre département est suffisamment grand pour avoir différents réseaux locaux. Dans ce cas vous désirerez sûrement que les hôtes appartenant à chacun de vos réseaux locaux puissent suivre la conférence, sans pour autant saturer Internet tout entier avec votre trafic multicast. Il est donc nécessaire de limiter la portée du trafic multicast au travers des routeurs. C'est ce à quoi est destiné le TTL. Chaque routeur a un seuil TTL assigné sur chaque interface, et seuls les datagrammes qui ont un TTL supérieur au seuil de l'interface sont retransmis au travers de ce routeur. Notez que lorsqu'un datagramme traverse un routeur avec une valeur de seuil donnée, le TTL du datagramme n'est <emphasis>pas</emphasis> décrémenté de la valeur de ce seuil. Seule une comparaison est faite. (Comme précedemment, le TTL est décrémenté de 1 à chaque passage au travers d'un routeur). </para> <para>Une liste de seuils TTL et de leur signification suit :</para> <para> <informaltable> <tgroup cols="2" colsep="1" rowsep="1"> <colspec colname="col0" align="center"/> <colspec colname="col1" align="center"/> <tbody> <row> <entry align="center" valign="top"> TTL </entry> <entry align="center" valign="top"> Signification </entry> </row> <row> <entry align="center" valign="top"> 0 </entry> <entry align="center" valign="top"> Restriction au même hôte. Le paquet ne sera émis sur aucune interface. </entry> </row> <row> <entry align="center" valign="top"> 1 </entry> <entry align="center" valign="top"> Restriction au même sous réseau. Le paquet ne pourra être routé </entry> </row> <row> <entry align="center" valign="top"> <32 </entry> <entry align="center" valign="top"> Restriction au même site, organisation ou département. </entry> </row> <row> <entry align="center" valign="top"> <64 </entry> <entry align="center" valign="top"> Restriction à la même région. </entry> </row> <row> <entry align="center" valign="top"> <128 </entry> <entry align="center" valign="top"> Restriction au même continent. </entry> </row> <row> <entry align="center" valign="top"> <255 </entry> <entry align="center" valign="top"> Aucune restriction. Global. </entry> </row> </tbody> </tgroup> </informaltable> </para> <para> Aucune signification exacte n'a été donnée au terme de « site » ou de « région ». Il est à la charge des administrateurs de décider des limites qui s'appliquent. </para> <para> Il est à noter que l'astuce liée au TTL n'est peut être pas toujours assez souple pour correspondre à tous les besoins, et plus spécialement s'il est nécessaire de traiter avec des régions qui se chevauchent et prenent en compte à la fois des limites géographiques, topologiques ou encore liées à une gestion de bande passante. Afin de résoudre ce problème, des régions multicast à caractère administratif ont été établies depuis 1994. (cf D.Meyer's « Administratively Scoped IP Multicast » Internet draft). Ce découpage est basé sur les adresses multicast au lieu des TTL. L'intervalle allant de 239.0.0.0 à 239.255.255.255 est reservé à ce découpage administratif. </para> </sect3> <sect3> <title>Loopback</title> <para> Lorsqu'un hôte est conforme au niveau 2 et qu'il est membre du groupe auquel il envoie des datagrammes, alors une copie des datagrammes lui est retransmise par défaut. Cela ne signifie pas que l'interface lit sa propre transmission depuis le réseau (en reconnaissant les datagrammes comme étant d'un groupe auquel appartient l'interface). Au contraire, c'est la couche IP qui, par défaut, reconnaît le datagramme à envoyer, le copie puis le met sur la file d'entrée IP avant de l'envoyer. </para> <para> Cette fonctionnalité est appréciable dans certains cas, mais pas pour tous. De ce fait il est possible d'activer ou de désactiver ce processus d'envoi selon ses souhaits. </para> </sect3> <sect3> <title>Sélection de l'interface.</title> <para> Les hôtes qui sont reliés à plus d'un réseau doivent pouvoir décider de l'interface réseau à utiliser pour envoyer les informations. Si rien n'est spécifié, alors le noyau en choisit une par défaut. Ce choix est basé sur la configuration faite par l'administrateur. </para> </sect3> </sect2> <sect2> <title>Recevoir des datagrammes multicast</title> <sect3> <title>Joindre un groupe multicast</title> <para> La diffusion en broadcast est (en comparaison) plus simple à implémenter que la diffusion en multicast. En effet dans le premier cas, il n'est pas nécessaire que les processus donnent au noyau des règles concernant la gestion des paquets diffusés. Le noyau sait ce qu'il doit faire avec <emphasis>tous</emphasis> les paquets : les lire et les délivrer aux applications concernées. </para> <para> En diffusion multicast il est nécessaire d'aviser le noyau des groupes multicast qui nous intéressent. Le noyau « joint » alors ces groupes. Puis selon la nature du matériel sous-jacent, les datagrammes multicast sont filtrés soit par le matériel, soit par la couche IP (et dans certains cas, par les deux). Seuls les datagrammes dont le groupe de destination a précédemment été rejoint sont acceptés. </para> <para> Essentiellement, lorsque l'on joint un groupe, nous disons au noyau « D'accord, je sais que par défaut tu ignores les datagrammes multicast, mais souviens toi que <emphasis>ce</emphasis> groupe multicast m'intéresse. De ce fait, lit et délivre (à tous les processus intéressés, pas seulement moi) tous les datagrammes que tu vois sur ton interface réseau et qui sont adressés au groupe multicast en question ». </para> <para> Quelques remarques : tout d'abord, notez que vous ne faites pas que rejoindre un groupe. Vous joignez un groupe sur une interface réseau particulière. Bien sûr, il est possible de joindre le même groupe sur plusieurs interfaces. Si vous ne spécifiez pas concrètement une interface, alors le noyau en choisira une (selon sa table de routage) lorsqu'il sera nécessaire d'envoyer des datagrammes. Par ailleurs, il est possible que plus d'un processus rejoignent le même groupe multicast par une même interface. Ces processus reçoivent alors tous les datagrammes envoyés à ce groupe au travers de cette interface. </para> <para> Comme dit précédemment, tous les hôtes gérant le multicast joignent le groupe <emphasis>all-hosts </emphasis>au démarrage, de ce fait on peut « pinger » tous les hôtes gérant le multicast au travers de l'adresse 224.0.0.1. </para> <para> Finalement, considérez le fait suivant : pour qu'un processus puisse recevoir des datagrammes multicast, il doit demander au noyau de joindre le groupe désiré, et doit se relier au port par lequel les datagrammes seront envoyés. La couche UDP se base à la fois l'adresse de destination et le numéro de port pour démultipexer les paquets reçus et décider à quelle(s) connection(s) les délivrer. </para> </sect3> <sect3> <title>Quitter un groupe multicast</title> <para> Quand un processus n'est plus intéressé par un groupe multicast, il informe le noyau qu'il désire quitter ce groupe. Il est important de comprendre que cela ne signifie pas que le noyau n'acceptera plus les datagrammes multicast destinés à ce groupe. En effet, il continuera à le faire si d'autres processus restent intéressés par ce groupe. Dans ce cas l'hôte reste membre de ce groupe, et cela jusqu'à ce que tous les processus décident de le quitter. </para> <para> L'explication ici est que joindre un groupe multicast nécessite seulement une adresse IP. C'est la couche de liaison de données qui, après une demande explicite au matériel dans certains cas, accepte les datagrammes multicast destinés à ce groupe. L'appartenance à un groupe ne se fait donc pas par processus, mais par hôte. </para> </sect3> <sect3> <title>Transcrire une adresse IP Multicast dans une adresse Ethernet/FDDI</title> <para> Les trames Ethernet, aussi bien que les trames FDDI, ont une adresse de destination codée sur 48 bits. Dans le but d'éviter une sorte d'ARP multicast translatant les adresses IP multicast en adresses ethernet/FDDI, l'IANA a réservé une plage d'adresses pour le multicast : chaque trame ethernet/FDDI dont l'adresse de destination appartient à l'intervalle allant de 01-00-5e-00-00-00 à 01-00-5e-ff-ff-ff contient des données à destination d'un groupe multicast. Le préfixe 01-00-5e identifie la trame comme étant multicast, le bit suivant étant toujours à 0, il reste donc 23 bits de disponibles pour les adresses multicast. Comme les groupes multicast sont définis sur 28 bits, la translation ne peut pas être une à une. Seuls les 23 bits les moins significatifs du groupe IP multicast sont placés dans la trame. Les 5 bits d'ordre supérieur restant sont ignorés, ce qui a pour résultat que 32 groupes multicast différents peuvent être translatés par une même adresse ethernet/FDDI. Cela signifie que la couche ethernet agit tel un filtre imparfait, et que la couche IP doit décider si elle accepte les datagrammes de la couche de liaison de données qui lui sont donnés. La couche IP agit tel un filtre final parfait. </para> <para> Tous les détails concernant l'IP Multicast au travers de FDDI sont donnés dans le RFC 1390 « Transmission of IP and ARP over FDDI Networks » (transmission IP et ARP au travers de réseaux FDDI). Pour plus d'information concernant la translation d'adresses IP multicast vers ethernet, vous pouvez consulter le draft-ietf-mboned-intro-multicast-03.txt: « Introduction to IP Multicast Routing » (introduction au routage IP multicast). </para> <para> Si vous êtes intéressé par l'IP multicast sur les réseaux locaux Token-Ring, consultez le RFC 1469. </para> </sect3> </sect2> </sect1> <sect1> <title>Besoins et configuration du noyau</title> <para> Linux est, bien sûr (doutez-vous de cela ?), pleinement compatible avec le multicast niveau 2. Il satisfait toutes les exigences liées à l'envoi, à la réception et au routage (grâce à mrouter) des datagrammes multicast. </para> <para> Si vous désirez émettre et recevoir des paquets IP multicast, vous devez activer l'option « IP: multicasting » lors de la configuration de votre noyau. Si vous désirez aussi que votre Linux agisse tel un routeur multicast, vous aurez alors besoin d'activer le routage multicast du noyau en sélectionnant « IP: forwarding/gatewaying » (transfert/passerelle), « IP: multicast routing » (routage multicast) et « IP: tunneling » (tunnel), cette dernière option est nécessaire car les nouvelles versions de mrouted peuvent aussi retransmettre les paquets au travers de tunnels IP ; les datagrammes IP multicast sont alors encapsulés dans des datagrammes unicast. Il est nécessaire d'établir des tunnels entre des hôtes multicast s'ils sont séparés par un réseau ou par plusieurs routeurs incapables de transférer des datagrammes multicast. (<emphasis>mrouted</emphasis> est un service qui implémente un algorithme de routage multicast -politique de routage- et informe le noyau sur la façon de router les datagrammes multicast. </para> <para> Certaines versions du noyau considèrent le routage multicast comme étant « EXPERIMENTAL », de ce fait vous devez activer l'option « Prompt for development and/or incomplete code/drivers » dans la section « Code maturity level options ». </para> <para> Si, durant l'exécution de <emphasis>mrouted</emphasis>, le trafic généré sur le réseau (où est connectée votre station linux) est correctement transféré aux autres réseaux, mais il vous est impossible de « voir » le trafic des autres réseaux sur votre réseau local, vérifiez alors si vous recevez des messages d'erreur du protocole ICMP. Il s'agit d'une erreur due, le plus fréquemment, à la non activation de l'IP tunneling de votre routeur Linux. C'est le genre d'erreur qui paraît stupide lorsque vous la connaissez mais, croyez moi, cela prend beaucoup de temps pour la détecter quand vous l'ignorez, car il n'y a pas de raison apparente signifant la cause de l'erreur. Un renifleur (ou « sniffeur ») s'avère utile dans ce genre de situation. </para> <para> Vous trouverez plus d'informations dans la <xref linkend="Politiques-de-routage"/> ; <emphasis>mrouted</emphasis> et les tunnels sont aussi expliqués dans la <xref linkend="MBone"/> et la <xref linkend="Applications-multicast"/>. </para> <para> Une fois votre nouveau noyau compilé et installé, vous devez définir une route par défaut pour votre trafic multicast. Ce qui revient à ajouter une route au réseau 224.0.0.0. </para> <para> Le problème auquel le plus de personnes font face à ce stade de la configuration est la valeur du masque à appliquer. Si vous avez lu précédemment l'excellent NET-3-HOWTO de Terry Dawson, il ne vous sera pas difficile de trouver la bonne valeur. Comme expliqué, le masque de sous réseau est un nombre codé sur 32 bits rempli avec des « 1 » sur la partie réseau de votre adresse IP, et avec des « 0 » sur la partie hôte. En référence à la section 2.1 une adresse multicast de classe D n'a pas de division réseau/hôte. À la place, il a un groupe d'identification codé sur 28 bits et un identifiant de classe D codé sur 4 bits. Le masque de sous réseau voulu est donc 11110000000000000000000000000000 ou d'une manière plus facilement lisible : 240.0.0.0. De ce fait la commande complète est : </para> <programlisting> route add 224.0.0.0 netmask 240.0.0.0 dev eth0 </programlisting> <para> Selon la version de votre programme <emphasis>route</emphasis>, il peut être nécessaire d'ajouter l'option <emphasis>-net</emphasis> après l'option <emphasis>add</emphasis>. </para> <para> Dans l'exemple, nous supposons que l'interface <emphasis>eth0</emphasis> supporte le multicast et, si rien d'autre n'est spécifié, nous voulons que le trafic multicast sorte par cette interface. Si cela n'est pas votre cas, changez alors le paramètre <emphasis>dev</emphasis> de manière appropriée. </para> <para>Le système de fichiers <emphasis>/proc</emphasis> s'avère utile une fois encore : il est possible de vérifier dans le fichier <emphasis>/proc/net/igmp</emphasis> les groupes auxquels votre machine est actuellement connectée. </para> </sect1> <sect1 id="MBone" xreflabel="section consacrée à MBone"> <title>MBone</title> <para> L'utilisation d'une nouvelle technologie apporte son lot d'avantages et d'inconvénients. Les avantages du multicast sont -je le pense- clairs. Le principal inconvénient est qu'actuellement des centaines d'hôtes, et plus spécialement les routeurs, ne supportent pas le multicast. Par conséquent, les personnes qui commencent à travailler avec du multicast, et qui de fait ont acheté de nouveaux équipements et modifié leurs systèmes d'exploitation ; on construit des <emphasis>îlots multicast</emphasis> dans leurs locaux. C'est alors qu'ils ont découvert qu'il leur était difficile de communiquer avec des personnes faisant de même car il suffit d'un routeur ne supportant pas le multicast pour que rien ne fonctionne. </para> <para> La solution est alors apparue comme évidente : ils décidèrent de contruire un réseau multicast virtuel au-dessus d'Internet. De fait : les sites reliés par des routeurs multicasts peuvent communiquer entre-eux directement. Mais les sites joigniables uniquement par le biais de routeurs unicast doivent encapsuler leur trafic multicast dans des paquets unicast pour communiquer avec les autres îlots multicast. Les routeurs traversés ne poserons pas de problèmes car ils savent gérer ce trafic unicast. Finalement, le site de réception désencapsulera le trafic, et le retransmettra à l'îlot selon la méthode multicast originale. Ainsi, les deux extrémités convertissent du multicast vers de l'unicast et à nouveau de l'unicast vers du multicast, définissant ainsi ce qui est appelé un tunnel multicast. </para> <para> Le MBone ou épine dorsale multicast (Multicast BackBone) est un réseau virtuel multicast basé sur l'interconnection d'îlots multicast reliés entre eux par des tunnels multicast. </para> <para> Diverses utilisations sont faites du MBone de nos jours, on peut ainsi remarquer la profusion de téléconférences audio/vidéo en temps réel qui ont lieu au travers d'Internet. Un exemple de ces téléconférences est la retransmission (en direct !) de la conférence de Linus Torvalds qui a été donnée au groupe d'utilisateurs de Linux de la Silicon Valley [ndt : en 1999 ?]. </para> <para> Pour plus d'informations à propos du MBone, consultez : http://www.mediadesign.co.at/newmedia/more/mbone-faq.html </para> </sect1> <sect1 id="Applications-multicast" xreflabel="section applications multicast"> <title>Applications multicast</title> <para> La plupart des personnes ayant affaire avec le multicast, décident tôt ou tard de se connecter au MBone, et de ce fait ont tradionnellement besoin de <emphasis>mrouted</emphasis>. Vous aurez sûrement besoin de lui si vous ne possédez pas de routeur capable de faire du multicast et que vous voulez que le travail effectué sur l'un de vos sous réseaux soit « entendu » par un autre réseau. <emphasis>mrouted</emphasis> circonscrit le problème d'envoi de trafic au travers des routeurs unicast -il encapsule les datagrammes multicast dans des datagrammes unicast (IP dans IP)-. Il ne s'agit pas de la seule fonctionnalité de <emphasis>mrouted</emphasis>. La plus importante, est qu'il indique au noyau la façon de router (ou de ne pas router) les datagrammes multicast selon leurs adresses d'origine et de destination. De ce fait, même si vous avez un routeur multicast, <emphasis>mrouted</emphasis> peut être utilisé pour lui dire <emphasis>quoi faire</emphasis> des datagrammes. (notez que j'ai dit <emphasis>quoi</emphasis>, et non <emphasis>comment</emphasis>, <emphasis>mrouted</emphasis> dit « transmet ceci au réseau connecté à cette interface », mais le transfert se fait actuellement par le noyau). Il existe une distinction à faire entre le transfert en lui-même et l'algorithme qui décide de ce qui doit être transféré et de la façon de le faire. Cette distinction est très utile car elle permet d'écrire un code unique permettant le transfert, en l'insérant dans le noyau ; tandis que les algorithmes et les politiques de transfert sont implémentés en tant que service utilisateur, ce qui permet un changement de politique sans recompiler le noyau. </para> <para> Vous pouvez vous procurer une version de <emphasis>mrouted</emphasis> pour Linux depuis : ftp://www.video.ja.net/mice/mrouted/Linux/. Des mirroirs de ce site existent tout autour de la planète. Lisez bien le fichier ftp://www.video.ja.net/mice/README.mirrors pour choisir le mirroir le plus près de chez vous. </para> <para> Vous trouverez ci-dessous une liste des applications qui ont été écrites afin de se connecter au MBone et qui ont été portées sous Linux. Cette liste est issue de la page d'information « Linux Multicast Information » écrite par Michael Esler : http://www.cs.virginia.edu/˜mke2e/multicast/. Je vous recommande cette page pour toutes les informations et ressources à propos du multicast et de Linux. </para> <sect2> <title>Conférences audio</title> <itemizedlist> <listitem> <para>NeVoT - Terminal réseau pour la voix http://www.fokus.gmd.de/step/nevot</para> </listitem> <listitem> <para>RAT - UCL outil audio robuste http://www-mice.cs.ucl.ac.uk/mice/rat</para> </listitem> <listitem> <para>vat - LBL outil audio visuel http://www-nrg.ee.lbl.gov/vat/</para> </listitem> </itemizedlist> </sect2> <sect2> <title>Conférences vidéo</title> <itemizedlist> <listitem> <para>ivs - Système de vidéo conférence de l'Inria http://www.inria.fr/rodeo/ivs.html</para> </listitem> <listitem> <para>nv - Outil réseau pour la vidéo ftp://ftp.parc.xerox.com/pub/net-research/</para> </listitem> <listitem> <para>nv w/ Meteor - Version de nv w/ pour Matrox Meteor (UVa) ftp://ftp.cs.virginia.edu/pub/gwtts/Linux/nv-meteor.tar.gz</para> </listitem> <listitem> <para>vic - LBL Outil de vidéo conférence http://www-nrg.ee.lbl.gov/vic/</para> </listitem> <listitem> <para>vic w/ Meteor - Version de vic w/ support pour Matrox Meteor (UVa) ftp://ftp.cs.virginia.edu/pub/gwtts/Linux/vic2.7a38-meteor.tar.gz </para> </listitem> </itemizedlist> </sect2> <sect2> <title>Autres utilitaires</title> <itemizedlist> <listitem> <para>mmphone service téléphonique multimédia http://www.eit.com/software/mmphone/phoneform.html</para> </listitem> <listitem> <para>wb - LBL tableau blanc partagé http://www-nrg.ee.lbl.gov/wb/</para> </listitem> <listitem> <para>webcast - Application multicast fiable pouvant relier les navigateurs Mosaic http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/CCI/webcast.html </para> </listitem> </itemizedlist> </sect2> <sect2> <title>Outils de session</title> <para> Les outils de gestion de sessions ont été placés après les autres, car ils nécessitent quelques explications. Lorsque qu'une conférence a lieu, il est assigné pour chaque service (audio, vidéo, tableau-blanc partagé, etc) un ou plusieurs groupes multicast, eux-mêms associés à un numéro de port. Les conférences qui vont avoir lieu sont périodiquement annoncées sur le MBone. Ces annonces contiennent des informations à propos des groupes multicasts, des numéros de ports et des programmes qui peuvent être utilisés (vic, vat, …). Les outils de gestion de sessions « écoutent » ces informations et vous les annoncent de manière à ce qu'elles soient facilement joignables. Vous pouvez ainsi décider quelle conférence vous intéresse. Ainsi, au lieu de démarrer chaque programme qui sera utilisé et lui indiquer les groupes multicast et les numéros de ports qu'il vous faut joindre, il vous suffit de cliquer sur l'annonce et l'outil de gestion de sessions démarre les bonnes applications, en leur communiquant toutes les informations nécessaires pour joindre la conférence. Les outils de gestion de sessions vous permettent généralement d'annoncer votre propre conférence sur le MBone. </para> <itemizedlist> <listitem> <para>gwTTS - système de télé-enseignement de Université de Virginie http://www.cs.Virginia.EDU/˜gwtts</para> </listitem> <listitem> <para>isc - contrôleur de session intégré http://www.fokus.gmd.de/step/isc</para> </listitem> <listitem> <para>mmcc - contrôle de conférences multimédia ftp://ftp.isi.edu/confctrl/mmcc</para> </listitem> <listitem> <para>sd - outil de référencement de session LBL ftp://ftp.ee.lbl.gov/conferencing/sd</para> </listitem> <listitem> <para>sd-snoop - utilitaire de référencement de sessions du Tenet Group ftp://tenet.berkeley.edu/pub/software</para> </listitem> <listitem> <para>sdr - nouvelle génération de référencement de sessions d'UCL ftp://cs.ucl.ac.uk/mice/sdr</para> </listitem> </itemizedlist> </sect2> </sect1> <sect1> <title>Programmation multicast</title> <para> Programmation multicast… ou comment écrire vos propres applications multicast. </para> <para> Diverses extensions de l'API de programmation sont nécessaires pour utiliser le multicast. Ces extensions sont utilisables par le biais de deux appels systèmes : setsockopt() (utilisé pour envoyer des informations au noyau) et getsockopt() (utilisé pour recevoir des informations du voisinage multicast). Cela ne signifie pas que ces 2 nouveaux appels systèmes ont été ajoutés pour le fonctionnement du multicast. La paire <emphasis>setsockopt() / getsockopt()</emphasis> est là depuis des années. Depuis la BSD 4.2 au moins. L'ajout consiste en un nouveau jeu d'options (options multicast) qui est passé à ces appels systèmes et que le noyau doit comprendre. </para> <para> Les deux lignes suivantes donnent le prototypage des fonctions <emphasis>setsockopt() / getsockopt()</emphasis>. </para> <programlisting> int getsockopt(int s, int level, int optname, void* optval, int* optlen); int setsockopt(int s, int level, int optname, const void* optval, int optlen); </programlisting> <para> Le premier paramètre, <emphasis>s</emphasis>, est la prise réseau (socket) à laquelle l'appel système s'applique. Pour le multicast, la prise doit être de la famille <emphasis>AF_INET</emphasis> et peut être de type <emphasis>SOCK_DGRAM</emphasis> ou <emphasis>SOCK_RAW</emphasis>. Le plus courant est l'utilisation d'une prise <emphasis>SOCK_DGRAM</emphasis>, mais si votre but est d'écrire un démon de routage ou d'en modifier un, vous aurez plutôt besoin d'une prise de type <emphasis>SOCK_RAW</emphasis>. </para> <para> Le deuxième paramètre, <emphasis>level</emphasis>, identifie la couche qui capturera l'option, le message, ou la requète, ou tout ce que vous désirez appeler. De fait, <emphasis>SOL_SOCKET</emphasis> est pour la couche de la prise réseau, <emphasis>IPPROTO_IP</emphasis> est pour la couche IP, etc. Pour la programmation multicast, la valeur est toujours <emphasis>IPPROTO_IP</emphasis>. </para> <para> <emphasis>optname</emphasis> identifie l'option que nous passons ou demandons. Sa valeur, soit fournie par le programme, soit retournée par le noyau, est <emphasis>optval</emphasis>. Les valeurs pour <emphasis>optname</emphasis> qui peuvent être invoquées pour la programmation multicast sont les suivantes : </para> <para> <informaltable> <tgroup cols="3" colsep="1" rowsep="1"> <colspec colname="col0" align="center"/> <colspec colname="col1" align="center"/> <colspec colname="col2" align="center"/> <tbody> <row> <entry align="center" valign="top"> </entry> <entry align="center" valign="top"> setsockopt() </entry> <entry align="center" valign="top"> getsockopt() </entry> </row> <row> <entry align="center" valign="top"> IP_MULTICAST_LOOP </entry> <entry align="center" valign="top"> oui </entry> <entry align="center" valign="top"> oui </entry> </row> <row> <entry align="center" valign="top"> IP_MULTICAST_TTL </entry> <entry align="center" valign="top"> oui </entry> <entry align="center" valign="top"> oui </entry> </row> <row> <entry align="center" valign="top"> IP_MULTICAST_IF </entry> <entry align="center" valign="top"> oui </entry> <entry align="center" valign="top"> oui </entry> </row> <row> <entry align="center" valign="top"> IP_ADD_MEMBERSHIP </entry> <entry align="center" valign="top"> oui </entry> <entry align="center" valign="top"> non </entry> </row> <row> <entry align="center" valign="top"> IP_DROP_MEMBERSHIP </entry> <entry align="center" valign="top"> oui </entry> <entry align="center" valign="top"> non </entry> </row> </tbody> </tgroup> </informaltable> </para> <para> <emphasis>optlen</emphasis> transporte la taille de la structure de données à laquelle <emphasis>optval</emphasis> fait référence. Notez que pour <emphasis>getsockopt()</emphasis>, c'est un résultat et non une donnée : le noyau écrit la valeur de <emphasis>optname</emphasis> dans la zone tampon pointée par <emphasis>optval</emphasis> et nous informe de la longueur de la valeur par <emphasis>optlen</emphasis>. </para> <para> Aussi bien <emphasis>setsockopt()</emphasis> que <emphasis>getsockopt()</emphasis> retournent 0 en cas de succès et -1 en cas d'erreur. </para> <sect2> <title>IP_MULTICAST_LOOP</title> <para> Vous devez décider, en tant que programmeur, si les données que vous voulez émettre doivent être retournées ou non sur votre hôte. Si vous pensez avoir plus d'un processus ou utilisateur en écoute, alors un retour doit être activé. À contrario, si vous émettez des images que votre caméra vidéo produit, vous ne nécessiterez probablement pas de retour, à moins que vous désiriez les voir sur votre écran. Dans ce dernier cas, votre application recevra déjà certainement les images depuis le périphérique connecté à votre ordinateur pour les envoyer à la prise réseau. De ce fait, l'application possède déjà les données, et cela devient improbable que vous vouliez les recevoir de nouveau au travers de la prise réseau. </para> <para> Il est à noter que le retour est activé par défaut. </para> <para> Comme <emphasis>optval</emphasis> est un pointeur, vous ne pouvez pas écrire : </para> <programlisting> setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, 0, 1); </programlisting> <para> pour désactiver le loopback vous devez écrire : </para> <programlisting> u_char loop; setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); </programlisting> <para> et donnez la valeur 1 à <emphasis>loop</emphasis> pour activer le retour et 0 pour le désactiver. </para> <para> Pour savoir si une prise réseau a activé ou non son retour, utilisez quelque chose comme : </para> <programlisting> u_char loop; int size; getsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &size) </programlisting> </sect2> <sect2> <title>IP_MULTICAST_TTL</title> <para> Si rien n'est précisé, les datagrammes multicast sont envoyés avec comme valeur par défaut 1, dans le but d'éviter qu'ils soient transférés sur tout le réseau local. Pour changer la valeur du <emphasis>TTL</emphasis> (de 0 à 255), mettez cette valeur dans une variable (ici nommée « ttl ») et écrivez dans votre programme : </para> <programlisting> u_char ttl; setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); </programlisting> <para> Le comportement avec <emphasis>getsockopt()</emphasis> est similaire à celui vu avec <emphasis>IP_MULTICAST_LOOP</emphasis>. </para> </sect2> <sect2> <title>IP_MULTICAST_IF</title> <para> Traditionnellement, l'administrateur système indique l'interface multicast par défaut sur laquelle les datagrammes sont envoyés. Le programmeur peut surcharger cela et choisir ainsi à l'aide de cette option une interface de sortie concrête pour une prise réseau donnée. </para> <programlisting> struct in_addr interface_addr; setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr)); </programlisting> <para> Ainsi, tout le trafic multicast généré par cette prise réseau sera envoyé sur l'interface choisie. Pour revenir au comportement par défaut et laisser le noyau choisir l'interface de sortie (choix basé sur la configuration de l'administrateur système), il suffit d'appeler <emphasis>setsockopt()</emphasis> avec la même option et <emphasis>INADDR_ANY</emphasis> comme valeur pour l'interface. </para> <para> Pour connaitre ou sélectionner une interface de sortie, les <emphasis>ioctls</emphasis> suivants peuvent être utililisés : <emphasis>SIOCGIFADDR</emphasis> (pour obtenir les adresses des interfaces), <emphasis>SIOCGIFCONF</emphasis> (pour obtenir la liste de toutes les interfaces) et <emphasis>SIOCGIFFLAGS</emphasis> (pour obtenir les fonctionnalités d'une interface et, de fait, permet de déterminer si l'interface supporte le multicast ou non. Fonction indiquée par l'option <emphasis>IFF_MULTICAST</emphasis>). </para> <para> Si un hôte a plus d'une interface et que l'option <emphasis>IP_MULTICAST_IF</emphasis> n'est pas mentionnée, alors les transmissions multicast sont émises sur l'interface par défaut, bien que les interfaces restantes puissent être utilisées pour des retransmissions multicast si l'hôte joue le rôle de routeur multicast. </para> </sect2> <sect2 id="IP-ADD-MEMBERSHIP" xreflabel="section IP_ADD_MEMBERSHIP"> <title>IP_ADD_MEMBERSHIP</title> <para> Rappelez vous que vous devez informer le noyau des groupes multicast qui vous intéressent. Si aucun processus n'est intéressé par un groupe donné, les paquets provenant de ce groupe et qui arrivent sur notre hôte sont rejetés. Pour informer le noyau, des groupes qui vous intéressent, et de fait, pour devenir membre de ce groupe, vous devez d'abord remplir une structure <emphasis>ip_mreq</emphasis> qui sera passée plus tard au noyau dans le champ <emphasis>optval</emphasis> avec l'appel système <emphasis>setsockopt()</emphasis>. </para> <para> La structure <emphasis>ip_mreq</emphasis> (provenant de /usr/include/linux/in.h) a les membres suivants : </para> <programlisting> struct ip_mreq { struct in_addr imr_multiaddr; /* adresse IP du groupe multicast */ struct in_addr imr_interface; /* adresse IP de l'interface locale */ }; </programlisting> <para> Note : la définition « physique » de la structure est contenue dans le fichier spécifié ci-dessus. Vous ne devez en aucun cas inclure <linux/in.h> si vous souhaitez que votre code soit portable. En lieu et place, incluez <netinet/in.h>, qui inclut à son tour <linux/in.h>. </para> <para> Le premier membre, <emphasis>imr_multiaddr</emphasis>, contient l'adresse du groupe que vous désirez joindre. Souvenez-vous que l'appartenance à un groupe se fait aussi par le biais d'une interface, pas uniquement sur l'adresse du groupe. C'est la raison pour laquelle vous devez fournir une valeur au second membre : <emphasis>imr_interface</emphasis>. De cette façon, si vous êtes sur un hôte ayant plusieurs interfaces multicast, vous pouvez joindre un même groupe par le biais de différentes interfaces. Si vous ne désirez pas indiquer d'interface, vous pouvez toujours remplir ce dernier membre avec un joker (<emphasis>INADDR_ANY</emphasis>), alors le noyau choisira de lui même l'interface. </para> <para> Une fois la structure remplie (définie en tant que <emphasis>struct ip_mreq mreq;</emphasis>) vous avez juste à appeler <emphasis>setsockopt()</emphasis> de cette manière : </para> <programlisting> setsockopt (socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); </programlisting> <para> Notez que vous pouvez joindre plusieurs groupes à travers la même prise réseau. Cette limite supérieure est fixée par <emphasis>IP_MAX_MEMBERSHIPS</emphasis> et, a pour la version 2.0.33 du noyau Linux, la valeur de 20. </para> </sect2> <sect2> <title>IP_DROP_MEMBERSHIP</title> <para> La procédure nécessaire pour quitter un groupe est semblable à celle nécessaire pour le joindre. </para> <programlisting> struct ip_mreq mreq; setsockopt (socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); </programlisting> <para> Où <emphasis>mreq</emphasis> est une structure contenant les mêmes données que celles utilisées lorsque ce groupe fût joint. Si le membre <emphasis>imr_interface</emphasis> contient la valeur <emphasis>INADDR_ANY</emphasis>, alors le premier groupe pouvant correspondre est supprimé. </para> <para> Si vous avez rejoint un grand nombre de groupes sur une même prise réseau, il n'est pas nécessaire de supprimer toutes les souscriptions pour terminer. Lorsque vous fermez une prise réseau, toutes les souscriptions associées à cette prise sont supprimées par le noyau. Il en est de même si le processus qui a ouvert la prise est tué. </para> <para> Cependant, gardez à l'esprit que si un processus abandonne la souscription à un groupe, cela n'implique pas forcément l'arrêt de la transmission des datagrammes du groupe en question à l'hôte. En effet, si une autre prise a joint ce groupe avec la même interface avant le <emphasis>IP_DROP_MEMBERSHIP</emphasis>, alors l'hôte continuera à être membre de ce groupe. </para> <para> <emphasis>ADD_MEMBERSHIP</emphasis> (aussi bien que <emphasis>DROP_MEMBERSHIP</emphasis>) est une opération non-bloquante. Il renvoie un résultat, immédiatement, indiquant s'il a réussi ou échoué. </para> </sect2> </sect1> <sect1> <title>Fonctionnement interne</title> <para> Ce chapitre délivre des informations, qui ne sont ni nécessaires à la compréhension du fonctionnement du multicast, ni nécessaires à l'écriture de programmes multicast, mais qui deumeurent cependant très intéressantes car elles permettent une compréhension des concepts sur lesquels s'appuient le multicast et ses implémentations. Cela permet ainsi de contourner les erreurs les plus fréquentes et de nombreuses incompréhensions. </para> <sect2> <title>IGMP</title> <para> Lorsque nous avons parlé de <emphasis>IP_ADD_MEMBERSHIP</emphasis> et de <emphasis>IP_DROP_MEMBERSHIP</emphasis>, nous avions dit que l'information délivrée était utilisée par le noyau pour accepter ou refuser les datagrammes multicast. Cela est vrai mais pas complêtement. Une telle simplification impliquerait que les datagrammes multicast de tous les groupes multicast à travers le monde seraient reçus par notre hôte, et alors il vérifierait les souscriptions des processus s'exécutant sur lui et déciderait s'il délivre l'information ou non. Comme vous pouvez l'imaginer, cela serait du gaspillage de bande passante. </para> <para> De fait actuellement, un hôte informe son routeur des groupes multicasts qui l'intéressent ; alors, ce routeur informe à son tour les routeurs en amont qu'il souhaite recevoir le trafic en question, et ainsi de suite. Les algorithmes employés servant à demander le trafic d'un groupe donné, ou à l'inverse ceux pour terminer une souscription, peuvent varier. Cependant, il y a quelque chose qui ne change jamais : la manière dont cette information est transmisse. IGMP est utilisé pour cela. IGMP signifie Internet Group Management Protocol. C'est un protocole similaire par de nombreux aspects à ICMP. Il porte un numéro de protocole égal à 2 et ses messages sont transportés dans des datagrammes IP. Tous les hôtes compatibles multicast niveau 2 doivent implémenter ce protocole. </para> <para> Comme dit précédemment, IGMP est utilisé aussi bien par les hôtes pour donner des informations de souscription à ses routeurs, que par les routeurs pour communiquer entre eux. Par la suite, il ne sera question que des relations entre les hôtes et les routeurs, principalement parce que les informations décrivant les communications entre routeurs (autres que celles provenant du source code de mrouted, RFC-1075) et décrivant le protocole de routage multicast « distance-vecteur » sont maintenant obsolètes. mrouted implémente quant à lui une version de ce protocole non encore documentée. </para> <para> La version 0 d'IGMP est spécifiée dans le RFC-988 qui est maintenant obsolète. Plus personne n'utilise la version 0 de nos jours. </para> <para> La version 1 d'IGMP est décrite dans le RFC-1112 et, bien qu'elle soit mise-à-jour par le RFC-2236 (IGMP version 2), elle est encore largement utilisée. </para> <para> Le noyau Linux implémente complètement IGMP version 1 et en partie la version 2. </para> <para> Vous trouverez ci-dessous une description informelle du protocole. Vous pouvez consulter le RFC-2236 pour une description formelle, avec beaucoup de diagrammes d'états et d'expiration de délais. </para> <para> Tous les messages IGMP ont la structure suivante : </para> <para> <informaltable> <tgroup cols="32" colsep="1" rowsep="1"> <colspec colname="col0" align="center"/> <colspec colname="col1" align="center"/> <colspec colname="col2" align="center"/> <colspec colname="col3" align="center"/> <colspec colname="col4" align="center"/> <colspec colname="col5" align="center"/> <colspec colname="col6" align="center"/> <colspec colname="col7" align="center"/> <colspec colname="col8" align="center"/> <colspec colname="col9" align="center"/> <colspec colname="col10" align="center"/> <colspec colname="col11" align="center"/> <colspec colname="col12" align="center"/> <colspec colname="col13" align="center"/> <colspec colname="col14" align="center"/> <colspec colname="col15" align="center"/> <colspec colname="col16" align="center"/> <colspec colname="col17" align="center"/> <colspec colname="col18" align="center"/> <colspec colname="col19" align="center"/> <colspec colname="col20" align="center"/> <colspec colname="col21" align="center"/> <colspec colname="col22" align="center"/> <colspec colname="col23" align="center"/> <colspec colname="col24" align="center"/> <colspec colname="col25" align="center"/> <colspec colname="col26" align="center"/> <colspec colname="col27" align="center"/> <colspec colname="col28" align="center"/> <colspec colname="col29" align="center"/> <colspec colname="col30" align="center"/> <colspec colname="col31" align="center"/> <tbody> <row> <entry align="center" valign="top"><para>0</para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para>1</para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para>2</para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para></para></entry> <entry align="center" valign="top"><para>3</para></entry> <entry align="center" valign="top"><para></para></entry> </row> <row> <entry align="center" valign="top"><para>0</para></entry> <entry align="center" valign="top"><para>1</para></entry> <entry align="center" valign="top"><para>2</para></entry> <entry align="center" valign="top"><para>3</para></entry> <entry align="center" valign="top"><para>4</para></entry> <entry align="center" valign="top"><para>5</para></entry> <entry align="center" valign="top"><para>6</para></entry> <entry align="center" valign="top"><para>7</para></entry> <entry align="center" valign="top"><para>8</para></entry> <entry align="center" valign="top"><para>9</para></entry> <entry align="center" valign="top"><para>0</para></entry> <entry align="center" valign="top"><para>1</para></entry> <entry align="center" valign="top"><para>2</para></entry> <entry align="center" valign="top"><para>3</para></entry> <entry align="center" valign="top"><para>4</para></entry> <entry align="center" valign="top"><para>5</para></entry> <entry align="center" valign="top"><para>6</para></entry> <entry align="center" valign="top"><para>7</para></entry> <entry align="center" valign="top"><para>8</para></entry> <entry align="center" valign="top"><para>9</para></entry> <entry align="center" valign="top"><para>0</para></entry> <entry align="center" valign="top"><para>1</para></entry> <entry align="center" valign="top"><para>2</para></entry> <entry align="center" valign="top"><para>3</para></entry> <entry align="center" valign="top"><para>4</para></entry> <entry align="center" valign="top"><para>5</para></entry> <entry align="center" valign="top"><para>6</para></entry> <entry align="center" valign="top"><para>7</para></entry> <entry align="center" valign="top"><para>8</para></entry> <entry align="center" valign="top"><para>9</para></entry> <entry align="center" valign="top"><para>0</para></entry> <entry align="center" valign="top"><para>1</para></entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col7"> Type </entry> <entry align="center" valign="top" namest="col8" nameend="col15"> Temp max. de réponse </entry> <entry align="center" valign="top" namest="col16" nameend="col31"> contrôle d'intégrité </entry> </row> <row> <entry align="center" valign="top" namest="col0" nameend="col31"> Adresse de groupe </entry> </row> </tbody> </tgroup> </informaltable> </para> <para> Dans le cas d'IGMP version 1 (appelé ci-après IGMPv1) le champ « temp maximum de réponse » est marqué comme « inutilisé ». Il est rempli de zéros lors d'une émission et est ignoré à la réception. De plus, cette version d'IGMP coupe le champ « type » en deux sous champs de longueur 4 bits : « version » et « type ». Comme IGMPv1 identifie un message d'<emphasis>interrogation de souscription</emphasis> comme étant 0x11 (version 1, type 1) et IGMPv2 aussi, les 8 bits ont la même signification. </para> <para> Je pense qu'il est plus instructif de donner d'abord une description d'IGMPv1 et de pointer ensuite les additions faites par IGMPv2. </para> <para> À la lecture de la description faite ci-dessous, gardez à l'esprit qu'un routeur multicast reçoit <emphasis>tous</emphasis> les datagrammes IP multicast. </para> <sect3 id="IGMP-version-1" xreflabel="section IGMP version 1"> <title>IGMP version 1</title> <para> Les routeurs émettent périodiquement des requêtes IGMP sur les souscriptions des hôtes (IGMP Host Membership Queries). Ces requêtes sont faites sur le groupe <emphasis>all-hosts</emphasis> (224.0.0.1) avec un TTL de 1, ceci toutes les 1 ou 2 minutes. Tous les hôtes supportant le multicast entendent cela, mais ne répondent pas immédiatement pour éviter une tempête de réponses. Au lieu de cela, ils déclenchent un compte à rebours pour chaque groupe auquel ils appartiennent, et cela sur l'interface sur laquelle ils ont reçu la demande. </para> <para> Tôt ou tard, le compte à rebours expirera sur un des hôtes, ce dernier envoiera alors un <emphasis>IGMP Host Membership Report</emphasis> (résultat d'appartenance) avec un TTL de 1 à l'adresse multicast du groupe devant être rapporté. Comme le résultat est envoyé au groupe, tous les hôtes qui ont rejoint ce dernier -et qui sont actuellement en train d'attendre que leur propre délai expire- le recoive aussi. Alors, ces hôtes stoppent leur compte à rebours, et ne génèrent pas d'autres rapports. Un seul rapport est généré - par l'hôte ayant le délai le plus court-, et cela est suffisant pour le routeur. Celui-ci doit seulement savoir s'il y a des membres de ce groupe dans le sous réseau, pas qui et combien ils sont. </para> <para> Lorsqu'aucune réponse n'est reçue pour un groupe donné après un certain nombre de requêtes, le routeur déduit qu'il n'y a pas de membre de ce groupe sur ce sous réseau, et de ce fait n'a pas à transmettre le trafic. Notez que pour IGMPv1 il n'y a pas de message de fin d'appartenance de groupe. </para> <para> Lorsqu'un hôte rejoint un <emphasis>nouveau</emphasis> groupe, le noyau envoie un rapport concernant ce groupe, ainsi il n'est pas nécessaire d'attendre une ou deux minutes jusqu'a ce que la demande d'appartenance suivante soit formulée. Comme vous pouvez le constater le paquet IGMP est généré par le noyau comme étant une réponse à la commande <emphasis>IP_ADD_MEMBERSHIP</emphasis>, comme vu dans la <xref linkend="IP-ADD-MEMBERSHIP"/>. Notez l'importance de l'adjectif <emphasis>nouveau</emphasis> : si la commande <emphasis>IP_ADD_MEMBERSHIP</emphasis> est effectuée sur un hôte déjà membre de ce groupe, aucun paquet IGMP n'est envoyé car nous recevons déjà le trafic pour ce groupe ; à la place, un compteur sur le nombre d'utilisateurs de ce groupe est incrémenté. <emphasis>IP_DROP_MEMBERSHIP</emphasis> ne génère aucun datagramme dans IGMPv1. </para> <para> Les requêtes sur les souscriptions des hôtes sont identifiées par le type 0x11, et les rapports d'appartenance par le type 0x12. </para> <para> Aucun rapport n'est envoyé pour le groupe <emphasis>all-hosts</emphasis>. L'appartenance à ce dernier groupe est permanente. </para> </sect3> <sect3> <title>IGMP version 2</title> <para> L'ajout majeur dans cette version du protocole est l'inclusion de messages de fin d'appartenance de groupe (<emphasis>Leave Group message</emphasis>) noté 0x17. La raison de cet ajout est d'éviter un gaspillage de bande passante entre le moment où le dernier hôte du sous-réseau quitte ses souscriptions et le moment où le routeur s'aperçoit qu'il n'y a plus de membre de ce groupe présent dans ce sous réseau (<emphasis>leave latency</emphasis>). Les messages de fin d'appartenance doivent être adressés au groupe <emphasis>all-routers</emphasis> (224.0.0.2) plus qu'au groupe que l'on vient de quitter, car l'information n'a pas d'utilité pour les autres membres de ce groupe (les versions du noyau ultérieures à 2.0.33 envoyent l'information au groupe ; et bien que cela ne porte pas préjudice aux hôtes, cela constitue une perte de temps car ces messages doivent êtres traités, sans pour autant donner d'information utile). Il est à noter qu'il existe certains détails subtiles à propos du moment où il est approprié ou non d'envoyer des Messages de fin d'appartenance ; si cela vous intéresse, reportez-vous au RFC. </para> <para> Quant un router IGMPv2 reçoit un message de fin d'appartenance de groupe, il envoie une requête « spécifique de groupe » (<emphasis>Group-Specific Queries</emphasis>) au groupe à quitter. Cela contitue un autre ajout. IGMPv1 n'a pas ces requêtes spécifiques de groupes. Toutes ces requêtes sont envoyées au groupe <emphasis>all-hosts</emphasis>. Le champ <emphasis>type</emphasis> de l'entête IGMP n'est pas amené à changer (0x11 comme précédemment), mais le champ « adresse du groupe » est rempli avec l'adresse du groupe multicast à quitter. </para> <para> Le champ <emphasis>Temps Maximum de Réponse</emphasis>, qui dans IGMPv1 était mis à 0 pour la transmission et ignoré à la réception, devient significatif seulement dans les messages de requêtes en appartenance (ou Membership Query). Ce champ informe du temps maximum alloué en 1/10 de secondes avant l'envoi d'un rapport. Il est donc utilisé comme mécanisme d'écoute. </para> <para> IGMPv2 introduit un nouveau type de message : 0x16. Il s'agit d'un « rapport d'appartence IGMPv2 » envoyé par les hôtes IGMPv2 si ceux-ci détectent qu'un routeur IGMPv2 est présent (un hôte IGMPv2 sait qu'un routeur IGMPv1 est présent s'il reçoit une requête avec le champ « Réponse Max » à 0). </para> <para> Lorsque plus d'un routeur se réclame comme agissant en interrogateur, IGMPv2 fournit un mécanisme pour écourter les discussions : le routeur possédant la plus petite adresse IP est désigné comme étant l'interrogateur. Les autres routeurs restent à l'écoute d'éventuels dépassements de temps de réponse. Ainsi, si le routeur ayant la plus petite adresse IP « tombe » ou est éteint, la décision pour connaitre le nouvel interrogateur est prise après que les délais aient expiré. </para> </sect3> </sect2> <sect2> <title>Aspects concernant le noyau</title> <para> Cette sous-section donne le point de départ de l'étude de l'implémentation du multicast dans le noyau Linux. Cela n'explique pas l'implémentation faite. Elle indique juste où trouver les éléments. </para> <para> L'étude a été menée sur la version 2.0.32, de ce fait il se peut qu'elle soit dépassée au moment où vous allez la lire (le code réseau du noyau semble avoir beaucoup changé dans les versions 2.1.x). </para> <para> Le code multicast dans les noyaux Linux est toujours entouré par une paire de balises #ifdef CONFIG_IP_MULTICAST / #endif, de cette façon vous pouvez l'inclure ou l'exclure de votre noyau selon vos besoins (cette inclusion/exclusion est faite à l'étape de compilation, comme vous le savez probablement… Les #ifdefs sont interprétés par le pré-processeur. La décision est prise selon les choix que vous avez effectués lors du make config, make menuconfig ou make xconfig). </para> <para> Vous désirez probablement activer les fonctionnalités multicast, mais si votre machine Linux n'a pas à se comporter comme un routeur multicast, vous n'aurez sûrement pas besoin d'activer le routage multicast du noyau. Le code concernant le routage multicast est contenu entre la paire de balises #ifdef CONFIG_IP_MROUTE / #endif. </para> <para> Les sources du noyau sont couramment placées dans le répertoire /usr/src/linux. Cependant, l'emplacement peut changer, de ce fait l'emplacement du répertoire de base des sources du noyau sera designé ici comme étant LINUX. De ce fait, LINUX/net/ipv4/udp.c correspond à /usr/src/linux/net/ipv4/udp.c si vous avez extrait les sources du noyau dans le répertoire /usr/src/linux. </para> <para> Toutes les interfaces multicast désignées dans cette section et dédiées à la programmation d'applications multicast, s'utilisent au travers des appels systèmes <emphasis>setsockopt() / getsockopt()</emphasis>. </para> <para> L'un comme l'autre est implémenté au moyen de fonctions qui effectuent quelques tests pour vérifier les paramètres qui leurs sont passés et qui, à tour de rôle, appellent une autre fonction qui effectue quelques tests complémentaires, démultiplexant l'appel passé dans le paramètre <emphasis>level</emphasis> pour chaque appel système, et appelle alors une autre fonction qui… (si vous êtes intéressé par tous ces sauts, vous pouvez les suivre dans LINUX/net/socket.c (fonctions <emphasis>sys_socketcall()</emphasis> et <emphasis>sys_setsockopt()</emphasis>), LINUX/net/ipv4/af_inet.c (fonction <emphasis>inet_setsockopt()</emphasis>) et LINUX/net/ipv4/ip_sockglue.c (fonction <emphasis>ip_setsockopt()</emphasis>)). </para> <para> Le fichier qui nous intéresse ici est LINUX/net/ipv4/ip_sockglue.c. Nous y trouvons <emphasis>ip_setsockopt()</emphasis> et <emphasis>ip_getsockopt()</emphasis> qui sont essentiellement des switchs (après quelques vérifications d'erreurs) vérifiant chaque valeur possible pour <emphasis>optname</emphasis>. Tout comme les options unicast, les options multicast sont capturées : <emphasis>IP_MULTICAST_TTL</emphasis>, <emphasis>IP_MULTICAST_LOOP</emphasis>, <emphasis>IP_MULTICAST_IF</emphasis>, <emphasis>IP_ADD_MEMBERSHIP</emphasis> et <emphasis>IP_DROP_MEMBERSHIP</emphasis>. Avant le switch, un test est fait pour savoir si les options sont spécifiques au routeur multicast, et dans ce cas, elles sont redirigées vers les fonctions <emphasis>ip_mroute_setsockopt()</emphasis> et <emphasis>ip_mroute_getsockopt()</emphasis> (fichier LINUX/net/ipv4/ipmr.c). </para> <para> Dans le fichier LINUX/net/ipv4/af_inet.c nous pouvons voir les valeurs par défaut -dont nous parlions dans les sections précédentes (loopback activé, TTL=1)- données à la prise réseau lorsqu'elle est crée (prises depuis la fonction <emphasis>inet_create()</emphasis> de ce fichier) : </para> <programlisting> #ifdef CONFIG_IP_MULTICAST sk->ip_mc_loop=1; sk->ip_mc_ttl=1; *sk->ip_mc_name=0; sk->ip_mc_list=NULL; #endif </programlisting> <para> L'assertion stipulant que « la fermeture d'une prise réseau implique que le noyau n'accepte plus les souscriptions faites par cette prise » est corroborée par : </para> <programlisting> #ifdef CONFIG_IP_MULTICAST /* Les applications oublient de quitter les groupes avant de partir */ ip_mc_drop_socket(sk); #endif </programlisting> <para> Extrait de la fonction <emphasis>inet_release()</emphasis>, dans le même fichier que précédemment. </para> <para> Les opérations indépendantes de la couche de liaison et relatives aux périphériques sont gardées dans le fichier LINUX/net/core/dev_mcast.c. </para> <para> Deux fonctions sont encore manquantes : les fonctions concernant le traîtement des paquets multicast en entrée et en sortie. Comme tous les autres paquets, les paquets entrants sont transmis depuis les pilotes de périphériques à la fonction <emphasis>ip_rcv()</emphasis> (LINUX/net/ipv4/ip_input.c). Cette fonction contient le filtrage parfait appliqué aux paquets multicasts qui ont passé la couche du périphérique (souvenez-vous que les couches les plus basses ne fournissent qu'un filtrage approximatif et ce n'est que la couche IP qui sait à 100% si nous sommes intéressés ou non par ce groupe multicast). Si l'hôte fonctionne comme un routeur multicast, alors la fonction décide aussi si le paquet doit être transmis. Il appelle alors <emphasis>ipmr_forward()</emphasis>. Cette dernière fonction est implémentée dans le fichier LINUX/net/ipv4/ipmr.c. </para> <para> Le code se chargeant des paquets émis en sortie est contenu dans le fichier LINUX/net/ipv4/ip_output.c. On y trouve l'effet possible de l'option des <emphasis>IP_MULTICAST_LOOP</emphasis>, selon que l'on souhaite ou non faire une boucle locale (fonction <emphasis>ip_queue_xmit()</emphasis>). Ainsi la valeur du <emphasis>TTL</emphasis> du paquet sortant est donné selon qu'il s'agit d'un paquet unicast ou multicast. Dans ce dernier cas, la valeur de l'argument <emphasis>IP_MULTICAST_TTL</emphasis> passé en option est utilisée (fonction <emphasis>ip_build_xmit()</emphasis>). </para> <para> Durant un travail à l'aide de mrouted (un programme fournissant des informations liées au noyau sur la façon de router des datagrammes multicast), nous avons détecté que les paquets multicast provenant du réseau local sont routés correctement exceptés ceux venant de la machine Linux agissant en tant que routeur multicast ! ip_input.c fonctionne bien, mais il semble que ce n'est pas le cas de ip_output.c. En lisant le code source des fonctions de sorties, nous avons trouvé que les paquets sortant n'étaient pas passés à <emphasis>ipmr_forward()</emphasis>, fonction décidant si les paquets doivent être routés ou non. Les paquets sont sortis sur le réseau local mais, comme les cartes réseaux sont le plus souvent incapables de lire les données transmises, ces datagrammes ne sont alors jamais routés. Nous avons ajouté le code nécessaire à la fonction ip_build_xmit() et le tour était joué. (Disposer du code source du noyau n'est pas un luxe, mais une nécessité !) </para> <para> <emphasis>ipmr_forward()</emphasis> a déjà été mentionné un certain nombre de fois. C'est une fonction importante car elle permet de résoudre un important problème de compréhension nécessitant d'être plus largement expliqué. En routant du trafic multicast, ce n'est pas mrouted qui fabrique les copies puis les expédie à ses propres destinataires. mrouted reçoit tout le trafic multicast et, basé sur cette information, calcule les tables de routages multicast puis informe le noyau de la manière de router : « les datagrammes pour ce groupe provenant de cette interface doivent être transférés à ces interfaces ». Cette information est transmise au noyau par l'appel de <emphasis>setsockopt()</emphasis> sur la file d'une prise réseau ouverte par le daemon mrouted (le protocole spécifié lors de la création de la file de la prise réseau doit être <emphasis>IPPROTO_IGMP</emphasis>). La prise en compte d'options s'effectue par l'appel à la fonction <emphasis>ip_mroute_setsockopt()</emphasis> de LINUX/net/ipv4/ipmr.c. Cette première option (il est préférable de les appeler commandes plutôt qu'options) provenant de cette prise réseau doit être <emphasis>MRT_INIT</emphasis>. Toutes les autres commandes sont ignorées (retournant <emphasis>-EACCES</emphasis>) si <emphasis>MRT_INIT</emphasis> n'est pas précisé en premier. Seulement une seule instance de mrouted peut être exécutée à la fois sur un même hôte. Pour garder une trace de cela, lorsque le premier <emphasis>MRT_INIT</emphasis> est reçu, une variable importante, <emphasis>struct sock* mroute_socket</emphasis>, est pointée sur la prise réseau ou le <emphasis>MRT_INIT</emphasis> a été reçu. Si <emphasis>mroute_socket</emphasis> n'est pas nul lors de l'attente d'un <emphasis>MRT_INIT</emphasis> cela signifie qu'un autre mrouted est en cours d'exécution, un <emphasis>-EADDRINUSE</emphasis> est alors renvoyé. Toutes les commandes s'appuyant sur le même principe (<emphasis>MRT_DONE</emphasis>, <emphasis>MRT_ADD_VIF</emphasis>, <emphasis>MRT_DEL_VIF</emphasis>, <emphasis>MRT_ADD_MFC</emphasis>, <emphasis>MRT_DEL_MFC</emphasis> et <emphasis>MRT_ASSERT</emphasis>) retournent <emphasis>-EACCES</emphasis> si elles proviennent d'une prise réseau différente de <emphasis>mroute_socket</emphasis>. </para> <para> Comme les datagrammes multicast routés peuvent être reçus/envoyés au travers d'interfaces physiques ou de tunnels, une abstraction commune a été définie : les VIFs, InterFaces Virtuelles (ou Virtual InterFaces). mrouted communique les structures VIFs au noyau, en indiquant les interfaces physiques ou tunnels pour qu'il les ajoute à sa table de routage. Les entrées de retransmissions multicast indiquent où transmettre les datagrammes. </para> <para> Les VIFs sont ajoutées à l'aide de <emphasis>MRT_ADD_VIF</emphasis> et supprimées avec <emphasis>MRT_DEL_VIF</emphasis>. L'un comme l'autre passent un struct vifctl au noyau (défini dans /usr/include/linux/mroute.h) avec les informations suivantes : </para> <programlisting> struct vifctl { vifi_t vifc_vifi; /* Index du VIF */ unsigned char vifc_flags; /* Attributs VIFF_ */ unsigned char vifc_threshold; /* Seuil du ttl */ unsigned int vifc_rate_limit; /* Valeur de débit limite : non implémenté */ struct in_addr vifc_lcl_addr; /* Notre adresse */ struct in_addr vifc_rmt_addr; /* Adresse du tunnel IPIP */ }; </programlisting> <para> Avec cette information une structure <emphasis>vif_device</emphasis> est construite : </para> <programlisting> struct vif_device { struct device *dev; /* le périphérique que nous utilisons */ struct route *rt_cache; /* Tunnel route cache */ unsigned long bytes_in,bytes_out; unsigned long pkt_in,pkt_out; /* Statistiques */ unsigned long rate_limit; /* Forme du trafic ; non implémenté */ unsigned char threshold; /* seuil du TTL */ unsigned short flags; /* attributs de contrôle */ unsigned long local,remote; /* Adresses(distantes pour les tunnels)*/ }; </programlisting> <para> Notez l'entrée <emphasis>dev</emphasis> dans la structure. La structure <emphasis>device</emphasis> est définie dans le fichier /usr/include/linux/netdevice.h. C'est une grosse structure, mais le champ qui nous intéresse est : </para> <programlisting> struct ip_mc_list* ip_mc_list; /* chaîne des filtres IP multicast */ </programlisting> <para> La structure <emphasis>ip_mc_list</emphasis> -définie dans /usr/include/linux/igmp.h- est comme suit : </para> <programlisting> struct ip_mc_list { struct device *interface; unsigned long multiaddr; struct ip_mc_list *next; struct timer_list timer; short tm_running; short reporter; int users; }; </programlisting> <para> Ainsi, le membre <emphasis>ip_mc_list</emphasis> de la structure <emphasis>dev</emphasis> est un pointeur sur une liste chaînée de structures <emphasis>ip_mc_list</emphasis>, chacune contenant une entrée pour chaque groupe multicast pour laquelle l'interface est membre. Ici nous voyons une fois de plus que les appartenances sont associées à des interfaces. LINUX/net/ipv4/ip_input.c parcourt cette liste chaînée pour décider si le datagramme reçu est destiné à un groupe auquel l'interface appartient : </para> <programlisting> #ifdef CONFIG_IP_MULTICAST if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK)) { /* * Verification de l'appartenance à un de nos groupes */ struct ip_mc_list *ip_mc=dev->ip_mc_list; do { if(ip_mc==NULL) { kfree_skb(skb, FREE_WRITE); return 0; } if(ip_mc->multiaddr==iph->daddr) break; ip_mc=ip_mc->next; } while(1); } #endif </programlisting> <para> Le champ <emphasis>users</emphasis> de la strucuture <emphasis>ip_mc_list</emphasis> est utilisé pour implémenter ce que nous avons dit dans la <xref linkend="IGMP-version-1"/> : si un processus joint un groupe et que l'interface est déjà membre de ce groupe (ie, un autre processus joint le même groupe sur la même interface que précédemment) seul le compteur du nombre de membres (<emphasis>users</emphasis>) est incrémenté. Aucun message IGMP n'est envoyé, comme vous pouvez le voir dans le code suivant (extrait de <emphasis>ip_mc_inc_group()</emphasis>, appelé par <emphasis>ip_mc_join_group()</emphasis>, provenant du fichier LINUX/net/ipv4/igmp.c) : </para> <programlisting> for(i=dev->ip_mc_list;i!=NULL;i=i->next) { if(i->multiaddr==addr) { i->users++; return; } } </programlisting> <para> À chaque suppression d'une souscription de groupe, le compteur est décrémenté. Des opérations supplémentaires sont appliquées seulement si le compteur est devient égal à 0 (fonction <emphasis>ip_mc_dec_group()</emphasis>). </para> <para> <emphasis>MRT_ADD_MFC</emphasis> et <emphasis>MRT_DEL_MFC</emphasis> ajoutent ou suppriment des entrées de retransmission dans la table de routage multicast. L'un comme l'autre passent un <emphasis>struct mfcctl</emphasis> au noyau (défini dans /usr/include/linux/mroute.h) avec cette information : </para> <programlisting> struct mfcctl { struct in_addr mfcc_origin; /* Origine du mcast */ struct in_addr mfcc_mcastgrp; /* Groupe en question */ vifi_t mfcc_parent; /* Où cela arrive */ unsigned char mfcc_ttls[MAXVIFS]; /* Où cela va t-il */ }; </programlisting> <para> Avec toute cette information en main, <emphasis>ipmr_forward()</emphasis> parcourt les VIFs, et si une correspondance est trouvée, on duplique le datagramme et on appelle <emphasis>ipmr_queue_xmit()</emphasis> qui, à tour de rôle, utilise le périphérique de sortie indiqué par la table de routage et une adresse de destination propre si le paquet est à envoyer au travers d'un tunnel (il s'agit en fait de l'adresse de destination unicast de l'autre coté du tunnel). </para> <para> La fonction <emphasis>ip_rt_event()</emphasis> (qui n'est pas directement apparentée à la sortie des datagrammes, mais qui se trouve pourtant dans ip_output.c) reçoit les évènements relatifs aux périphériques réseaux, tel que le branchement du périphérique par exemple. Cette fonction assure que le périphérique joint bien le groupe multicast <emphasis>ALL-HOSTS</emphasis>. </para> <para> Les fonctions IGMP sont implémentées dans le fichier LINUX/net/ipv4/igmp.c. Les informations importantes concernant ces fonctions se trouvent dans /usr/include/linux/igmp.h et /usr/include/linux/mroute.h. L'entrée IGMP dans le répertoire /proc/net est créée à l'aide de la fonction <emphasis>ip_init()</emphasis> contenue dans le fichier LINUX/net/ipv4/ip_output.c. </para> </sect2> </sect1> <sect1 id="Politiques-de-routage" xreflabel="section politiques de routage et techniques de retransmission"> <title>Politiques de routage et techniques de retransmission</title> <para> Un algorithme trivial pour rendre le trafic multicast disponible partout est de l'envoyer… partout, sans se soucier des besoins des utilisateurs. Comme cela ne semble pas être bien optimisé, plusieurs algorithmes de routage et techniques de retransmission ont été implémentés. </para> <para> DVMRP (Distance Vector Multicast Routing Protocol, ou Protocole de routage multicast basé sur des vecteurs de distances) est, peut-être, le plus utilisé par les routeurs multicast de nos jours. Il s'agit d'un protocole de routage en mode dense, de fait, il convient bien dans les environnements à large bande passante et dont les membres sont densément distribués. Cependant, dans des scénarios moins denses, il souffre de problèmes de changement d'échelles. </para> <para> Il existe d'autres protocoles de routage denses, tels que MOSPF (Extentions multicast à OSPF -Open Shortest Path First) et PIM-DM (Protocol-Independent Multicast Dense Mode). </para> <para> Pour pouvoir faire du routage dans un environnement économe, il existe PIM-SM (Protocol Independent Multicast Sparse Mode) et CBT (Core Based Tree). </para> <para> OSPF version 2 est expliqué dans les RFC 1583, et MOSPF dans le RFC 1584. Les spécifications de PIM-SM et CBT peuvent être trouvées respectivement dans les RFC 2117 et 2201. </para> <para> Tous ces protocoles de routage utilisent différents types de retransmissions multicast, tels que le flooding (technique par indondation), RTB (ou Reverse Path Broadcasting), TRPB (ou Truncated Reverse Path Broadcasting), RPM (ou Reverse Path Multicasting) ou Shared Trees. </para> <para> Il serait trop long d'expliquer toutes ces techniques ici et, comme de courtes descriptions sont publiquement disponibles, je vous recommende la lecture du texte draft-ietf-mboned-in.txt. </para> <para> De même vous pouvez trouver les RFCs correspondants, expliquant en détails toutes les techniques et politiques employées. </para> </sect1> <sect1 id="Proto-transport-multicast" xreflabel="section Protocoles de transport multicast"> <title>Protocoles de transport multicast</title> <para> Jusqu'à présent nous avons parlé des transmissions multicast via UDP. Cela est une pratique courante, car il est impossible de faire de même avec TCP. Cependant, une recherche importante a lieu depuis un certain nombre d'années et dont le but est de développer de nouveaux protocoles de transport multicast. </para> <para> Plusieurs de ces protocoles ont été implémentés et testés. Une bonne leçon à tirer est qu'il ne semble pas y avoir de protocoles de transport multicast génériques et suffisament bons pour tous les types d'applications multicast. </para> <para> Si les protocoles de transports sont complexes et difficiles à optimiser, imaginez une façon de gérer les délais, la perte de données, l'ordonnancement, les retransmissions, le contrôle de flux et des congestions, le management des groupes, etc, lorsque le destinataire n'est pas unique, mais peut être constitué de centaines ou de milliers d'hôtes dispersés. Le changement d'échelle est donc un problème. De nouvelles techniques sont à implémenter, tel que ne pas délivrer des accusés de réception à chaque paquet reçu mais, à la place, envoyer des accusés de non-réception (negative acknowledges, ou NACKs) pour les données qui n'ont pas été reçues. Le RFC 1458 donne des propositions relatives aux conditions nécessaires à l'implémentation de tels protocoles multicasts. </para> <para> Donner la description de ces protocoles multicast sort de la portée de cette section. À la place, vous trouverez ci-dessous les noms de certains d'entre eux et quelques sources d'informations complémentaires : RTP, le protocole de transport temps-réel (ou Real-Time Transport Protocole) concerne les conférences multimédia multi-partite, SRM (Scalable Reliable Multicast) est utilisé par <emphasis>wb</emphasis> (l'outil servant de tableau blanc partagé, voyez la <xref linkend="Applications-multicast"/>), URGC (Uniform Reliable Group Communication Protocol) permet des transactions fiables et ordonnées -ce protocole est basé sur un contrôle centralisé-, Muse a été développé comme un protocole d'application spécifique au transfert de nouvelles (articles) au travers du MBone, le MFTP (Protocole Multicast de Transport de Fichiers, ou Multicast File Transport Protocol) se décrit de lui-même ; les personnes « joignent » un transfert de fichier (précédemment annoncé) de la même façon qu'ils joignent une conférence, LBRM (Log-Based Receiver-reliable Multicast) est un protocole curieux qui permet de garder une trace de tous les paquets envoyés par un serveur « loggant » ces derniers -ce serveur indique à l'émetteur s'il doit retransmettre les données ou s'il peut les supprimer proprement dans le cas où tous les destinataires ont bien reçu les données. Un protocole avec un drôle de nom -spécialement pour un protocole multicast- est STORM (STructure-Oriented Resilient Multicast). De nombreux protocoles multicast peuvent être trouvés en cherchant sur Internet, de même que d'intéressants papiers proposant de nouveaux champs d'applications au Multicast (par exemple, la distribution de pages web en multicast). </para> <para> Une bonne page fournissant des comparaisons entre les différents protocoles multicastes fiables est http://www.tascnets.com/mist/doc/mcpCompare.html. </para> <para> Un très bon site (à jour !), avec des liens intéressants (Internet drafts, RFCs, papiers, liens vers d'autres sites) est : http://research.ivv.nasa.gov/RMP/links.html. </para> <para> http://hill.lut.ac.uk/DS-Archive/MTP.html est aussi une bonne source d'informations sur ce sujet. </para> <para> L'article de Katia Obraczka « Multicast Transport Protocols: A Survey and Taxonomy » donne de courtes descriptions pour chaque protocole et essaye de les classifer selon diverses fonctionnalités. Vous pouvez le lire dans le magazine IEEE Communication, Janvier 1998, vol 36, No 1. </para> </sect1> <sect1> <title>Bibliographie</title> <sect2> <title>RFCs</title> <itemizedlist> <listitem> <para>RFC 1112 « Host Extensions for IP Multicasting ». Steve Deering. Août 1989.</para> </listitem> <listitem> <para>RFC 2236 « Internet Group Management Protocol, version 2 ». W. Fenner. Novembre 1997.</para> </listitem> <listitem> <para>RFC 1458 « Requirements for Multicast Protocols ». Braudes, R and Zabele, S. Mai 1993.</para> </listitem> <listitem> <para>RFC 1469 « IP Multicast over Token-Ring Local Area Networks ». T. Pusateri. Juin 1993.</para> </listitem> <listitem> <para>RFC 1390 « Transmission of IP and ARP over FDDI Networks ». D. Katz. Janvier 1993.</para> </listitem> <listitem> <para>RFC 1583 « OSPF Version 2 ». John Moy. Mai 1994.</para> </listitem> <listitem> <para>RFC 1584 « Multicast Extensions to OSPF ». John Moy. Mai 1994.</para> </listitem> <listitem> <para>RFC 1585 « MOSPF: Analysis and Experience ». John Moy. Mai 1994.</para> </listitem> <listitem> <para>RFC 1812 « Requirements for IP version 4 Routers ». Fred Baker, Editor. Juin 1995.</para> </listitem> <listitem> <para>RFC 2117 « Protocol Independent Multicast-Sparse Mode (PIM-SM): Protocol Specification ». D. Estrin, D. Farinacci, A. Helmy, D. Thaler; S. Deering, M. Handley, V. Jacobson, C. Liu, P. Sharma, and L. Wei. Juillet 1997.</para> </listitem> <listitem> <para>RFC 2189 « Core Based Trees (CBT version 2) Multicast Routing ». A. Ballardie. Septembre 1997.</para> </listitem> <listitem> <para>RFC 2201 « Core Based Trees (CBT) Multicast Routing Architecture ». A. Ballardie. Septembre 1997.</para> </listitem> </itemizedlist> </sect2> <sect2> <title>Brouillons Internet (Internet Drafts)</title> <itemizedlist> <listitem> <para>« Introduction to IP Multicast Routing ». draft-ietf-mboned-intro-multicast-03.txt. T. Maufer, C. Semeria. Juillet 1997</para> </listitem> <listitem> <para>« Administratively Scoped IP Multicast ». draft-ietf-mboned-admin-ip-space-03.txt. D. Meyer. 10 Juin 1997.</para> </listitem> </itemizedlist> </sect2> <sect2> <title>Pages web</title> <itemizedlist> <listitem><para> Page d'accueil du Multicast sous Linux. <ulink url="http://web.archive.org/web/20010209032950/http://www.cs.washington.edu/homes/esler/multicast/"/> </para></listitem> <listitem><para> Foire Aux Questions (FAQ) Multicast sous Linux. <ulink url="http://andrew.triumf.ca/pub/linux/multicast-FAQ"/> </para></listitem> <listitem><para> Multicast et MBONE sous Linux. <ulink url="http://web.archive.org/web/19990128143933/http://www.teksouth.com/linux/multicast/"/> </para></listitem> <!-- Page disparue sans laisser de traces :( <listitem><para> La page du MBONE-Linux selon Christian Daudt. <ulink url="http://www.microplex.com/˜csd/linux/mbone.html"/> </para></listitem> --> <listitem><para> Liens sur les protocoles multicast fiables <ulink url="http://www.nard.net/~tmont/rm-links.html"/> </para></listitem> <listitem><para> Protocoles de Transport Multicast <ulink url="http://web.archive.org/web/20020124084206/http://hill.lut.ac.uk/DS-Archive/MTP.html"/> </para></listitem> </itemizedlist> </sect2> <sect2> <title>Livres</title> <itemizedlist> <listitem> <para>« TCP/IP Illustrated: Volume 1 The Protocols ». Stevens, W. Richard. Addison Wesley Publishing Company, Reading MA, 1994</para> </listitem> <listitem> <para>« TCP/IP Illustrated: Volume 2, The Implementation ». Wright, Gary and W. Richard Stevens. Addison Wesley Publishing Company, Reading MA, 1995</para> </listitem> <listitem> <para>« UNIX Network Programming Volume 1. Networking APIs: Sockets and XTI ». Stevens, W. Richard. Second Edition, Prentice Hall, Inc. 1998.</para> </listitem> <listitem> <para>« Internetworking with TCP/IP Volume 1 Principles, Protocols, and Architecture ». Comer, Douglas E. Second Edition, Prentice Hall, Inc. Englewood Cliffs, New Jersey, 1991</para> </listitem> </itemizedlist> </sect2> </sect1> <sect1> <title>Licence et mise en garde</title> <para> Copyright © 1998 Juan-Mariano de Goyeneche pour la version originale. </para> <para> Copyright © 2003 Antoine Duval & Fabrice Gadaud pour la version française. </para> <para> Ce guide pratique est un document libre ; vous pouvez le redistribuer et le modifier selon les termes de la Licence publique générale GNU (GPL) telle que publiée par la Free Software Foundation, dans sa version 2, ou (a votre souhait) toute version ultérieure. </para> <para> Ce document est distribué dans l'espoir qu'il vous soit utile, mais sans aucune garantie ; sans même la garantie implicite de la valeur marchande ou de l'utilisation dans un but particulier. Consultez la Licence publique générale GNU (GPL) pour plus de détails. </para> <para> Vous pouvez obtenir une copie de cette licence en écrivant à la Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. </para> <para> Si vous publiez ce document sur un CD-ROM ou sous la forme d'une copie physique, une copie complémentaire sera la bienvenue ; envoyez-moi un courrier électronique (en anglais) à l'adresse <email>jmseyas CHEZ dit POINT upm POINT es</email>. N'hesitez pas non plus à faire une donation au Projet de documentation Linux (LDP) ou à la Free Software Foundation pour apporter votre soutien au projet de documentation libre pour Linux/GNU. Contactez le Projet de documentation Linux <email>feedback CHEZ en POINT tldp POINT org</email> pour plus d'informations. </para> </sect1> </article>