このページは大阪弁化フィルタによって翻訳生成されたんですわ。

翻訳前ページへ


Guide pratique du maintien de connexion TCP

Guide pratique du maintien de connexion TCP

Version fran?aise du TCP Keepalive HOWTO.

Laurent Gauthier

Adaptation fran?aise?

Eric Deschamps

Relecture de la version fran?aise?

Jean-Philippe Gu?rard

Pr?paration de la publication de la v.f.?

Version?: 1.0.fr.1.0

2007-05-04

Historique des versions
Version 1.0.fr.1.02008-05-02LG, ED, JPG
Premi?re adaptation fran?aise.
Version 1.02007-05-04FB
Premi?re ?dition, r?vis?e par TM.

R?sum?

Ce document d?crit l'impl?mentation du TCP keepalive dans le noyau linux, pr?sente le concept global et d?taille ? la fois la configuration syst?me et le d?veloppement d'application.


Table des mati?res

1. Introduction
1.1. Droits d'utilisation
1.2. Avertissement
1.3. Remerciements et contributions
1.4. Commentaires et corrections
1.5. Traductions
2. Aper?u de TCP keepalive
2.1. Qu'est-ce que TCP keepalive ?
2.2. Pourquoi utiliser TCP keepalive ?
2.3. V?rifier les h?tes injoignables
2.4. ?viter une d?connexion due ? une inactivit? r?seau.
3. Utiliser TCP keepalive sous Linux
3.1. Configurer le noyau
3.2. Rendre les modifications persistantes au red?marrage
4. Programmer des applications
4.1. Quand votre code requiert keepalive
4.2. L'appel de fonction setsockopt
4.3. Exemples de code
5. Impl?menter keepalive sur une application tierce
5.1. Modifier le code source
5.2. libkeepalive: pr?chargement de biblioth?que

Comprendre TCP keepalive n'est pas indispensable dans la plupart des cas, mais cela peut ?tre tr?s utile dans certaines circonstances. Il vous faudra poss?der quelques notions de base des r?seaux TCP/IP et de la programmation en langage C pour comprendre toutes les sections de ce document.

Le principal objectif de ce tutoriel (HOWTO) est de d?crire en d?tail le TCP keepalive et de pr?senter diff?rents cas d'application. Apr?s avoir d?but? avec un peu de th?orie, le propos se concentre sur l'impl?mentation des routines TCP keepalive dans les noyaux Linux actuels (2.4.x, 2.6.x), et sur les moyens dont les administrateurs syst?me peuvent tirer parti de ces routines, avec des exemples de configuration pr?cis et des astuces.

La seconde partie de ce tutoriel met en jeu l'interface de programmation propos?e par le noyau Linux, et le mode d'?criture des applications qui impl?mentent le TCP keepalive en langage C. Des exemples pratiques sont pr?sent?s, et une approche du projet libkeepalive est amorc?e, permettant aux applications de b?n?ficier par h?ritage du keepalive sans modification de code.

Afin de comprendre ce que fait TCP keepalive (que nous appellerons 'keepalive'), vous n'avez besoin que d'en lire le nom : keep TCP alive (maintenir TCP en vie), c'est ? dire conserver la connexion TCP. Cela signifie que vous serez en mesure de v?rifier l'?tat de votre socket de connexion (appel?e aussi socket TCP), et de d?terminer si la connexion est toujours ?tablie ou si elle est rompue.

Keepalive peut ?tre utilis? pour ?tre averti que l'h?te distant est mort avant qu'il soit capable de vous le notifier. Cela pourrait se produire en diff?rentes circonstances, une panique noyau ou une interruption soudaine du processus maintenant la connexion par exemple. Un autre cas justifiant keepalive pour d?tecter que l'h?te distant n'est pas joignable est la d?faillance du r?seau. Dans ce cas, si le r?seau n'est pas ? nouveau op?rationnel, vous ?tes dans la m?me situation que pour la mort de l'h?te distant. C'est dans ces cas de figure que les m?canismes TCP classiques ne permettent pas de s'assurer de l'?tat d'une connexion.

