Repository navigation
Lunatik v5.0
Lunatik 5.0 brings eBPF into Lua scripts, with pinned maps and Traffic Control and sched_ext programs that call Lua, along with filesystem notification, a netlink stack written in Lua, per-CPU runtimes and a bytecode compiler. A review of every module fixed crashes, hangs and leaks, made interrupt-context runtimes refuse what would sleep, and made the APIs consistent across modules; scripts written for 4.4 need the changes listed under Changes to existing APIs.
Highlights
- eBPF maps:
bpfopens a pinned eBPF map with one constructor per map type, andbpf.mapturns it into a table a script indexes, assigns and iterates, or into a queue withpush,popandpeek. - Traffic Control: with
tc, a TC/eBPF program calls Lua at the ingress and egress layers of the network stack;examples/sniclassifyclassifies egress traffic by its TLS server name. - sched_ext: with
scx, a sched_ext program calls Lua for task scheduling. - Filesystem notification:
fsnotifyplaces marks on files, directories and mounts and hands their events to a Lua callback, permission events included;examples/fsmonitorlogs what changes in a directory, andexamples/execguardrefuses anexecwhose name is not on an allowlist. - Netlink in Lua: the
netlinknamespace speaks generic netlink, routing (rt: links, addresses, routes and rules) and nl80211 (interfaces, stations, access points) from a script, andnetlink.channelmulticasts to user space from softirq;examples/linkflapandexamples/netfailoverreact to links going up and down. - Per-CPU runtimes:
lunatik.percpuandlunatik run --percpucreate one runtime per CPU sharing one registration, so a hook runs on the CPU it fires on. - Bytecode:
lunatik compilebuilds chunks the kernel loads, with the luac of the kernel's own Lua configuration, for a target of either byte order. - More modules:
taskfor the Linux task interface,structfor fixed C struct layouts, andclassfor object-style Lua modules. - Lua 5.5.1.
- New examples: dropreason answers "why is my packet dying?" from the kernel's drop reason, and the six above.
- Documentation: a site at https://luainkernel.github.io/lunatik, with a guide, the reference of every module and the C API.
Fixes
- Crashes:
skb:forward()panicked on a packet whose MAC header sits pastskb->data(#1291);skb:data()in a tc callback could free the head the calling BPF program still points into (#1369); an object left inlunatik._ENVoutlived its module and was released into freed module memory at unload (#1390);thread:stopread a runtime its body's end released (#1428); a view of a copy's data outlived the copy (#1275); a runtime could clonelunatik_envafter its release (#1387); a recursion through C ran past the kernel stack, and now raises "C stack overflow" (#1669). - Sleeping in interrupt context: once armed, a softirq or hardirq runtime refuses a
requirethat opens a file or loads a binding its body did not load (#1282, #1729),require("io")(#1421),linux.netns(#1283),linux.schedule(#1194),hid.register(#864),darken.run(#1256) and a netfilter registration (#1276), and a monitored method allocates with its object's gfp under the object's lock (#1487). - Callbacks: probe and notifier callbacks get their arguments inside a protected call (#1188); netfilter no longer leaks a packet a callback answers with
STOLEN,REPEATorSTOP(#1280); a hid callback that raises no longer leaves its data object on the kernel's buffer (#1361); a callback's errno from the kernel's internal block no longer reaches io_uring (#1737). - Leaks and warnings: aead frees its output buffer when pushing the result fails (#1759); darken refuses a ciphertext past kmalloc's largest block without the allocator's warning (#1744); netfilter refuses a family or hook with no hook table instead of reaching a kernel warning (#1745);
tostringof a shared data object reads it under its lock (#1504). - Values:
skb:data("net")andskb:data("mac")are two views, so taking one no longer moves the other (#1289); autogen's unsigned 32-bit constants reach Lua without sign extension (#1285);netlink.rt.addr's address is the local one, and a point-to-point address reports its peer (#1286). - CLI:
lunatik reloadunloads every loaded module, and refuses to replace a module loaded from another build (#737, #1381).
Before upgrading
- Lunatik supports Linux 6.6 and later; the 5.x kernel line is no longer built.
- Unload the previous release with its own CLI before installing 5.0, or reboot: a driver loaded by a release before 5.0 fails every command of the 5.0 CLI with
loaded from another build. - 32-bit ARM is not supported in 5.0: the OpenWrt build fails on missing division helpers (#418), and autogen drops the
linux.*constants there (#1349). - On Linux 7.1 and later,
luacrypto.koloads only on a kernel that builds a user of the crypto rng API, such asCONFIG_CRYPTO_DRBG(#1415). xdpandtcbuilt without the running kernel's BTF (make btf_installbeforemake) load with their kfunc unregistered andmissing module BTFin the log, and an eBPF program that calls the kfunc then fails to load (#1607).
Changes to existing APIs
- Outcomes and failures (#1301, #1327): an expected outcome, a timeout, a full queue, nothing to read or an absent device, returns nil, with the errno's name as a second value when the kernel gave one, or false; a failed kernel call raises the errno's name.
- Hook decisions (#1296, #1298): a hook callback's decision is its return value in every hook, xdp, tc and sched included; a device or hid callback fails an operation by returning a negative errno.
- stop, close and
__close(#1313): a registration stops withstopand a resource closes withclose, both idempotent, and every such handle offers__close; netfilter and hid gainstop. Dropping a handle stops nothing, a child runtime whose script registered a hook included (#1042). - No positional booleans (#1302): runner, probe and socket take a table of options where a boolean changed a call's behaviour or arity.
- Waits (#1757): a wait's timeout is a millisecond count from 0 to
INT_MAX, or none for no bound. - Callbacks (#1754, #1758): device, hid and probe refuse a callback field that is not a function, and a callback's errno from the kernel's own block is refused and logged.
- Class names (#1299): a class is named by its module and type,
crypto.aead,bpf.hash,lunatik.runtime, as a type error quotes it. - Requiring (#1423, #1729): a binding is found before a Lua file of its name, the driver installs as
lunatik/driver.lua, the top-level names Lunatik reserves are listed, and an armed interrupt-context hook requires only what its body loaded. - netfilter (#1294, #1745): a hook registered without a mark sees every packet, and
registerrefuses, without of bounds, a family netfilter keeps no hook table for and a hook past its family's table. - notifier (#1746): a callback's return reaches the chain only as a
linux.notifycode. - skb (#1295, #1539, #1325, #1747, #1748):
skb:data()starts atskb->data,data("net")at the network header anddata("mac")at the MAC header, and a view whose header is absent is nil;resizeanswers whether it resized and keeps a checksum the stack still fills;mark,priorityandconnmarkread when given nil;skb.attris removed. - probe (#1311): a handler receives the target and one
regsobject. - hid (#1312, #1751): one table per device, the same in every callback, and a
removecallback; the report a callback is handed is closed once it returns, also when it raises. - socket (#1304, #1305, #1317, #1755): an AF_PACKET address in host order, the same shape in and out;
socket.raw.newbuilds the socket and closes it when its bind raises; a value out of its range raises;socket.newanswers nil andESRCHfor a pid no task holds, aslinux.netnsdoes. - signal (#1324):
killonly, with the pid resolved in the initial pid namespace. - darken (#1323): an authenticated format,
gcm(aes). - cpu (#1309, #1749):
cpu.maxidand the iteratorscpu.possible,cpu.presentandcpu.online;cpu.statsanswers nil for a CPU that is not online. - rcu (#1322):
rcu.mapisrcu.foreach, and its callback's return is ignored. - crypto (#1321, #1750):
rng:seedsize, and hkdf without a public hmac;aead:decryptanswers nil andEBADMSGfor a message that does not authenticate. - data (#1756):
getstringanswers an empty string, andsetstringwrites nothing, for a zero length up to the end. - fsnotify (#1753): a mark ends with
stop, which a second call and__closetake as well. - linux, thread, data, bpf (#1303):
linux.difftime,thread.current,data:getnumber/setnumberand#on a bpf map are removed, andlinux.ifaddrislinux.hwaddr. - linux.* (#1297, #1308): one table per kernel family; each hook family's verdict table is
action, andlinux.bpf.map_typestands apart from the update flags. - runner (#1314):
listreturns a sequence of names. - util (#1320): the test harness moves to
tests.lib, and the hex codec returns one value. - fib is removed;
netlink.rt.rulesupersedes it. - CLI (#1315): the CLI still reads the 4.4 command grammar, and the
/dev/lunatikprotocol is internal to it.
Known issues
Each is tracked in the issue it names, and the documentation of its module names the first five (#1727, #1752):
- A sched_ext callback runs under its CPU's runqueue lock, where
print, a completion'scompleteor a mailbox'ssendcan hang the CPU (#1718). - A netdevice callback's
STOPorBADon an event the kernel does not veto stops the chain (#1739). - An
rcutable a probe handler writes deadlocks against a writer that holds it with interrupts on (#1740). - A probe handler runs Lua in NMI, where its allocation can take a lock its CPU holds (#1741).
- A netlink channel used from a hardirq runtime reaches a warning through the nlmon tap (#1742).
skb:data()andskb:resize()write into a head a clone shares (#1260).
Contributors
Lourival Vieira Neto (@lneto), Ashwani Kumar Kamal (@sneaky-potato), Harshdeep Singh (@Harshdeep-creator) and Prath (@prath47); @prath47 and @Harshdeep-creator made their first contributions in #654 and #741.
Full Changelog: v4.4.1...v5.0