zurück zum Artikel

Linux 6.3: Wegbereiter für die Abkehr von C

Oliver Müller

(Bild: heise online)

Linux 6.3 öffnet mit eBPF und Rust den Blick auf Horizonte jenseits von C. Zudem zieht es bei Jumbopaketen und gemischten Subflows bei Multipath TCP nach.

Die aktuell nutzbaren Features des neuen Linux 6.3 lassen das Kernel-Release äußerlich wie ein Wartungs-Release erscheinen. Im Inneren bahnen sich jedoch größere Umbrüche an.

Von einigen architekturspezifischen Teilen in Assembler abgesehen, ist der Linux-Kernel in der Programmiersprache C geschrieben. Neue Funktionen und Treiber konnten nur als C-Code einfließen. Was lange als gesetzt galt, weicht zunehmend auf. Neben den rasanten Schritten, Rust in den Kernel zu integrieren, mausert sich auch eBPF zunehmend zu einer Alternative, um vormals C vorbehaltene Funktionalität in den Kernel bringen.

Linux 6.3 ermöglicht den Zugriff auf die "Red-Black Trees" des Kernels (rbtrees) aus eBPF-Programmen heraus. Die rbtrees sind eine Form von binären Suchbäumen, die der Kernel intensiv an vielen Stellen nutzt, unter anderem in Dateisystemen, in I/O- und CPU-Schedulern sowie Netzwerkprotokollen. eBPF-Programme können über eine (noch) rudimentäre API (Application Programming Interface) auf die Bäume zugreifen sowie Knoten hinzufügen und löschen. Diese API wird voraussichtlich in kommenden Kernel-Versionen noch ausgebaut.

Dieser direkte Zugriff auf die rbtrees aus eBPF heraus ist bemerkenswert. Bislang ließen sich komplexe Datenstrukturen aus dem Kernel lediglich als eBPF-Maps nutzen. Die eBPF-Engine im Kernel hatte weder die Privilegien noch die Notwendigkeit, komplexe Datenstrukturen im Kernel zu manipulieren.

Mit Linux 5.13 wurden bereits Kernel-Funktionen für eBPF [1] direkt erreichbar. Damals konnte dieser Schritt noch mit dem Ziel "Vereinheitlichen" erklärt werden. Durch die Beschränkungen beim Zugriff auf Kernel-Funktionen vor 5.13 war schlicht eine Parallelwelt in eBPF entstanden, um wichtige Kernel-Funktionen dennoch nutzen zu können. Vorreiter und Sonderfall war damals die "TCP Congestion Control".

Mit dem Öffnen der rbtrees für eBPF verhält es sich jetzt anders. Normalerweise fließen derartige neue APIs nur dann ein, wenn es bereits einen konkreten Anwendungsfall im Kernel selbst gibt. Diesen gibt es diesmal jedoch nicht. Vielmehr handelt es sich um eine Weichenstellung für die Zukunft. In diesem Zusammenhang lassen die Aussagen des eBPF-Maintainers Alexei Starovoitov auf der "Linux Plumbers Conference 2022" in Dublin aufhorchen. Die Absicht hinter der Arbeit an eBPF sei, eine sicherere Version der Programmiersprache C für die Kernel-Programmierung zu schaffen.

Damit bringt sich eBPF in Stellung, zukünftig als neue und sichere Alternative Funktionen in den Kernel einzubringen. Da eBPF zudem mit seinen Hilfsfunktionen einen Bogen zwischen Userspace und Kernelspace schlägt, erinnert das nun zweifellos an eine Microkernel-Architektur durch die Hintertür.

Rust ist zwar offiziell im Kernel seit Linux 6.1 [2] angekommen, aber auch mit den Rust-Erweiterungen in Linux 6.2 geht kaum etwas Nachvollziehbares über kleine Beispiele und Demos wie ein "Hello, world!" hinaus. Doch hinter den Kulissen geht das Klopfen und Hämmern am Rust-Grundgerüst erstaunlich schnell und praxisorientiert voran.

Ein praktischer Anwendungsfall ist ein Grafiktreiber für Apple-Hardware, den Asahi Lina in Rust programmiert und bereits im September 2022 im Entwicklerstadium [3] zum Laufen brachte. Für den Treiber benötigt die Entwicklerin eine Reihe von Rust-Modulen, die in der Kernel-Infrastruktur noch nicht existieren. Zu Kernel 6.3 steuert sie einige Puzzle-Teile für das große Rust-Bild bei. Eines der Module der Japanerin zeigt, welche Herausforderungen die Integration von Rust im Kernel mit sich bringt.

Lina brachte unter anderem ein Modul für Zeitfunktionen ein [4]. Im Kernel gibt es mehrere Zeitfunktionen ktime_*, die alle die Zeit im Wesentlichen als 64-Bit-Integer oder C-union diverser Integers je nach Variante in Sekunden oder Nanosekunden zurückliefern. Wie dieser Integer-Wert jedoch zu interpretieren ist, hängt von der Funktion ab, die ihn lieferte. So gibt ktime_get_boottime() die Sekunden seit dem Systemstart wieder, ktime_get_real() jedoch die Sekunden seit dem 01.01.1970 zurück, also in Epoch-/Unix-Zeit. Es ist demnach immer eine Differenz zu einem zeitlichen Fixpunkt, der variiert. Dieser Fixpunkt ist aber im zurückgelieferten Wert nirgends ersichtlich.

Eine 1-zu-1-Umsetzung der C-API ins Rust-Modul warf Fragen auf, ob dies mit Rusts Typsicherheit verträglich wäre. Rust bietet zwar eigene Zeittypen wie Instant für eine Differenz oder SystemTime für den Inhalt der Systemuhr. Diese erweisen sich aber als nicht nützlich. Konvertieren die ktime_*-Wrapper für Rust die Werte beispielsweise in Instant, bietet das nicht mehr Sicherheit als ein Integer. Schließlich kann etwa ein Instant-Wert von ktime_get_boottime() von einem geliefert durch ktime_get_real() subtrahiert werden. Syntaktisch zwar korrekt, aber programmlogisch höchst fraglich. Das versprochene Mehr an Sicherheit durch Rust wäre unterlaufen und an dieser Stelle durch ein gefährliches Trugbild ersetzt.

Schließlich war das Einführen eines neuen Typs, der sich an Instant anlehnt, jedoch den "Fixpunkt" einbezieht. Mit der Integration von Rust werden in C gelebte Praktiken neu überdacht und für Rust neu gestaltet werden müssen. Andernfalls droht das angestrebte Ziel – Rusts Sicherheit im Kernel zu nutzen – ins Wanken zu geraten.

Es zeigt aber auch, warum die Integration von Rust nicht im Tempo von Sieben-Meilen-Stiefeln erledigt sein kann. Daher ist es umso erstaunlicher, wie schnell Grundlagen für Rust geschaffen werden können. In Linux 6.3 kommen so für Referenzzähler (Reference Counter) der Typ Arc und zum Austausch von Zeigern zwischen Rust und C der Typ ForeignOwnable hinzu. Außerdem erfährt der Crate alloc eine Verschlankung. Trotz der Fortschritte kann unter Linux 6.3 als Mainline-Kernel noch kein "echtes" Modul in Rust programmiert werden.

Mit Linux 5.19 hielt BIG TCP für IP-Pakete in Jumbogröße [5] Einzug in den Kernel. Die Pakete in "Übergröße" waren jedoch auf IPv6 beschränkt. Linux 6.3 rüstet das Feature nun auch für IPv4 nach. Somit lassen sich jetzt Jumbopakete sowohl in IPv6, als auch in IPv4 nutzen.

Multipath TCP (MPTCP) versteht es nun auch, in einer Verbindung mit gemischten IPv4- und IPv6-Subflows umzugehen. Damit fällt die Beschränkung für eine Verbindung auf lediglich ein Protokoll, entweder IPv4 oder IPv6, weg.

Die Tage der alten API für die "Wireless Extensions" für das Verwalten und Kontrollieren von WLAN-Schnittstellen scheinen gezählt zu sein. Diese API wird bereits seit 2006 als Emulation mitgeschleppt. Für modernes WiFi 7 gemäß IEEE 802.11be unterstützt Linux 6.3 diese emulierte API nicht mehr. Die API kann nicht mehr alle unter WiFi 7 verfügbaren Features konfigurieren. Der Einsatz der alten API generiert ab jetzt auch eine Warnung. Ein Umstieg auf die neue API ist Entwicklern jetzt dringend angeraten.

Um über 150.000 Zeilen Code erleichtert den Kernel der Wegfall veralteter und unbenutzter ARM-SoC-Boards (System on a Chip). Das Mitschleppen dieser Altlasten führte zunehmend bei Änderungen zu Konflikten. Einen Überblick über das Weggefallene verschafft der zugehörige git-Commit [6].

User-Mode-Linux (UML) unterstützt im neuen Kernel in Rust-geschriebenen Code. Dies allerdings nur auf x86_64-Systemen.

Die chinesische CPU-Architektur LongArch erhält Kernel-Address-Layout-Randomization, Hardware-Break- und -Watch-Points. Zudem können nun kprobes zum Debugging auf LongArch genutzt werden.

Das tmpfs beherrscht jetzt ID-mapped Mounts [7]. Somit lassen sich auch in Container tmpfs-Dateisysteme mit Remapping einbinden.

NFS (Network File System) legt bei der Kryptografie nach und erlaubt jetzt AES-SHA2-basierte Verschlüsselung. Dies sowohl auf der Client-, als auch auf der Server-Seite.

Von vielen zwar schon fast vergessen, aber Linux ließ sich bis zum jetzigen Release mit drei Compilern bauen. Neben dem Urgestein gcc und LLVM/clang, konnte der Kernel auch mit Intels C-Compiler ICC übersetzt werden. Linux 6.3 reduziert die Palette auf gcc und clang. ICC fällt dem Rotstift zum Opfer. Das hat jedoch keine politischen Gründe, sondern eine ganz praktische, technische Ursache.

Intel schwenkte bereits im Dezember 2020 mit der Freigabe seines neuen ICC (oneAPI DPC++) von seinem proprietären Code auf eine LLVM/clang-basierte Variante um. Der ursprüngliche ICC erhielt damals den neuen Namen "Intel C++ Compiler Classic". Vom Wegfall ist lediglich die klassische Variante betroffen.

Bereits im Oktober des vergangenen Jahres diskutierten die Kernel-Entwickler diese Maßnahme. Viele Stellen im Kernel-Code beziehen sich nur noch auf gcc und clang. Der ICC ist schon lange nicht mehr aktiv im Fokus der Entwickler. Es ist davon auszugehen, dass der Kernel sich mit dem klassischen ICC praktisch ohnehin nicht mehr compilieren lässt. Nachdem die Ankündigung, den ICC zu streichen, keine lauten Aufschreie nach sich zog, schritten die Entwickler nun zur Tat. Der klassische ICC kann den Kernel 6.3 jetzt offiziell nicht mehr bauen.

Die neue oneAPI-Variante von Intel kann Linux 6.3 vermutlich noch übersetzen. Da dieser Compiler auf LLVM/clang basiert, sollte sich dieser den Kernel-Build-Prozess der clang-Variante zu Nutze machen können. Allerdings ist aktuell kein Projekt bekannt, das den Kernel überhaupt mit irgendeiner Variante von Intels Compiler übersetzt. Zumindest kein offen einsehbares Projekt. In geschlossenen Entwicklungsabteilungen von Firmen und Institutionen mag dies anders aussehen.

Linux 6.3 könnte als Wartungs-Release durchgehen, säubert es doch an vielen Stellen (WiFi, ICC) den Code und stellt Neuerungen seiner Vorgänger breiter auf (MPTCP, BIG TCP). Der praxisorientierte Ausbau von Rust und das Neupositionieren von eBPF-Programmen eröffnet neue Horizonte abseits von C. Zudem birgt das Infragestellen eingefahrener Strategien auch die Chance, das eine oder andere in C implementierte neu zu bewerten, vielleicht auch zu härten. eBPF als Risikofaktor [8] scheint kein Thema mehr zu sein. Insgesamt deutet der als Wartungs-Release nutzbare neue Kernel eine spannende Zukunft und neue Entwicklungen an.

Der neue Kernel steht wie immer auf https://kernel.org zum Download bereit. Alle Änderungen können im Linux-Kernel-Changelog [9] nachgelesen werden.

(dmk [10])


URL dieses Artikels:
https://www.heise.de/-8977938

Links in diesem Artikel:
[1] https://www.heise.de/news/Linux-5-13-mit-Angriffsschutz-und-Sandbox-6129642.html
[2] https://www.heise.de/news/Linux-6-1-als-naechster-Langzeit-Kernel-erschienen-7393140.html
[3] https://www.reddit.com/r/rust/comments/xqzbpz/asahi_lina_got_the_apple_m1_driver_working/
[4] https://lore.kernel.org/all/20230221-gpu-up-time-v1-1-bf8fe74b7f55@asahilina.net/
[5] https://www.heise.de/news/Linux-5-19-IP-Pakete-in-Jumbogroesse-und-Unterstuetzung-fuer-LoongArch-Befehlssatz-7203904.html
[6] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ff0c7e18629b
[7] https://www.heise.de/news/Linux-5-12-Standard-Release-mit-neuem-Hypervisor-ueberarbeitetem-ID-Remapping-6024865.html
[8] https://www.heise.de/news/Linux-5-13-mit-Angriffsschutz-und-Sandbox-6129642.html
[9] https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.3
[10] mailto:dmk@heise.de