Songez ? une simple connexion TCP entre l'h?te A et l'h?te B: il y a la poign?e de main initiale en trois phases, le paquet SYN de A vers B, le SYN/ACK en retour de B vers A, et le ACK final de A vers B. A ce stade, nous sommes dans une situation stable : la connexion est ?tablie, et les donn?es peuvent donc ?tre envoy?es sur ce lien. Mais le probl?me survient : d?branchez l'alimentation de B et instantan?ment il s'?teint, sans rien envoyer sur le r?seau pour notifier A que la connexion va ?tre interrompue. A, de son c?t?, est pr?t ? envoyer des donn?es, et n'imagine pas que B est muet. Maintenant rebranchez l'alimentation de B et attendez que le syst?me red?marre. A et B sont de retour, mais A pr?sente une connexion toujours active vers B, alors que B l'ignore. La situation se r?sout d'elle-m?me lorsque A tente d'envoyer des donn?es ? B sur une connexion morte, et que B r?pond par un paquet RST, for?ant A ? finalement mettre fin ? la connexion.

Keepalive peut vous notifier quand un destinataire devient injoignable sans risque de faux positif. En fait, si le probl?me tient au r?seau entre les deux h?tes, le r?le du keepalive est d'attendre un temps pour tenter ? nouveau, adressant le paquet keepalive avant de notifier de la rupture du lien.

 _____                                                     _____
|     |                                                   |     |
|  A  |                                                   |  B  |
|_____|                                                   |_____|
   ^                                                         ^
   |--->--->--->-------------- SYN -------------->--->--->---|
   |---<---<---<------------ SYN/ACK ------------<---<---<---|
   |--->--->--->-------------- ACK -------------->--->--->---|
   |                                                         |
   |                                   le syst?me meurt ---> X
   |
   |                               le syst?me red?marre ---> ^
   |                                                         |
   |--->--->--->-------------- PSH -------------->--->--->---|
   |---<---<---<-------------- RST --------------<---<---<---|
   |                                                         |

L'autre objectif utile de keepalive est d'?viter que l'inactivit? ne provoque une d?connexion. C'est un cas fr?quent d'?tre d?connect? sans raison lorsque vous vous trouvez derri?re un proxy NAT ou un pare-feu. Ce comportement est d? aux proc?dures de surveillance des connexions des proxies et pare-feu, qui tiennent un inventaire des connexions qui les traverse. En raison des limites physiques de leurs ressources, ces machines ne peuvent conserver en m?moire qu'un nombre d?termin? de connexions. La r?gle la plus courante et la plus logique est de maintenir les connexions les plus r?centes et de mettre d'abord fin aux connexions les plus anciennes ou inactives.

Pour revenir ? nos h?tes A et B, reconnectons les. Une fois le lien ?tabli, attendons qu'un ?v?nement se produise pour le transmettre ? l'h?te distant. Qu'en est-il si cet ?v?nement se produit apr?s un long moment ? Notre connexion a sa propre dur?e, qui est inconnue du proxy. Lorsque nous finissons par transmettre des donn?es, le proxy n'est plus capable de les traiter correctement, et la connexion est rompue.

Puisque le fonctionnement normal est de mettre en t?te de liste la connexion par laquelle transitent des paquets, et de choisir la derni?re connexion de la file quand il faut en supprimer une, le fait d'envoyer p?riodiquement des paquets sur le r?seau est un bon moyen pour toujours rester en phase avec un risque minime de suppression.

 _____           _____                                     _____
|     |         |     |                                   |     |
|  A  |         | NAT |                                   |  B  |
|_____|         |_____|                                   |_____|
   ^               ^                                         ^
   |--->--->--->---|----------- SYN ------------->--->--->---|
   |---<---<---<---|--------- SYN/ACK -----------<---<---<---|
   |--->--->--->---|----------- ACK ------------->--->--->---|
   |               |                                         |
   |               | <--- connexion supprim?e de la table    |
   |               |                                         |
   |--->- PSH ->---| <--- connexion invalide                 |
   |               |                                         |

Linux int?gre nativement le keepalive. Vous devez activer le r?seau TCP/IP pour pouvoir l'utiliser. Vous avez aussi besoin du support de procfs et de sysctl pour pouvoir configurer les param?tre noyau au lancement.

Les fonctions impliquant keepalive utilisent trois variables manipul?es par l'utilisateur :

Rappelez-vous que le support du keepalive, m?me s'il est configur? dans le noyau, n'est pas le comportement par d?faut de Linux. Les programmes doivent requ?rir le contr?le du keepalive pour que ses sockets puissent utiliser l'interface setsockopt. Relativement peu de programmes impl?mentent keepalive, mais vous pouvez facilement ajouter le support du keepalive pour la plupart d'entre eux en suivant les instructions d?taill?es plus avant dans ce document.

