Skip to content

R5 eBPF: the interpreter, maps and cgroup programs #537

Closed

Description

@tamnd

Part of #14.

rukernel has classic BPF only: the seccomp filters (core/rk-proc/src/bpf.rs) and SO_ATTACH_FILTER (net/rk-net/src/filter.rs). There is no bpf(2) system call, no eBPF interpreter, no map and no bpffs. LTP bpf_map01 and bpf_prog01 to bpf_prog07 do not apply now ("__NR_bpf not supported"). spec/11-bpf.md section 11.7 puts the interpreter, the maps and the helpers for networking and cgroups in R5, and the JIT, BTF and CO-RE in R7.

Scope

  • The bpf(2) entry with the size rules of union bpf_attr, map file descriptors with their fdinfo, and BPF_MAP_CREATE, BPF_MAP_LOOKUP_ELEM, BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM and BPF_MAP_GET_NEXT_KEY for the hash, array, per CPU hash, per CPU array and LPM trie maps. Add the sysctl kernel.unprivileged_bpf_disabled with the value 2. Test: LTP bpf_map01. Exit: bpf_map01 passes. bpf: add bpf(2) with hash, array, per CPU and LPM trie maps #568: bpf_map01 passes on x86_64, and the new init boot checks pass on x86_64 and arm64.
  • The verifier, first part: a port of the checks of kernel/bpf/verifier.c for the program types of this issue. It tracks the register types and bounds, the stack, the bounds of map values and the argument types of each helper, and it refuses back edges that it cannot bound. It gives the verifier log. Test: LTP bpf_prog02 and bpf_prog05, and kselftest test_verifier (add bpf/test_verifier to tools/kselftest/build.sh). Exit: for each program of test_verifier that this issue covers, rukernel accepts or refuses as the reference does. Write the result to tools/kselftest/bpf.md. bpf: the verifier gives the result of Linux for test_verifier #701: test_verifier gives 281 PASSED, 510 SKIPPED and 0 FAILED for the five program types of this issue. bpf_prog02 passes, and bpf_prog05 gives TCONF, as on the reference with kernel.unprivileged_bpf_disabled=2.
  • The interpreter: all ALU64, ALU32, JMP, JMP32, load, store and atomic instructions of RFC 9669, tail calls, and the helpers that systemd uses (map_lookup_elem, map_update_elem, map_delete_elem, get_current_pid_tgid, get_current_uid_gid, get_current_cgroup_id, ktime_get_ns, get_prandom_u32, skb_load_bytes). Test: LTP bpf_prog01, bpf_prog03, bpf_prog04, bpf_prog06 and bpf_prog07. Exit: all bpf_prog tests reach the pass set of the reference. bpf: run calls of functions, BPF_LD_[ABS|IND] and loads of map values #678: calls of functions of the program, BPF_LD_[ABS|IND] and loads of map values. bpf: add BPF_MAP_TYPE_PROG_ARRAY and bpf_tail_call #686: BPF_MAP_TYPE_PROG_ARRAY and tail calls. bpf_prog01 to bpf_prog04 pass, and bpf_prog05 to bpf_prog07 give TCONF, as on the reference with kernel.unprivileged_bpf_disabled=2.
  • bpffs at /sys/fs/bpf, with BPF_OBJ_PIN and BPF_OBJ_GET for maps, programs and links. Test: a new check in the systemd boot test pins a map, gets it again and reads a value. Exit: the check passes, and sys-fs-bpf.mount is active. xtask: pin a BPF map in the systemd boot test #607, xtask: check the bpf mount of the systemd test in mountinfo #614, bpf: check the pins of a program and a link in bpffs #630: the systemd boot test pins a map, a program and a link in /sys/fs/bpf and gets them again, and /proc/self/mountinfo shows a bpf file system at /sys/fs/bpf. systemd mounts /sys/fs/bpf itself and makes no sys-fs-bpf.mount unit, also on Linux, so the test checks mountinfo and not the unit.
  • Cgroup programs: BPF_PROG_ATTACH, BPF_PROG_DETACH, BPF_PROG_QUERY and BPF_LINK_CREATE with BPF_F_ALLOW_MULTI and BPF_F_ALLOW_OVERRIDE, and the effective program arrays of each cgroup. Run BPF_PROG_TYPE_CGROUP_DEVICE at the open and the mknod of a device file. Run BPF_PROG_TYPE_CGROUP_SKB at the ingress and egress of IPv4 and IPv6, and BPF_PROG_TYPE_CGROUP_SOCK and BPF_PROG_TYPE_CGROUP_SOCK_ADDR at socket, bind and connect. Test: the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs from the systemd-tests package. Exit: the three tests pass. xtask: the sdbpf boot test runs the systemd unit tests for cgroup BPF programs #705: the sdbpf boot test runs the three tests on x86_64, and all three exit 0. The kernel needed no change. xtask has no systemd tests on arm64, so the init -- only bpf test covers the cgroup programs on arm64.
  • systemd IP accounting and the device controller in the systemd boot test. Start a unit with IPAccounting=yes that pings the host, and a unit with DevicePolicy=closed that opens /dev/vda. Exit: systemctl show -p IPIngressBytes,IPEgressBytes gives values that are not zero, and the open of /dev/vda gives EPERM. xtask: check IP accounting and DevicePolicy=closed in the systemd boot test #632: IPIngressBytes and IPEgressBytes are 84 and 84 after one ping of the gateway, and the open of /dev/vda gives EPERM.

