Aller au contenu

Architecture et réseau

Version

Page écrite pour pupitre 0.1.35-1.

Cette page décrit une salle servie par pupitre, ce qui tourne dans la machine virtuelle pour chaque poste, les ports et les débits en jeu, puis le dimensionnement et les préconisations.

La salle

Une salle de dix postes : dix Wyse 1010 reliés à un commutateur gigabit, une liaison montante à 1 Gbit/s qui porte le VLAN de la classe jusqu'à l'hyperviseur où tourne la VM pupitre

Le schéma montre une salle de dix postes : un commutateur, une liaison montante et une VM, dans la salle ou dans un local technique. Cliquez sur le schéma pour l'ouvrir en pleine taille.

Chaque poste est un Dell Wyse 1010 avec un écran VGA, un clavier et une souris USB (un récepteur sans fil convient), un casque et, au besoin, une clé USB. Le boîtier prend son adresse par DHCP sur le réseau de l'école ; pupitre ne sert pas de DHCP. Le serveur a une adresse fixe sur le même VLAN.

Pourquoi la couche 2 est obligatoire

Ce n'est pas une prudence, c'est le code :

  • La découverte passe par la diffusion. Chaque boîtier s'annonce en diffusion UDP sur le port
  • Le gestionnaire et les sièges écoutent ce port ; le siège répond en unicast depuis le port 52340 (pupitre/main.py). Une diffusion ne traverse pas un routeur.
  • Le client de siège parle directement Ethernet. fast_tcp2 construit lui-même ses trames Ethernet avec la MAC du boîtier en destination, et rejette toute trame reçue d'une autre MAC (src/fast_tcp2/fast_tcp2.c). Derrière un routeur, la MAC source vue serait celle du routeur et chaque trame serait jetée.

Conséquences : la carte réseau de la VM est en pont sur le VLAN des boîtiers, jamais derrière un NAT, et aucun routeur ne s'intercale. Un relais DHCP ne remplace pas ce lien. Le Wi-Fi ne se ponte pas : l'hyperviseur doit être relié en filaire.

