Bael#

Serveur DHCP intégré, en coexistence avec dnsmasq, et documentation du projet.

Fonctionnalités#

Serveur DHCP intégré

  • Nouveau binaire dhcp, une instance par subnet lancée dans le netns du VPC par l’unit dhcp@<netns>_<bridge>. Il reçoit son bridge et ses deux chemins de fichiers en paramètres : il ne compose aucun chemin et ignore le netns dans lequel il tourne

  • Piloté par l’agent sur une socket Unix /run/two/dhcp/<netns>_<bridge>.sock, en JSON par ligne. Ordres idempotents en remplacement intégral : configuration du subnet à sa création, une réservation par interface à chaque création ou suppression de VM

  • Réservations statiques uniquement, pas de baux : une MAC inconnue n’obtient rien, et le serveur reste silencieux plutôt que de répondre par un refus. Aucun DHCPNAK n’est émis

  • État auto-persisté dans /run/two/dhcp/<netns>_<bridge>.state, en écriture atomique et lisible par le seul root. Le fichier appartient au processus, qui le relit à son démarrage ; l’agent ne l’écrit jamais et se borne à le supprimer — à la création du subnet pour écarter un résidu, à sa suppression après avoir arrêté l’unit

  • La route par défaut est décidée par interface et non plus par subnet, ce qui permet de ne l’annoncer que sur une interface d’une VM multi-réseaux

  • L’encodage RFC 3442 de l’option 121 est délégué à github.com/insomniacslk/dhcp

Coexistence avec dnsmasq

  • Nouvelle clé dhcp.backend, dnsmasq ou two, qui choisit le serveur des subnets créés par cet agent. Le défaut est dnsmasq : un fichier de configuration de la 0.1.0, non modifié, se comporte exactement comme avant

  • La bascule est une opération manuelle sur un hyperviseur vide — l’option ne migre rien, un subnet déjà créé reste servi par le serveur qui l’a été. La procédure est documentée

  • Toute valeur autre que dnsmasq ou two fait échouer le démarrage de l’agent

Exploitation

  • Le watchdog interroge le serveur DHCP intégré et compare les réservations servies à celles que la base implique. Il nomme ce qui diverge — ordre perdu à la création, ordre perdu à la suppression, adresse ou route par défaut divergente — et reste en lecture seule

  • La socket de contrôle répond à get-state et à probe, ce dernier montrant sans effet de bord ce qui serait envoyé à une MAC donnée : adresse, masque, routeur, DNS et routes

  • Documentation Sphinx du projet : concepts, architecture, déploiement et exploitation

Correctifs#

  • Un fichier de configuration présent mais invalide fait désormais échouer le démarrage. Jusqu’en 0.1.0 l’erreur de lecture était ignorée : l’agent tournait alors entièrement sur ses valeurs par défaut sans le dire, ce qui rendait indétectable une simple tabulation d’indentation

  • probe annonce explicitement "served": false pour une MAC non réservée, au lieu d’omettre le champ et de le rendre indistinguable d’une réponse tronquée

Changements internes#

  • Le module passe à Go 1.25, exigé par la bibliothèque DHCP retenue. La version de Go du workflow de build, restée à 1.21 alors que le module en demandait davantage, est alignée

  • Nouveau paquet pkg/db/statefile : persistance générique d’un état de composant dans un fichier, en écriture atomique. Badger a été écarté pour cet usage — une instance par subnet coûterait une memtable de 64 Mio et quatre goroutines de compaction pour environ un kilo-octet d’état, dans un tmpfs, et laisserait un verrou résiduel après un arrêt brutal

  • internal/subnet et internal/vm ne parlent plus à dnsmasq en direct mais à une interface Backend à deux implémentations

Périmètre et limites connues#

Celles de la 0.1.0 restent valables, sauf mention contraire ci-dessus. S’y ajoutent :

  • dnsmasq n’est pas retiré et reste un paquet requis : le backend intégré ne sert que les subnets créés après la bascule, et le retour arrière suppose dnsmasq installé

  • Pas de DNS, pas de pool dynamique, pas de PXE, pas de DHCPv6 dans le serveur intégré

  • La comparaison faite par le watchdog porte sur les réservations et non sur la configuration du subnet : celle-ci dépend de la route par défaut de l’host, dont la lecture au moment du contrôle produirait de faux écarts. Un serveur dépourvu de configuration est en revanche signalé

  • L’option 249 (routes classless de Microsoft) n’est pas émise, comme dnsmasq ne l’émet pas

  • Le serveur intégré écoute UDP/67 sans authentification, comme tout serveur DHCP : l’isolation entre locataires d’un même subnet repose sur les règles ebtables anti-usurpation, inchangées

  • internal/dhcpbackend n’est testé sous Linux que pour ses appels systemd ; le reste, y compris le dialogue avec le serveur intégré, est couvert sur toute plateforme

Mise à jour depuis la 0.1.0#

curl -O https://git.g3e.fr/syonad/two/raw/branch/main/scripts/deploy.sh
bash ./deploy.sh -t 0.2.0

Aucune action n’est requise : sans dhcp.backend dans /etc/two/agent.yml, le comportement est celui de la 0.1.0. Pour passer au serveur intégré, suivre la procédure de bascule dans la documentation d’exploitation — elle suppose un hyperviseur vidé.