Il existe deux moyens de configurer les param?tres keepalive du noyau au travers de commandes utilisateur:

Nous aborderons essentiellement comment proc?der au travers de l'interface procfs car elle est la plus utilis?e, recommand?e et la plus simple ? appr?hender. L'interface sysctl, particuli?rement sous l'aspect de l'appel syst?me (syscall) sysctl(2) et non de l'outil sysctl(8), n'est l? qu'? titre informatif.

Cette interface n?cessite quesysctl et procfs soient inclus au noayu, et que procfs soit mont? quelque part dans le syst?me de fichiers (habituellement /proc, comme dans l'exemple ci-dessous). Vous pouvez lire les valeurs des param?tres actuels en listant avec la commande ??cat?? les fichiers du r?pertoire /proc/sys/net/ipv4/ :

Les deux premiers param?tres sont exprim?s en secondes, et le dernier est un nombre simple. Cela signifie que les routines keepalive attendent deux heures (7200 secs) avant d'adresser la premi?re sonde keepalive, et en adressent une nouvelle toutes les 75 secondes. Si aucune r?ponse ACK n'est re?ue apr?s neuf tentatives cons?cutives, la connexion est consid?r?e comme rompue.

La modification de ces valeurs est directe : il faut ?crire de nouvelles valeurs dans les fichiers. Supposons que souhaitiez configurer la machine pour que le keepalive d?bute apr?s dix minutes d'inactivit? sur le lien, et que des sondes soient envoy?es chaque minute. En raison de l'instabilit? de ce brin de votre r?seau et de la faible valeur de l'intervalle, supposons que vous vouliez augmenter le nombre de tentatives ? 20.

Voici comment param?trer ces valeurs :

  # echo 600 > /proc/sys/net/ipv4/tcp_keepalive_time

  # echo 60 > /proc/sys/net/ipv4/tcp_keepalive_intvl

  # echo 20 > /proc/sys/net/ipv4/tcp_keepalive_probes
        

Pour confirmer la prise en compte des nouvelles valeurs, affichez ? nouveau le contenu des fichiers pour v?rifier qu'ils pr?sentent bien les valeurs souhait?es.

Il faut garder pr?sent ? l'esprit que procfs manipule des fichiers sp?ciaux, et vous ne pouvez pas tout faire sur ces fichiers qui ne sont qu'une interface vers l'environnement du noyau, non de v?ritables fichiers. Testez vos scripts avant de les utiliser et faites en sorte d'utiliser des modes d'acc?s simples comme dans les exemples ci-dessus.

Vous pouvez acc?der ? l'interface gr?ce ? l'outil sysctl(8), en pr?cisant ce que vos voulez lire ou ?crire.

  # sysctl \
  > net.ipv4.tcp_keepalive_time \
  > net.ipv4.tcp_keepalive_intvl \
  > net.ipv4.tcp_keepalive_probes
  net.ipv4.tcp_keepalive_time = 7200
  net.ipv4.tcp_keepalive_intvl = 75
  net.ipv4.tcp_keepalive_probes = 9
        

Remarquez que les noms sysctl sont proches des chemins procfs. L'?criture se fait gr?ce ? l'option -w de sysctl (8):

  # sysctl -w \
  > net.ipv4.tcp_keepalive_time=600 \
  > net.ipv4.tcp_keepalive_intvl=60 \
  > net.ipv4.tcp_keepalive_probes=20
  net.ipv4.tcp_keepalive_time = 600
  net.ipv4.tcp_keepalive_intvl = 60
  net.ipv4.tcp_keepalive_probes = 20
        

Remarquez que sysctl (8) n'utilise pas l'appel syst?me (syscall)sysctl(2), mais lit et ?crit directement dans l'arborescence procfs, donc procfs devra ?tre activ? dans le noyau et mont? dans le syst?me de fichiers, comme si vous acc?diez directement aux fichiers via l'interface procfs. Sysctl(8) n'est qu'un moyen diff?rent de faire la m?me chose.

Il existe diff?rents moyens de param?trer le syst?me ? chaque d?marrage. Tout d'abord, souvenez vous que chaque distribution Linux poss?de son propre jeu de scripts d'initialisation appel? par init (8). Les configurations les plus courantes incluent soit le r?pertoire /etc/rc.d/ , soit /etc/init.d/ . Dans ce cas vous pouvez positionner les param?tres dans un script de d?marrage quelconque, keepalive relisant les valeurs ? chaque fois que ses routines en ont besoin. Donc si vous changez la valeur de tcp_keepalive_intvl alors que la connexion est encore active, le noyau utilisera la nouvelle valeur pour continuer.

Les commandes d'initialisation peuvent logiquement ?tre plac?es en trois endroits diff?rents : le premier est dans la configuration r?seau, le second dans le script rc.local , habituellement inclus dans toutes les distributions, et connu comme ?tant le point de configuration utilisateur au d?marrage. Le troisi?me point existe peut-?tre d?j? sur votre syst?me. En revenant ? l'outil sysctl (8) , vous pouvez voir que l'option -p charge les param?tres du fichier de configuration /etc/sysctl.conf . Il est fr?quent que votre script d'initialisation ex?cute d?j? sysctl -p (un ??grep?? sur le r?pertoire de configuration le confirmera), et vous n'avez alors qu'? ajouter les lignes dans /etc/sysctl.conf pour qu'elles soient prises en compte ? chaque d?marrage. Pour davantage d'informations sur la syntaxe de sysctl.conf (5), reportez vous au manuel.

Cette section aborde le code n?cessaire ? l'?criture d'une application utilisant keepalive. Ce n'est pas un manuel de programmation, et il requiert d'avoir une connaissance du langage C et des concepts r?seau. Je consid?re que la notion de socket vous est famili?re, de m?me que tous les aspects g?n?raux de votre application.

Tout le monde n'est pas d?veloppeur d'application, et tout le monde ne r??crira pas enti?rement une application pour combler le manque d'une fonctionnalit?. Peut-?tre souhaitez vous ajouter keepalive ? une application existante, et m?me si son auteur n'a pas consid?r? cela important, vous pensez que ce sera utile.

Tout d'abord, souvenez vous de ce qui a ?t? dit pr?c?demment ? propos des cas o? keepalive est n?cessaire. Ensuite vous devrez affecter les sockets TCP orient?es connexion.

Comme Linux ne fournit pas la possibilit? d'activer le support keepalive via le noyau (les OS de type BSD le permettent souvent), le seul moyen est d'appeler setsockopt (2) apr?s la cr?ation de la socket. Il y a deux solutions:

Souvenez-vous que keepalive n'est pas orient? programme, mais orient? socket, donc si vous avez de multiples sockets, vous pouvez g?rer keepalive s?par?ment pour chacune d'entre elles. La premi?re ?tape consiste ? comprendre ce que fait le programme, la seconde ? rechercher le code pour chaque socket dans le programme. Cela peut ?tre fait en utilisant grep(1), comme suit:

  # grep 'socket *(' *.c
      

Cela vous montrera ? peu pr?s toutes les sockets du code. L'?tape suivante consiste ? choisir les bonnes : vous ciblez les sockets TCP, donc recherchez PF_INET (ou AF_INET), SOCK_STREAM et IPPROTO_TCP (ou plus commun?ment, 0) dans les param?tres de votre liste de sockets, et enlevez celles qui ne correspondent pas.

Il existe un autre moyen de cr?er une socket au travers de accept(2). En ce ce cas, suivez les sockets TCP identifi?es et v?rifiez si certaines sont en ?coute : si c'est le cas, gardez ? l'esprit que accept(2) retourne un descripteur de socket, qui doit ?tre ajout? ? votre liste de sockets.

Une fois les sockets identifi?es, vous pouvez proc?der aux modifications. Le patch le plus 'fast & furious' peut consister ? simplement ajouter la fonction setsockopt(2 ) juste apr?s le bloc de cr?ation de la socket. ?ventuellement, vous pouvez ajouter des appels suppl?mentaires pour modifier les param?tres syst?mes par d?faut de keepalive. Surtout soyez attentif au positionnement des v?rifications d'erreurs et des handlers de la fonction, peut-?tre en recopiant le style du code alentour. Songez ? affecter ? optval une valeur non nulle et ? initialiser optlen avant d'appeler la fonction.

Si vous en avez le temps ou pensez que ce serait plus ?l?gant, essayez d'impl?menter compl?tement le keepalive ? votre programme, en incluant une option de ligne de commande ou un param?tre de configuration pour laisser ? l'utilisateur la libert? d'utiliser ou non keepalive.

Dans de nombreux cas vous n'avez pas la possibilit? de modifier le code source d'une application, ou bien lorsque vous devez activer keepalive pour tous vos programmes, tout patcher et tout recompiler n'est pas recommand?.

Le projet libkeepalive a vu le jour pour faciliter l'impl?mentation du keepalive au sein des applications puisque le noyau Linux ne permet pas de le faire nativement (comme le fait BSD). La page d'accueil du projet libkeepalive est disponible ? l'adresse http://libkeepalive.sourceforge.net/

Il consiste en une biblioth?que partag?e qui outrepasse l'appel syst?me socket de la plupart des ex?cutables, sans aucun besoin de les recompiler ni de les modifier. La technique repose sur la fonctionnalit? de pr?-chargement (preloading) de ld.so(8), chargeur inclus dans Linux, qui qui permet le chargement de biblioth?ques partag?es avec une priorit? sup?rieure ? la normale. Les programmes utilisent habituellement l'appel de fonction socket (2) situ? dans la glibc, librairie partag?e; avec libkeepalive il est possible d'encapsuler la fonction setsockopt(2) juste apr?s la cr?ation, retournant au programme principal une socket avec keepalive d?j? positionn?. En raison des m?canismes utilis?s pour r?aliser l'appel syst?me, ce proc?d? ne fonctionne pas lorsque la fonction socket est compil?e statiquement dans le binaire, comme dans le cas d'un programme li? par l'option -static de gcc(1 ).

Apr?s avoir t?l?charg? et install? libkeepalive, vous serez en mesure d'ajouter le support de keepalive ? vos programmes sans ?tre root au pr?alable, simplement en initialisant la variable d'environnement LD_PRELOAD avant d'ex?cuter le programme. Au fait, le super utilisateur peut aussi forcer la pr?-chargement au travers d'une configuration globale, et les utilisateurs peuvent choisir de le d?sactiver en positionnant la variable d'environnement KEEPALIVE ? off.

L'environnement est aussi utilis? pour positionner des valeurs sp?cifiques pour les param?tres de keepalive, vous avez donc la possibilit? de g?rer chaque programme de fa?on distincte, en initialisant KEEPCNT, KEEPIDLE et KEEPINTVL avant de lancer l'application.

Voici un exemple d'utilisation de libkeepalive :

  $ test
  SO_KEEPALIVE is OFF

  $ LD_PRELOAD=libkeepalive.so \
  > KEEPCNT=20 \
  > KEEPIDLE=180 \
  > KEEPINTVL=60 \
  > test
  SO_KEEPALIVE is ON
  TCP_KEEPCNT   = 20
  TCP_KEEPIDLE  = 180
  TCP_KEEPINTVL = 60
      

Et vous pouvez utiliser strace (1) pour comprendre ce qui se passe:

  $ strace test
  execve("test", ["test"], [/* 26 vars */]) = 0
  [..]
  open("/lib/libc.so.6", O_RDONLY)        = 3
  [..]
  socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
  getsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [0], [4]) = 0
  close(3)                                = 0
  [..]
  _exit(0)                                = ?

  $ LD_PRELOAD=libkeepalive.so \
  > strace test
  execve("test", ["test"], [/* 27 vars */]) = 0
  [..]
  open("/usr/local/lib/libkeepalive.so", O_RDONLY) = 3
  [..]
  open("/lib/libc.so.6", O_RDONLY)        = 3
  [..]
  open("/lib/libdl.so.2", O_RDONLY)       = 3
  [..]
  socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
  setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
  setsockopt(3, SOL_TCP, TCP_KEEPCNT, [20], 4) = 0
  setsockopt(3, SOL_TCP, TCP_KEEPIDLE, [180], 4) = 0
  setsockopt(3, SOL_TCP, TCP_KEEPINTVL, [60], 4) = 0
  [..]
  getsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], [4]) = 0
  [..]
  getsockopt(3, SOL_TCP, TCP_KEEPCNT, [20], [4]) = 0
  [..]
  getsockopt(3, SOL_TCP, TCP_KEEPIDLE, [180], [4]) = 0
  [..]
  getsockopt(3, SOL_TCP, TCP_KEEPINTVL, [60], [4]) = 0
  [..]
  close(3)                                = 0
  [..]
  _exit(0)                                = ?
    

Pour d'autres informations, visitez la page d'accueil du projet libkeepalive : http://libkeepalive.sourceforge.net/