VM dans la salle ou VM déportée

  • Montage de référence : une VM KVM/libvirt sur une machine reliée au réseau des boîtiers, avec une interface macvtap sur la carte filaire (c'est ce que fait le démonstrateur tools/demo-vm.sh).
  • Exigence pour déporter la VM dans une autre salle ou un local technique : le VLAN de la classe doit arriver tel quel, au niveau 2, jusqu'à l'hyperviseur, par exemple en 802.1Q de bout en bout sur les commutateurs intermédiaires.
  • Latence : la vidéo avance par fenêtre de 14 336 octets et par accusé de fin de trame, son débit baisse donc quand l'aller-retour augmente. En réseau local, l'accusé revient en 0,4 ms environ. Gardez la VM sur un lien de faible latence ; avant de la déporter sur un lien de plusieurs millisecondes, vérifiez le débit vidéo d'un poste.

Ce qui tourne dans la VM

Pile d'un siège : services communs en haut, puis le lanceur pupitre-seat@N avec un côté session (Xvfb, bureau, PulseAudio, injecteur) et un côté lien (encodeur, curseur, clé, pupitre.main, fast_tcp2), reliés au boîtier par quatre canaux TCP et les annonces UDP

Cliquez sur le schéma pour l'ouvrir en pleine taille.

Les services communs

Unité Rôle
pupitre-nft Une seule fois, en root : une table nftables ip pupitre qui jette les RST que le noyau enverrait vers les ports des boîtiers. Le noyau ne connaît pas les connexions TCP de fast_tcp2 et répondrait RST à chacun de leurs segments. Depuis 0.1.27, une mise à jour recharge la règle en place au lieu de la redémarrer, ce qui ne coupe plus les sièges.
pupitre-manager Écoute les annonces UDP 52330, tient la table MAC vers siège (/var/lib/pupitre/seats.json), écrit /run/pupitre/seat-N.env (MAC, IP, interface) et démarre pupitre-seat@N. Un boîtier inconnu est enrôlé tout seul au plus petit numéro libre (enroll = yes, le défaut).
pupitre-web La console d'administration, sur 127.0.0.1:8080 par défaut. Elle lit les écrans des sièges directement dans les framebuffers de Xvfb.
lightdm Seulement en mode eleves (depuis 0.1.27) : un écran de connexion par siège, posé sur l'Xvfb du siège.

Un siège : le côté session et le côté lien

pupitre-seat@N lance un script, /usr/lib/pupitre/pupitre-seat, qui reste root pour ce qui l'exige et démarre le reste sous l'utilisateur du siège, pupitre-seat-N. Il sépare deux mondes, et cette frontière explique le comportement quand un élève éteint son boîtier :

  • Côté session, ce qui survit à une coupure du lien : Xvfb sur l'affichage :(100+N) en 1280 × 1024, le bureau, le PulseAudio du siège et son pont parec, l'injecteur d'entrées. En mode fixe, le bureau est xfce4-session sous pupitre-seat-N. En mode eleves, c'est l'écran de connexion puis la session de l'élève sous son propre compte.
  • Côté lien, ce qui est refait sans toucher la session : pupitre.main, qui fait la poignée de main DCP et lance fast_tcp2, l'encodeur, le programme du curseur, et le veilleur de clé (pupitre-cle) avec son fichier FUSE, arrêtés avant fast_tcp2 pour vider une clé montée.

Quand le boîtier disparaît, seul le côté lien est arrêté puis refait ; l'élève retrouve son bureau tel qu'il l'a laissé (depuis 0.1.13). Sans lien depuis PUPITRE_GRACE secondes (600 par défaut), le siège s'arrête. En mode eleves, la session de l'élève est fermée après PUPITRE_FERMETURE secondes de boîtier éteint (600 par défaut).

fast_tcp2 n'a besoin que des capacités CAP_NET_RAW et CAP_SYS_NICE, posées par le paquet. Il dort dans ppoll entre deux trames : 1,50 % d'un cœur par siège au lieu d'un cœur entier (depuis 0.1.5).

Le chemin des données

Tous les tubes vivent dans /run/pupitre/seat-N/.

Flux Chemin
Image Le bureau dessine dans Xvfb, qui écrit son framebuffer dans un fichier. encoder.py repère les zones modifiées, les code en RLE et les pousse dans le tube video. fast_tcp2 les envoie au boîtier sur TCP 1234 et 4321. Double tampon différé par défaut (depuis 0.1.20) : pas de déchirure, deux fois moins d'octets qu'un double tampon complet.
Curseur curseur_x.py lit la forme et la position du pointeur par XFixes et les écrit dans le tube curseur ; le boîtier dessine lui-même le pointeur, sur le canal vidéo. Allumé par défaut depuis 0.1.14.
Son Les applications jouent dans un puits PulseAudio nul nommé wyse, que parec lit en PCM 16 bits stéréo à 44,1 kHz vers le tube audio. fast_tcp2 l'envoie sur TCP 1235 et 4322, une unité de 1780 octets toutes les 10 ms.
Clavier et souris Le boîtier remonte les rapports HID par le tunnel USB, TCP 4660. fast_tcp2 les écrit dans le tube input ; input_inject.py les rejoue dans Xvfb par XTEST, en codes de touche, et la disposition xkb du siège en fait des caractères.
Clé USB fast_tcp2 parle à la clé par TCP 1237 et 4324 et la sert sur la socket cle.sock. wyse_cle_fuse en fait un fichier disque.img, que fusefatfs monte au double-clic dans le dossier « Clé USB ». Le noyau ne monte jamais la clé d'un élève. Port isolé du boîtier servi depuis 0.1.29.

Ports et protocoles

Tous les canaux d'un boîtier passent par la même carte en pont. Les canaux TCP sont portés par fast_tcp2 sur sa socket AF_PACKET ; le boîtier est le côté serveur des ports listés.

Port Protocole Rôle Sens principal
52330 UDP, diffusion annonces DCP des boîtiers, toutes les 10 s boîtier vers serveur
52340 vers 52330 UDP, unicast réponse du siège à son boîtier serveur vers boîtier
4660 TCP tunnel USB : descripteurs, clavier, souris dans les deux sens
1234 et 4321 TCP vidéo et curseur : 1234 annonce, 4321 porte les données serveur vers boîtier
1235 et 4322 TCP son serveur vers boîtier
1237 et 4324 TCP clé USB (paire annoncée par le boîtier) dans les deux sens
1234 à 1241 et 4321 à 4328 TCP toutes les paires possibles, couvertes par la règle pupitre-nft
8080 TCP, HTTP console web, sur 127.0.0.1 par défaut poste d'administration vers serveur

Pupitre ne pose aucune règle d'entrée sur le serveur. Un pare-feu en entrée doit laisser passer l'UDP 52330 : c'est par là que les boîtiers s'annoncent, sans quoi ils ne sont pas découverts.

Débits

1 Mio/s vaut environ 8,4 Mbit/s.

Usage d'un poste Débit
Bureau au repos négligeable (8 bandes en 60 s)
Frappe continue qui sature l'affichage ≈ 0,29 Mio/s, soit ≈ 2,3 Mbit/s
Terminal qui défile vingt lignes par seconde ≈ 0,28 Mio/s, soit ≈ 2,3 Mbit/s
Vidéo sans plafond (défaut depuis 0.1.17) jusqu'à 6064 Kio/s, ≈ 50 Mbit/s (depuis 0.1.24)
Vidéo plafonnée par PUPITRE_DEBIT_MAX=1024 1009 à 1038 Kio/s, ≈ 8,5 Mbit/s
Son en lecture 178 000 o/s, ≈ 1,4 Mbit/s
Clé USB ≈ 430 Kio/s en écriture, ≈ 900 Kio/s en lecture
Clavier et souris négligeable

Un port à 100 Mbit/s par boîtier suffit donc. La fiche Dell annonce un port Ethernet 10/100/1000.

Pour la salle, en additionnant :

Cas 10 postes 13 postes
Tous en bureautique, frappe saturante ≈ 23 Mbit/s ≈ 30 Mbit/s
Tous en vidéo sans plafond, avec le son ≈ 510 Mbit/s ≈ 660 Mbit/s
Tous en vidéo plafonnée à 1024 Kio/s ≈ 85 Mbit/s ≈ 110 Mbit/s

Le surcoût des en-têtes Ethernet, IP et TCP n'est pas compté. La clé et la vidéo d'un même siège ne s'additionnent pas en pointe : la vidéo attend la fin d'une commande de clé.

Latence en réseau local : environ 55 ms de la frappe au dernier octet de l'image sur le fil, dont 24 ms pour que X dessine, 4 ms d'encodage et 27 ms de transfert en médiane.

Dimensionner la VM

Tableau indicatif, pour une salle d'élèves qui ont chacun un bureau et Firefox ouvert :

Sièges vCPU Mémoire Disque Débit maximal vers le serveur
5 2 8 Go 30 Go ≈ 255 Mbit/s
10 4 16 Go 40 Go ≈ 510 Mbit/s
15 6 32 Go 50 Go ≈ 765 Mbit/s
20 8 32 Go 60 Go ≈ 1 020 Mbit/s, au-delà d'un lien à 1 Gbit/s

Le débit maximal est celui où tous les postes lisent une vidéo en même temps : environ 50 Mbit/s d'image plus 1,4 Mbit/s de son par poste. En bureautique, comptez environ 2,3 Mbit/s par poste.

La règle de calcul :

  • Mémoire. 2 Go de réserve pour le système, plus environ 0,75 Go par élève : le bureau et Firefox ouvert sur une page, dont environ 590 Mio pour Firefox. Le total est arrondi au palier courant en gardant environ un quart de marge. Dimensionnez pour le navigateur, pas pour le bureau : un siège au repos ne coûte que 128 à 162 Mio.
  • Processeur. L'encodeur fait environ 65 écrans complets par seconde et par vCPU, pour un besoin de 8 par siège : un vCPU pour huit sièges, et autant pour Xfce, Firefox et LibreOffice, arrondi au-dessus avec de la marge. Le client coûte 1,50 % d'un cœur par siège. tools/bench_encode_n_seats.py vérifie l'encodeur sur la VM cible.
  • Disque. 20 Go de système, 2,6 Go pour TuxBot et Wine, environ 1 Go par élève pour son dossier, arrondi avec de la marge.
  • Au-delà de 15 sièges, le nombre par défaut depuis 0.1.35, réglez seats dans /etc/pupitre/pupitre.conf (seats = 0 lève la limite).
  • Réseau. Le lien du serveur reste à 1 Gbit/s : à vingt postes qui lisent tous une vidéo, il sature.
  • zram. Compressée en zstd, la mémoire anonyme d'un siège au repos passe de 155 à 28 Mio, soit 5,39 pour 1. zram et la limite souple par siège (PUPITRE_MEMOIRE=1) sont livrés éteints : la procédure est dans Installation de zéro.

Préconisations

Réseau

  1. Mettre la VM et les boîtiers dans le même VLAN, la carte de la VM en pont, sans NAT ni routeur entre eux (imposé par le code).
  2. Donner au serveur une adresse fixe sur ce VLAN ; laisser les boîtiers en DHCP.
  3. Un port d'accès à 100 Mbit/s par boîtier suffit : un boîtier atteint environ 50 Mbit/s en vidéo.
  4. Le port de la VM et chaque liaison entre commutateurs jusqu'à elle : 1 Gbit/s dès que deux postes peuvent lire une vidéo en même temps (deux vidéos font ≈ 100 Mbit/s).
  5. Pour déporter la VM, étendre le VLAN de la classe au niveau 2 jusqu'à l'hyperviseur, puis vérifier le débit vidéo d'un poste avant de généraliser.
  6. Si le serveur a un pare-feu en entrée, y laisser passer l'UDP 52330.

Machine virtuelle

  1. Debian 13 uniquement : l'unité de siège exige systemd 254 ou plus.
  2. KVM/libvirt, avec une carte macvtap ou un pont sur le VLAN des boîtiers.
  3. Pour une salle de dix : 4 vCPU et 16 Go.
  4. Avec moins de 16 Go, activer zram et PUPITRE_MEMOIRE=1.

Console d'administration

La console : sur la boucle locale, jointe par ssh ; sur le réseau, seulement avec un mot de passe (depuis 0.1.14) et sur un VLAN d'administration, car elle reste en HTTP clair et montre l'écran de chaque élève. Mise en place : Console web et son mot de passe.

Limites connues côté réseau

  • DHCP : un boîtier qui démarre sans bail prend l'adresse de repli 169.254.10.10 et n'est pas servi : vérifiez le DHCP du VLAN, puis faites un cycle d'alimentation du boîtier.
  • Clavier et souris se branchent boîtier éteint : le client ne les configure qu'à l'ouverture du lien. Branchés après, ils sont vus dans l'inventaire du boîtier mais pas servis de façon fiable, et le boîtier peut redémarrer au branchement. Un arrêt et une remise en marche du boîtier les fait prendre, bureau gardé ; un Relink revient au même, car il fait redémarrer le boîtier (une quarantaine de secondes). La clé USB, elle, se branche à chaud.