Phase 4 : tripoli-netctl, labo network namespaces + veth (rtnetlink)
- CLI (clap) : create/destroy/list. Network namespace créé via rtnetlink::NetworkNamespace (fork + unshare(CLONE_NEWNET) + bind-mount, équivalent de `ip netns add`), paire veth créée dans la racine, un bout déplacé dans le namespace (setns_by_fd) et adressé depuis un thread OS dédié qui fait setns() - jamais un thread du pool spawn_blocking de tokio, qui serait réutilisé pour d'autres tâches et resterait coincé dans le namespace. - Journal d'audit JSON (stderr + /var/log/tripoli-netctl/audit.log) à chaque opération. - Documenté explicitement comme labo pédagogique un-seul-poste : tripoli-edge et tripoli-api restent nativement sur l'hôte, ce projet ne pilote aucun trafic de production. - Testé en conditions réelles sur le serveur : création, adressage des deux côtés (dont lo, down par défaut dans un netns neuf), ping traversant effectivement la veth, puis destruction propre (veth + namespace) vérifiée par absence des interfaces et du namespace. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
546734ad77
commit
991f4dd04f
9 changed files with 688 additions and 2 deletions
84
tripoli-netctl/README.md
Normal file
84
tripoli-netctl/README.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# tripoli-netctl
|
||||
|
||||
Labo pédagogique un-seul-poste sur les network namespaces Linux et la
|
||||
crate `rtnetlink`. **Ne pilote aucun service de production** :
|
||||
tripoli-edge et tripoli-api continuent de tourner nativement sur l'hôte,
|
||||
dans le namespace racine. Ce n'est pas un CNI, pas un orchestrateur -
|
||||
juste une démonstration, sur une seule machine, de ce qui se passe sous
|
||||
le capot quand un outil comme Docker ou Kubernetes isole un service en
|
||||
réseau.
|
||||
|
||||
## Ce que fait `create <name>`
|
||||
|
||||
1. Crée un network namespace nommé `<name>` (`rtnetlink::NetworkNamespace::add`,
|
||||
équivalent de `ip netns add` - fork + `unshare(CLONE_NEWNET)` +
|
||||
bind-mount de `/proc/self/ns/net` sur `/run/netns/<name>`).
|
||||
2. Crée une paire veth (`tv-<name>h` / `tv-<name>p`, noms tronqués à 6
|
||||
caractères alphanumériques pour respecter la limite de 15 caractères
|
||||
des interfaces Linux).
|
||||
3. Déplace `tv-<name>p` dans le namespace créé (`setns_by_fd`).
|
||||
4. Adresse le côté hôte (`10.200.<subnet-id>.1/30`) et l'active.
|
||||
5. Depuis un thread OS dédié qui fait `setns()` vers le namespace cible,
|
||||
adresse le côté namespace (`10.200.<subnet-id>.2/30`), l'active, et
|
||||
active `lo` (qui démarre toujours *down* dans un namespace neuf -
|
||||
détail facile à oublier, source classique de "ça ne marche pas" dans
|
||||
ce genre de labo).
|
||||
|
||||
Chaque étape est journalisée en JSON sur stderr et dans
|
||||
`/var/log/tripoli-netctl/audit.log`.
|
||||
|
||||
## Pourquoi un thread dédié, pas `tokio::task::spawn_blocking`
|
||||
|
||||
`setns()` change la namespace réseau du **thread appelant**, pour toute
|
||||
sa durée de vie. Les threads de `spawn_blocking` sont mis en pool et
|
||||
réutilisés par tokio pour d'autres tâches bloquantes : y laisser un
|
||||
thread « coincé » dans un namespace réseau casserait silencieusement
|
||||
n'importe quelle tâche bloquante ultérieure qui tomberait dessus. Un
|
||||
`std::thread::spawn` dédié, jamais réutilisé, élimine le risque.
|
||||
|
||||
## `destroy <name>`
|
||||
|
||||
Supprime le côté hôte de la veth - le noyau supprime automatiquement le
|
||||
pair, même déplacé dans un autre namespace, dès qu'un des deux bouts
|
||||
disparaît - puis démonte/supprime le fichier de namespace.
|
||||
|
||||
## `list`
|
||||
|
||||
Énumère `/run/netns` et vérifie, pour chacun, la présence de la veth
|
||||
hôte associée.
|
||||
|
||||
## Utilisation
|
||||
|
||||
```bash
|
||||
sudo ./tripoli-netctl create demo --subnet-id 5
|
||||
sudo ./tripoli-netctl list
|
||||
sudo ./tripoli-netctl destroy demo
|
||||
```
|
||||
|
||||
Root est requis (namespaces + netlink privilégié) - vérifié explicitement
|
||||
au démarrage plutôt que de laisser échouer la première opération avec un
|
||||
message obscur.
|
||||
|
||||
## Limites assumées (v1)
|
||||
|
||||
- Pas d'allocation automatique de sous-réseau : `--subnet-id` est
|
||||
explicite, une collision entre deux services donnerait une erreur
|
||||
claire plutôt qu'une allocation silencieuse qui la masquerait.
|
||||
- IPv4 uniquement.
|
||||
- Un seul veth par service - pas de topologie plus complexe (bridge,
|
||||
plusieurs interfaces).
|
||||
|
||||
## Vérifié
|
||||
|
||||
```
|
||||
$ sudo tripoli-netctl create demo1 --subnet-id 5
|
||||
service 'demo1' prêt :
|
||||
hôte : tv-demo1h 10.200.5.1/30 (namespace racine)
|
||||
ns : tv-demo1p 10.200.5.2/30 (namespace demo1, /run/netns/demo1)
|
||||
|
||||
$ ping -c 2 10.200.5.2 # depuis la racine, vers le namespace
|
||||
2 packets transmitted, 2 received, 0% packet loss
|
||||
|
||||
$ sudo tripoli-netctl destroy demo1
|
||||
service 'demo1' détruit # veth et namespace bien supprimés, vérifié
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue