Arbeiten an der Portierung von Tailscale auf Plan 9
(tailscale.com)- Die Unterstützung für Plan 9 begann als Aprilscherz-Ankündigung, führte aber zu echten PRs sowie Kernel- und Go-Änderungen; Stand 2. April 2025 ist Tailscale unter Plan 9 lauffähig
- Es ging nicht nur um einen einfachen Build mit
GOOS=plan9 GOARCH=386: Im Plan-9-Port von Go traten zunächst Runtime-Crashes und Probleme mit Sonderbehandlungen im Compiler zutage - Durch Änderungen von Russ Cox am Plan-9-Kernel sowie an Go-Runtime und -Compiler wurden SSE, Floating-Point-Kontext, monotone Zeit, DNS und die Entwicklungsumgebung aufgeräumt
- Tailscale nutzt Plan 9s
/net-Dateischnittstelle und ergänzt damit eine TUN-ähnliche Implementierung, Routing, Tailscale SSH, MagicDNS und Service-Erfassung; einige Teile sind jedoch provisorisch oder noch unvollständig - Der aktuelle Validierungsumfang betrifft vor allem 9legacy und
GOARCH=386; 9front, amd64, Exit Nodes und Go-net/netns-Unterstützung benötigen weitere Prüfung oder ein Redesign
Aus einem Aprilscherz wurde eine echte Portierung
- Tailscale kündigte am 1. April 2025 Plan-9-Unterstützung an und erklärte am nächsten Tag, dass diese Ankündigung auf einer tatsächlich funktionierenden Portierung basierte
- Die Arbeit mündete in einen Tailscale-PR und mehrere Änderungen an Plan 9 und Go
- Der ursprüngliche Ansatz begann mit der Erwartung, dass es reichen würde, die beiden Go-Binaries von Tailscale mit
GOOS=plan9 GOARCH=386 go install ./cmd/tailscale{,d}zu bauen - Beim ersten Versuch im August 2023 ließ sich ein Teil bauen, doch zur Laufzeit kam es zu abnormalen Crashes
- Der Plan-9-Port von Go war kein First-Class-Port, sodass Regressionen liegen geblieben waren
- Möglicherweise reizte Tailscale Go unter Plan 9 stärker aus als bisherige Software
- Die Portierung lag 2024 weitgehend brach und wurde im März 2025 zusammen mit der Aprilscherz-Idee wieder aufgenommen
SSE und Aufräumen der Plan-9-Unterstützung in Go
- Die 1999 mit dem Intel Pentium III eingeführten SSE-Instruktionen waren einer der wichtigsten Ausgangspunkte dieser Arbeit
- Der Go-Compiler versuchte, auf dem Plan-9-Target die Nutzung von SSE zu vermeiden
- Der Plan-9-Kernel speicherte und restaurierte in Note-Handlern keine SSE-Register
- Der Go-Compiler konnte nicht wissen, welcher Code innerhalb eines Note-Handlers ausgeführt wird, und versuchte daher, SSE global zu deaktivieren
- Diese Sonderbehandlung ging häufig kaputt, und im Compiler häuften sich
plan9-Ausnahmen
- Russ Cox änderte den Plan-9-Kernel so, dass Note-Handler Floating-Point- und SIMD-Kontext behandeln
- Für 386 kam die Änderung sys/src/9: allow floating point in note handlers hinzu
- Beim amd64-9k-Kernel wurden weitere Probleme entdeckt, darunter FP-State-Aliasing nach
fork, SIMD in Note-Handlern und Registerverlust beinoted(NCONT)
- Auf Go-Seite wurde die Sonderbehandlung bei der Codegenerierung für Plan 9 entfernt, wodurch
tailscaledlänger laufen konnte
IPC und Entwicklungsumgebung
- Danach begann
tailscaled, nicht mehr wegen Stack-Korruption, sondern wegen Speichermangel abzustürzen - Aus einem früheren Plan-9-Portierungsversuch gab es im Tailscale-IPC-Paket
safesocketeinen Bug, der unbegrenzt Goroutines erzeugte - Das Problem wurde zunächst gelöst, indem auf localhost-TCP umgestellt wurde
- Das passt weniger gut zu Plan 9s Ansatz „alles ist eine Datei“, aber es wurde bestätigt, dass auch andere Plan-9-Dienste localhost-TCP verwenden
- Künftig könnte es besser sein, die LocalAPI mit dem von Russ nach Go portierten srv9p package umzusetzen
- Die aktuelle Implementierung kann anders als auf anderen Plattformen keine localhost-Authentifizierung hinzufügen; daher wird ausdrücklich davon abgeraten, sie auf gemeinsam genutzten Plan-9-Maschinen zu verwenden
- Die frühe Entwicklung erfolgte in einer VM auf Basis eines 9legacy-CD-Images; der wiederholte Ablauf, Binaries per HTTP herunterzuladen und auszuführen, war langsam
- rsc/plan9 von Russ Cox enthält den Plan-9-Quellcode, vorkompilierte Binaries und ein
./boot/qemu-Skript- Die qemu-VM bootet ohne Disk und verwendet ein von einem localhost-9P-Server bereitgestelltes Git-Repository als Root-Dateisystem
- Durch das Teilen des Dateisystems zwischen Entwicklungsmaschine und Plan 9 sank die Iterationszeit von Minuten auf Sekunden
- qemu nutzt außerdem virtio und wurde dadurch schneller
Netzwerkintegration: TUN, Routing, MagicDNS
- Das erste funktionierende Tailscale lief im Userspace-Networking-Modus, der den Kernel-Netzwerkstack nicht verwendet
- TCP, UDP, ICMP usw. werden über gVisors netstack verarbeitet
- Um von einer Plan-9-Maschine aus auf ein Tailnet zuzugreifen, musste man den HTTP/SOCKS5-Proxy von
tailscaledverwenden - Das war nicht ideal, da kaum Plan-9-Programme die Umgebungsvariablen
HTTP_PROXYoderALL_PROXYverstehen
- Die TUN-ähnliche Implementierung von Plan 9 war sehr einfach
/net/ipifc/cloneöffnen und die neue Interface-Nummer lesen- Wenn man
"bind pkt\n"in das Control-fd schreibt, entsteht ein neues Interface wie/net/ipifc/2/* /net/ipifc/2/dataöffnen und IP-Pakete unverändert lesen und schreiben- Es sind weder ein separates ioctl noch Längen-Framing nötig
- Auch die Manipulation der Routing-Tabelle erfolgt über die Datei
/net/iproute- Mit
"tag tail\n"erhalten anschließend hinzugefügte Routen das Tagtail - Routen werden über Nachrichten wie
"add 100.64.0.0 /106 100.102.103.104"hinzugefügt - Da Plan 9 intern IPv6-zentriert ist und IPv4 als IPv4-mapped IPv6-Adressen behandelt, wird CGNAT
100.64.0.0/10als/106dargestellt
- Mit
- MagicDNS bestand unter Plan 9 darin, Peers unter Namen wie
foooderfoo.tailnet-name.ts.neterreichbar zu machen- Es wurde auch diskutiert, Abfragen an
/net/dnsoder/net/csabzufangen - Am Ende änderte Russ Plan 9 so, dass sich für bestimmte DNS-Suffixe alternative DNS-Server angeben lassen
- Außerdem wurde ein Problem behoben, bei dem DNS-Abfragen fälschlich negativ gecacht wurden
- Es wurde auch diskutiert, Abfragen an
Tailscale SSH und Service-Erfassung
- Tailscale SSH ist ein in
tailscaledintegrierter SSH-Server, der über den mit dem Paket verbundenen WireGuard-Schlüssel gegen eine bekannte Tailscale-Identity authentifiziert - Zunächst wurde die Plan-9-Shell
/bin/rcmitos/exec.Commandgestartet und stdin/stdout verbunden- Die Shell lief, aber Echo, Navigation, Prozess-Interrupts und Ähnliches funktionierten nicht korrekt
- Russ fügte das netshell example zu 9fans/go hinzu
- Dieses Beispiel ähnelte einem sehr unsicheren Telnet-Server, war aber ausreichend, um es hinter Tailscale SSH zu hängen
- Danach wurde es einfacher, per SSH den Inhalt von Plan 9s
/dev/snarfabzurufen oder Go-Tests auf dem Laptop zu cross-kompilieren und anschließend per SSH auszuführen
- Auch die optionale Tailscale-Funktion Service-Erfassung wurde für Plan 9 geprüft
- Es wird
/proc/NNN/fddurchlaufen, um Prozesse zu finden, die/net/tcp/clonegeöffnet haben - Die QID des fd wird mit
/net/tcp/NNN/{status,local}abgeglichen, um Listening-Status und Port zu ermitteln - Die Methode, die TCP-Nummer aus der QID zu berechnen, ist anfällig gegenüber Änderungen an der Kernel-Implementierung und bleibt daher ein unbefriedigender Punkt
- Es wird
Zeit, Web-Demo, v86
- In einigen Fällen stürzte
tailscaledab, weil gVisors netstack meldete, dass die monotone Zeit rückwärts gelaufen sei- Die Plan-9-Zeitimplementierung von Go verwendete Wall Time als monotone Zeit
- Wenn
ntpddie Uhr zurückstellte, brach die Annahme von netstack über monotone Zeit
- Russ fügte Plan 9s
/dev/bintimemonotone Zeit hinzu und änderte Go so, dass diese verwendet wird - Zum Ausführen von Plan 9 im Web wird v86 genutzt
- v86 führt 32-Bit-Betriebssysteme in WASM aus und bietet mehrere Netzwerkmodi
- Das war einer der Gründe, sich auf
GOARCH=386zu konzentrieren
- Anfangs wurde Tailscales Netzwerksimulationsumgebung um wsproxy protocol support ergänzt, um Ethernet-Frames über ein WebSocket-Relay zu senden
- Das läuft in einer Integrationstestumgebung, die ARP, DHCP, DNS, NAT, Control Plane, DERP usw. mit gVisor netstack nachbildet
- Wegen der DHCP-Roundtrips wurde der Start der Plan-9-GUI
riojedoch langsam, wenn das Relay weit entfernt war
- Später wurde auch ein WISP-Server implementiert, doch vor der Produktionsreife fehlte die Zeit; veröffentlicht wurde daher mit der Standard-Netzwerk-Relay-Konfiguration von copy.sh/v86
- Das Disk-Image mit Tailscale und Plan 9 war 16 MB groß, das Tailscale-Binary nach dem Entpacken 23 MB
- Deshalb sieht man beim Booten die Phase „gunzip…“
- Das Beispiel-Image ist im 9legacy-Profil von
copy.sh/v86enthalten
Offene Arbeiten und tatsächliche Ergebnisse
- Die aktuelle Tailscale-Portierung für Plan 9 wurde nur auf 9legacy getestet
- Zu den wichtigsten Plan-9-Forks gehören das minimal veränderte 9legacy und das stärker modifizierte 9front
- Einige der Patches, die Russ für 9legacy geschrieben hat, müssen möglicherweise auf 9front portiert werden
- Die 64-Bit-Unterstützung mit
GOARCH=amd64muss ebenfalls noch validiert werden - Exit-Node-Unterstützung und Unterstützung für das Go-Paket
net/netnssind nicht implementiert- Dafür könnte eine Neubewertung nötig sein, etwa in der Art, dass Tailscale sich unter Plan 9 als eigenes
/netsichtbar macht
- Dafür könnte eine Neubewertung nötig sein, etwa in der Art, dass Tailscale sich unter Plan 9 als eigenes
- Durch diese Arbeit wurde auch die Plan-9-Unterstützung in Go verbessert
- cmd/compile: use FMA on plan9, and drop UseFMA
- runtime: remove nextSampleNoFP from plan9
- cmd/compile, runtime: remove plan9 special case avoiding SSE
- net: fix parsing of interfaces on plan9 without associated devices
- os: guarantee min buffer size for ReadFile reads on /proc-like files
- net: unblock UDP Reads upon Close on plan9, add test
- runtime: fix plan9 monotonic time, crypto randomness
- Insbesondere durch das Entfernen von Plan-9-Sonderfällen aus dem Go-Compiler wurde der Compiler einfacher und leichter zu ändern
- Zum Zeitpunkt der Veröffentlichung der v86-Demo gab es durch einen Aprilscherz des v86-Autors noch das Problem, dass selbst VGA-Textausgabe wie falsches Niederländisch angezeigt wurde; mit dem Query-Argument
&nojokeließ sich das umgehen
1 Kommentare
Hacker-News-Kommentare
Wenn es Fragen gibt, kann ich sie beantworten.
Ein paar Leute sprechen gerade unter https://meet.google.com/qre-gydb-mkv darüber.
Edit: Nach einer Stunde sind alle gegangen.
Der frühere Blogpost vom 1. April war https://tailscale.com/blog/tailscale-enterprise-plan-9-suppo...
Dass Russ Cox diesen Witz wirklich bis zum Ende durchgezogen hat, ist absolut legendär.
Auf der 9fans-Liste gab es zum Aprilscherz Folgendes:
Wegen der zu hohen Wartungskosten für unausgereifte Computerarchitekturen wie mips, 386, arm, arm64 und amd64 habe man beschlossen, sich auf reifere und stabilere Architekturen zu konzentrieren.
Gemeint seien power64 und itanium; daher würden alle Architekturen außer power64 und itanium eingefroren, archiviert und zum End of Life befördert.
Kein Witz: Ich wünschte, es gäbe wirklich eine Enterprise-Version von Plan 9.
Die meisten meiner Skripte schreibe ich inzwischen in
rc; weil wir nix nutzen und sie mit direnv automatisch heranziehen können, tolerieren meine Kollegen das, und es war ziemlich gut.rc-Skripte ausführen können, als darüber, ob sie sie lesen und ändern können.rcist dieser[1]:„Das wichtigste Prinzip beim Design von rc ist, dass es kein Makroprozessor ist. Eingaben werden vom lexikalischen und syntaktischen Analysecode niemals mehr als einmal gescannt.“
Bei einer Unix-Firma, bei der ich früher gearbeitet habe, wurde einmal ein laufendes Shell-Skript geändert, wodurch ein Großteil der Arbeitsplatten gelöscht wurde. Zum Glück hatten wir tägliche Backups auf Band; das war vor etwa 17 Jahren.
[1] https://www.scs.stanford.edu/nyu/04fa/sched/readings/rc.pdf
Falls du den ersten Beitrag verpasst hast und es einfach selbst ausprobieren willst: Es läuft in diesem v86-Image:
https://copy.sh/v86/?profile=custom&m=768&vram=16&hda.url=ht...
In der VM kannst du
tailscaledundtailscalestarten. Wegen eingeschränkter Proxy-Verfügbarkeit kann es eine Weile dauern, bis sie online ist.Edit: Alt fungiert als dritte Maustaste. Um ein Terminal zu starten: Alt gedrückt halten und rechtsklicken, „new“ auswählen, Alt loslassen und per Rechtsklick-Ziehen die Größe des Terminalfensters festlegen.
Das Webinar läuft gerade (Google Meet): https://ftp.plan9.ts.net/webinar
Die Prämisse des Witzes gefiel mir, aber je länger die Erklärung wurde, desto deprimierter wurde ich plötzlich.
Es ist so viel kaputt und die Komplexität ist so groß. Und wofür am Ende – um einen Netzwerktunnel zu bauen? Wenn dieser Zusatzaufwand selbst der Witz gewesen wäre, wäre es lustig gewesen.
Ich glaube, ich könnte rsc, Rob Pike und bradfitz stundenlang festhalten und mit ihnen besonders über Plan 9 reden. Natürlich wäre das eine völlige Verschwendung ihrer Zeit.
Dieses Betriebssystem ist wirklich faszinierend.
Ich erinnere mich an einen Experten, mit dem ich früh in meiner Karriere zusammenarbeitete: Er saß neben mir, zeigte mir geduldig Vorgehensweisen und beantwortete Fragen, bis ich genug verstanden hatte. Es war, als würde er mich ins tiefe Wasser werfen und zugleich dafür sorgen, dass ich schwimmen konnte; in drei Stunden fühlte es sich an, als hätte ich in einem Spezialgebiet einen Bachelorabschluss gemacht – einer der schnellsten Wachstumsschübe meiner Karriere.
Ich kann weder C noch weiß ich genug, um Plan 9 produktiv zu nutzen, aber es gibt dort großartige und nützliche Funktionen, über die ich mehr wissen und lernen möchte – schon allein, um bedauern zu können, dass sie in den heutigen drei großen Betriebssystemen fehlen.
Wenn ich das Geld hätte, würde ich mir Zeit mit allen dreien kaufen, um mein Go-Wissen zu erweitern, und zusätzlich Zeit mit rsc und Rob Pike, um endlich das Plan-9-Verständnis zu bekommen, das ich mir immer gewünscht, aber nie selbst erarbeitet habe.
Ich mag Plan 9 wirklich sehr. Viele seiner Prinzipien zu übernehmen und daraus mein eigenes Betriebssystem zu bauen, ist mein Ruhestandsprojekt und Lebensziel.
Edit: Den Namen „chaos10“ habe ich für dieses Projekt reserviert. Denn wie bei SerenityOS wird es wohl keinen Plan geben.
Ich hätte überhaupt nicht erwartet, dass sie sogar den Plan-9-Kernel patchen würden, um das zum Laufen zu bringen.