Done when

systemd IP accounting and the device controller work. This is the exit of the second item of #14.

Test each task on x86_64 and on arm64. Give the result of both in the PR body.

Linux reference: kernel/bpf/syscall.c, kernel/bpf/verifier.c, kernel/bpf/core.c, kernel/bpf/cgroup.c, kernel/bpf/hashtab.c, kernel/bpf/lpm_trie.c, kernel/bpf/inode.c.

Activity

  1. added
    kind/featureNew behavior or a new part.
    area/bpfBPF: the verifier, the JIT, maps and BTF.
    on Nov 2, 2026
  2. tamnd commented on Nov 4, 2026

    @tamnd
    OwnerAuthor

    The first item is done in #568. It adds bpf(2) in the new crate rk-bpf, with the size rules of union bpf_attr, map fdinfo, BPF_MAP_FREEZE, and the hash, array, per CPU hash, per CPU array and LPM trie maps. The sysctl kernel.unprivileged_bpf_disabled has the value 2. LTP bpf_map01 passes on x86_64 and is now in tools/ltp/tests.txt. The 20 new bpf checks of the init boot test pass on x86_64 and arm64. #569 is empty because the PR script ran again after the merge. Next: the interpreter, BPF_PROG_LOAD and a first verifier.

  3. tamnd commented on Nov 4, 2026

    @tamnd
    OwnerAuthor

    PR #577 merged the second item: BPF_PROG_LOAD, the interpreter of RFC 9669 with the helpers, and a first safe verifier. LTP bpf_map01 and bpf_prog01 to bpf_prog04 pass on x86_64, and bpf_prog05 to bpf_prog07 give TCONF as on Linux. The init checks pass on x86_64 and arm64. The item stays open, because calls to functions of the program, tail calls, kfuncs, BPF_LD_[ABS|IND] and state pruning are not done.

  4. tamnd commented on Nov 4, 2026

    @tamnd
    OwnerAuthor

    PR #583 merged bpffs with BPF_OBJ_PIN and BPF_OBJ_GET for maps and programs. mount -t bpf bpf /sys/fs/bpf works, a pinned map stays after its last descriptor closes, and BPF_OBJ_GET gives the map again. The new init checks pass on x86_64 and arm64. The item stays open, because rukernel has no BPF links yet, and the check in the systemd boot test and sys-fs-bpf.mount are not done.

  5. tamnd commented on Nov 4, 2026

    @tamnd
    OwnerAuthor

    #589 is merged. It adds the object IDs, BPF_OBJ_GET_INFO_BY_FD and the BPF links of kernel/bpf/syscall.c of Linux. bpffs can pin a link. The systemd boot test checks that sys-fs-bpf.mount is active, and init takes only bpf to run only the BPF checks.

    Tests: cargo test -p rk-bpf passed. In QEMU on x86_64, all 31 BPF checks of the init test are ok. The boot test timed out under load (load average 30 to 43). It stopped in the test "1000 threads start" and at "cpu.max limits a busy loop", before or after the BPF checks. On arm64, RK_CMDLINE="-- only bpf" RK_AARCH64_TESTS=init cargo xtask boot-test aarch64 passed with 44 checks ok at load 47.

    The bpffs item is not ticked yet. The pin, get and read check in the systemd boot test comes in the next PR.

  6. tamnd commented on Nov 4, 2026

    @tamnd
    OwnerAuthor

    #591 is merged. It adds BPF_PROG_ATTACH, BPF_PROG_DETACH, BPF_PROG_QUERY and BPF_LINK_CREATE for a cgroup, with BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE, BPF_F_REPLACE, BPF_F_BEFORE and BPF_F_AFTER, and the effective arrays of each cgroup. The verifier takes the cgroup program types.

    Tests: cargo test -p rk-bpf -p rk-fs-cgroup passed (58 and 5). RK_CMDLINE="-- only bpf" boot tests passed on x86_64 (pvh, bzImage and UEFI) and on arm64, with 53 checks ok. The load average was 28 to 37.

    The cgroup programs item is not ticked yet. The hooks remain: DEVICE at open and mknod, CGROUP_SOCK at socket, CGROUP_SKB at ingress and egress, and SOCK_ADDR at bind and connect. The systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs also remain.

  7. tamnd commented on Nov 5, 2026

    @tamnd
    OwnerAuthor

    #595 runs the device and socket programs of cgroup2. BPF_PROG_TYPE_CGROUP_DEVICE runs at the open and the mknod of a device file, and BPF_CGROUP_INET_SOCK_CREATE runs at socket of IPv4 and IPv6. A program that gives 0 refuses the access with EPERM.

    Tests: cargo test -p rk-vfs -p rk-bpf -p rk-syscall passed (91, 58 and 0). RK_CMDLINE="-- only bpf" boot tests passed on x86_64 (pvh, bzImage and UEFI) and on arm64, with 57 checks ok. The load average was 26 to 34.

    The cgroup programs item is not ticked yet. These parts remain: CGROUP_SKB at ingress and egress, SOCK_ADDR at bind and connect, and the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs.

  8. tamnd commented on Nov 5, 2026

    @tamnd
    OwnerAuthor

    #597 runs the packet programs of cgroup2 on IPv4 and IPv6 sockets. BPF_CGROUP_INET_INGRESS runs on each datagram and TCP segment that a socket of the cgroup gets, and BPF_CGROUP_INET_EGRESS runs on each packet that it sends. A socket keeps the cgroup of its creator. A program that gives 0 drops the packet, and a send then gives EPERM.

    Tests: cargo test -p rk-net -p rk-net-inet -p rk-bpf -p rk-syscall passed (58, 74, 108 and 0). The x86_64 -- only bpf boot tests passed with pvh, bzImage and UEFI (62 checks ok, load average 38). The arm64 kernel did not build because other jobs filled the disk of server2.

    The cgroup programs item is not ticked yet. These parts remain: SOCK_ADDR at bind and connect (the next PR), and the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs.

  9. tamnd commented on Nov 5, 2026

    @tamnd
    OwnerAuthor

    #600 adds the address programs of cgroup2, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, at bind and connect of TCP and UDP sockets for IPv4 and IPv6. The verifier takes the context struct bpf_sock_addr with the access rules of Linux. A program can change the address and the port, a program that gives 0 makes the call give EPERM, and a bind program can let a low port skip the check of CAP_NET_BIND_SERVICE.

    Tests: cargo test -p rk-bpf -p rk-syscall passed (60 and 0). The -- only bpf boot tests passed on x86_64 (pvh, bzImage and UEFI) and on arm64, with 69 checks ok. The load average was 18 to 28.

    The cgroup programs item is not ticked yet. These parts remain: the sendmsg, recvmsg, getpeername and getsockname address types, BPF_CGROUP_INET_SOCK_RELEASE and the post-bind types, and the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs.

  10. tamnd commented on Nov 5, 2026

    @tamnd
    OwnerAuthor

    #607 adds a bpffs check to the systemd boot test: rk-bpfpin pins an array map in /sys/fs/bpf, which sys-fs-bpf.mount mounts, gets it again with BPF_OBJ_GET and reads the value. The rk-check service runs it.

    Tests: the kernel and the initramfs built. On server2 under load (load average 27), systemd stopped at the generators with "Failed to fork off sandboxing environment for executing generators: Protocol error", which is known on main under load. On the idle server1, systemd reached basic.target, but systemd-logind.service failed to start again and again, and the boot did not get to rk-check in 900 seconds. So rk-bpfpin has not run in a full boot yet.

    The bpffs item is not ticked yet. What remains: find why systemd-logind.service fails, then see the systemd boot test pass with rk-bpfpin.

  11. tamnd commented on Nov 5, 2026

    @tamnd
    OwnerAuthor

    The bpffs item: #614 fixes the check of the systemd boot test. The test asked for systemctl is-active sys-fs-bpf.mount, but systemd mounts /sys/fs/bpf itself as an API file system (mount_table in src/shared/mount-setup.c), and mount_setup_unit makes no unit for an API mount point. So sys-fs-bpf.mount cannot be active, also on Linux. The test now reads /proc/self/mountinfo and checks that /sys/fs/bpf has the type bpf.

    Result on server1 (load average 0.75, 0.89, 0.82), with #611 for systemd-logind: "rk-systemd: state running", "rk-systemd: /sys/fs/bpf bpf", "rk-bpfpin: pass", "rk-systemd: pass". rk-bpfpin pins an array map, gets it again with BPF_OBJ_GET and reads a value.

    I did not tick the item. The exit text names sys-fs-bpf.mount, which cannot exist, so it needs a change to "/sys/fs/bpf is a bpf mount". The item also asks for the pin of programs and links, and the boot test checks only a map.

  12. tamnd commented on Nov 6, 2026

    @tamnd
    OwnerAuthor

    #623 adds the cgroup programs that were missing, as kernel/bpf/cgroup.c of Linux:

    • BPF_CGROUP_UDP4_SENDMSG and BPF_CGROUP_UDP6_SENDMSG on the address of a UDP send. A program of BPF_CGROUP_UDP6_SENDMSG can change the source of IPV6_PKTINFO.
    • BPF_CGROUP_UDP4_RECVMSG and BPF_CGROUP_UDP6_RECVMSG on the source address of a UDP receive.
    • The getsockname and getpeername types for IPv4 and IPv6, also on the address of accept.
    • The 5 Unix types: connect, sendmsg, recvmsg, getpeername and getsockname.
    • BPF_CGROUP_INET4_POST_BIND and BPF_CGROUP_INET6_POST_BIND. A program that gives 0 frees the port, and bind gives EPERM.
    • BPF_CGROUP_INET_SOCK_RELEASE at the last close of an IPv4 or IPv6 socket.

    The programs use the cgroup of the socket, as Linux does.

    Test: the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs are not in the systemd image. tools/systemd/build.sh installs only systemd, kmod, systemd-sysv and dbus, and there is no systemd-tests package. So a new focused check in the init boot test (test_bpf_cgroup_sock_msg) tests each new hook in a cgroup. RK_CMDLINE="-- only bpf" passes on x86_64 and arm64, load average 13 to 14 on server2.

    The item stays open: the code of the item is done, but its exit (the three systemd unit tests) cannot run until the image has them. Next: the bpffs pin checks for a program and a link, then IP accounting and the device controller in the systemd boot test.

  13. tamnd commented on Nov 6, 2026

    @tamnd
    OwnerAuthor

    #630 adds checks of BPF_OBJ_PIN and BPF_OBJ_GET for programs and links:

    • rk-bpfpin of the systemd boot test pins a program of BPF_PROG_TYPE_CGROUP_SKB and a link of the program to the root cgroup, gets them again with BPF_OBJ_GET, and checks the type and the IDs. The pinned link keeps the program attached after its descriptors close, and the unlink of the pin detaches it.
    • test_bpffs of the init boot test does the same checks on a new cgroup.

    Results: the -- only bpf init boot test passes on x86_64 and arm64 (server2, load average 16 to 19). The systemd boot test passes in 168 s on server1 (load average 0.1 to 1.0, TCG): rk-systemd: /sys/fs/bpf bpf, rk-bpfpin: map pass, program pass, link pass, and rk-systemd: pass.

    systemd mounts /sys/fs/bpf itself (mount_table in src/shared/mount-setup.c) and makes no sys-fs-bpf.mount unit, also on Linux. So the test checks /proc/self/mountinfo, and I ticked the bpffs item with #607, #614 and #630.

    What remains: the cgroup item waits for the systemd unit tests, which are not in the image. Next is the IP accounting and DevicePolicy=closed item in the systemd boot test.

  14. tamnd commented on Nov 7, 2026

    @tamnd
    OwnerAuthor

    #632 adds checks of systemd IP accounting and the device controller to the systemd boot test:

    • rk-ipacct.service has IPAccounting=yes and runs rk-cgunit ping. The program sets 10.0.2.15/24 on the network device and pings the gateway 10.0.2.2 of the user network of QEMU on a raw socket.
    • rk-dev.service has DevicePolicy=closed and runs rk-cgunit open /dev/vda. The program exits with 0 only if the open gives EPERM.
    • The QEMU machine of the test has a virtio-blk disk and a virtio-net device. No kernel change was necessary.

    Result: the systemd boot test passes in 161 s on server1 (load average 0.1 to 1.1, TCG). IPIngressBytes and IPEgressBytes are 84 and 84 (one echo request and one reply), and the open of /dev/vda gives EPERM. I ticked the item with #632.

    What remains of #537:

    • The verifier item: LTP bpf_prog02 and bpf_prog05, and kselftest test_verifier with the result in tools/kselftest/bpf.md.
    • The interpreter item: LTP bpf_prog01, bpf_prog03, bpf_prog04, bpf_prog06 and bpf_prog07 must reach the pass set of the reference.
    • The cgroup item: the code is done (Run the cgroup programs of sendmsg, recvmsg, the names, Unix sockets, post_bind and release #623 and earlier PRs), and the focused init checks pass. The exit asks for the systemd unit tests test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs. They are not in the systemd image (tools/systemd/build.sh does not install systemd-tests), so the item stays open until the image has them.
  15. tamnd commented on Nov 9, 2026

    @tamnd
    OwnerAuthor

    #678 adds calls of functions of the program, BPF_LD_[ABS|IND], BPF_PSEUDO_MAP_VALUE and fd_array to the interpreter and the verifier, with the errors and messages of Linux without a JIT.

    Test results:

    • cargo test -p rk-bpf: 69 passed. clippy: no new warning.
    • x86_64 init boot test with -- only bpf, built on server2 and run on server1: bzImage and UEFI pass (load 0.30).
    • arm64 init boot test with -- only bpf on server2: pass (load 14.5).

    The interpreter item stays open. Tail calls (BPF_MAP_TYPE_PROG_ARRAY) and the LTP bpf_prog runs come next.

  16. tamnd commented on Nov 10, 2026

    @tamnd
    OwnerAuthor

    #686 adds BPF_MAP_TYPE_PROG_ARRAY and bpf_tail_call, as kernel/bpf/arraymap.c and JMP_TAIL_CALL of Linux. With #678, the interpreter item is done.

    Test results:

    • cargo test -p rk-bpf: 75 passed. Clippy gives no new warnings.
    • x86_64 boot-test init with -- only bpf (server1, load 0.13 to 0.35): exit 33, each check passed, with 9 new checks for tail calls.
    • x86_64 ltp (server1, load 0.35 to 0.60): bpf_map01 and bpf_prog01 to bpf_prog04 pass. bpf_prog05, bpf_prog06 and bpf_prog07 give TCONF, as on Linux 7.3 with kernel.unprivileged_bpf_disabled=2, because they drop CAP_BPF.
    • arm64 boot-test aarch64 with RK_AARCH64_TESTS=init and -- only bpf (server2, load 11.3 to 29.1): pass.
  17. tamnd commented on Nov 12, 2026

    @tamnd
    OwnerAuthor

    #701 finishes the first part of the verifier. For each program of bpf/test_verifier of the program types of this issue (SOCKET_FILTER, CGROUP_SKB, CGROUP_SOCK, CGROUP_SOCK_ADDR and CGROUP_DEVICE), rukernel now accepts or refuses the program as Linux does, with the same message. It adds state pruning, the Linux rules for back edges with CAP_BPF, the bounds after BPF_JSET and BPF_JMP32, the alignment and context access rules, and BPF_PROG_TEST_RUN. tools/kselftest/bpf.md gives the result.

    Test results:

    • cargo test -p rk-bpf -p rk-abi (server2): 80 and 7 passed. Clippy gives no new warnings. Load of server2: 14.6 to 18.5.
    • x86_64 kselftest with bpf/test_verifier (server1, load 2.6 to 3.3): Summary: 281 PASSED, 510 SKIPPED, 0 FAILED. Before, 259 passed and 22 failed. The skips are the unprivileged runs, the program types outside this issue, the bpf_loop inline that needs a JIT, and BPF_MAP_TYPE_PERF_EVENT_ARRAY.
    • x86_64 ltp (server1, load 0.18 to 0.44): bpf_map01, bpf_prog01, bpf_prog02, bpf_prog03 and bpf_prog04 pass. bpf_prog05, bpf_prog06 and bpf_prog07 give TCONF, as on Linux with kernel.unprivileged_bpf_disabled=2.
    • x86_64 boot-test init with -- only bpf (server1, load 0.03 to 0.11): exit 33, 94 checks ok.
    • arm64 boot-test aarch64 with RK_AARCH64_TESTS=init and -- only bpf (server2, load 5.4 to 5.7): pass, 94 checks ok.
  18. tamnd commented on Nov 12, 2026

    @tamnd
    OwnerAuthor

    #705 adds the sdbpf boot test. It runs test-bpf-devices, test-bpf-firewall and test-bpf-foreign-programs of systemd, which use BPF_PROG_ATTACH, BPF_PROG_DETACH, BPF_PROG_QUERY and BPF_LINK_CREATE with the effective arrays. The kernel needed no change.

    • x86_64 sdbpf on server1: the three tests exit 0, rk-sdbpf: pass, QEMU exit 1. Load average 2.1 to 3.4.
    • x86_64 init -- only bpf on server1: exit 33, 94 ok. Load average 0.03 to 0.11.
    • arm64 init -- only bpf on server2: pass, 94 ok. Load average 5.4 to 5.7. xtask has no systemd tests on arm64.

    Remaining: systemd logs "Failed to get cgroup ID ... Operation not supported", probably from name_to_handle_at on cgroupfs. systemd ignores it.

  19. tamnd commented on Nov 12, 2026

    @tamnd
    OwnerAuthor

    All items of this issue are done. The last PR is #705. The verifier is in #701, the interpreter in #678 and #686, and bpffs and the systemd checks in #607, #614, #630 and #632. Release 0.5.23 has #701, and the next release will have #705.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/bpfBPF: the verifier, the JIT, maps and BTF.kind/featureNew behavior or a new part.

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions