Date: Fri, 22 Aug 2025 19:10:15 +0300 From: Konstantin Belousov <kostikbel@gmail.com> To: hackers@freebsd.org Subject: My experiences with Rust Message-ID: <aKiWZ1I3pqZSOsfk@kib.kiev.ua>
next in thread | raw e-mail | index | archive | help
There was a long and hot thread about 'Rust in base' recently. Since I did used the rust language to write some very OS-specific utilities, I decided to share my experience. If written in C, yjr w tools would definitely end up in base. I do not have any huge investments in Rust, neither emotional nor huge time spent learning it. Still, I decided to use Rust since I was curious and the hate/love dihotomy for just a language felt weird. I used Rust for two utilities, first one is https://github.com/kostikbel/pollinfo ports:sysutils/pollinfo (disclosure: the work was sponsored by The FreeBSD Foundation) the second one is https://github.com/kostikbel/ktcplist ports:net/ktcplist (another disclosure: the work was sponsored by Nvidia networking BU). In both cases, it was a common theme to retrieve system information in the binary format by a direct syscall invocation, then provide a user- or machine-friendly output format for consumption. The pollinfo utility was a part of the efforts to make event wait observable. There was a 'procstat kqueue' command added that reported the kqueue(2) events that process wait for. Similarly, a residual tool for select(2)/(p)poll(2) interrogation felt natural. There were already the pre-existing kernel facilities (ptrace) that were needed to write the tool (but transparent ptrace attach made things better, just a disgress). For ktcplist, the more natural action would be to extend netstat(8) then to write a new tool, but I cannot make myself to use libxo. It is less painful to write Rust then to try to use libxo, at least for me. But first, I need to define and implement the kernel interface to export the ktls connection list to userspace, unlike the pollinfo case. Nice things about using Rust: - after typechecking, the program just worked. This was an experience very similar to haskell. Of course, there were unsafe {} blocks, and part of the good design was to contain the unsafety to only the code that advanced iterators over the elements of the kernel returned array. If this was followed, it was quite nice environment to work with WRT correctness. Problematic parts: 1.Rust uses its own so called libc bindings. This is a Rust crate containing collections of pure bindings both to libc and kernel interfaces. After gettting the kernel interface done, you have to write separate patches for Rust libc and then work to upstream it, before the new kernel feature becomes useful for Rust code. A silly alternative is to maintain the rust libc fork, which is not sustainable. Fortunately, the libc maintainers are very responsible (count for a week to get a feedback). 2.Quite surprising, is the portability. It is a known sore with C that you need to use %jd and (intmax_t) cast to get platform-independent printing of ints/longs. For Rust, a similar issue is the signess of char. When providing Rust libc binding, and testing either amd64, it is very tempting to use i8 as the type for char kernel native type, which breaks everywhere outside amd64. You must use libc::c_char. This is due to Rust type construct being an equivalent of C typedef. 3.It was more prominent for ktcplist then for pollinfo, so I will explain it there. Nvidia verification team requested that ltcpdump has machine-readable output, preferrably json. Adding serde serialization to json was trivial, and solved the problem, by the cost of adding another: making the small utility depend on several dozens of the external packages. This makes it very problematic if we ever want to allow Rust in base and include ktcpdump as part of it. I do not have any conclusions. I am happy that both utilities live in ports (thanks to gleb@), and they should be left there IMO.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?aKiWZ1I3pqZSOsfk>
