We need a way to handle multiple kernel capabilities
Right now, the HID-BPF kernel API hasn't changed much since v6.3.
But I hope in merging some new capabilities in v6.10, which will allow for more features from HID-BPF.
BPF in itself allows for new addition and removal in the kfunc API, but udev-hid-bpf
isn't smart regarding that right now. It'll just take whatever object is given to it, and will try to load it. This works in the way that if a BPF program is accepted by the kernel it will be properly loaded and if not, then it will be rejected.
However, what happens if we have multiple version with different features for the same device?
My thoughts as I was writing this project was to rely on the bpffs: if a program is already pinned in the bpffs, udev-hid-bpf will simply just unload the program, and move on.
But there are a few corner cases where it's not exactly working:
Use cases
A device is supported in kernel X, and we want to add a new independent behavior thanks to kernel Y
We can probably just split the bpf program in 2, one for kernel X and one for kernel Y. On kernel Y both will be loaded, while on kernel X only the first one will.
A device is supported in kernel X, but Y dropped part of the API to replace it with something else
Again, I think we need 2 BPF programs. One for X, one for Y and the bpf loader will do the rest.
A device is supported in kernel X, and we want to amend the support thanks to a new feature of kernel Y
For example, once we have sleepable bpf_timers, we can extend the features of a device and fix more corner cases.
This could also be the case if we want to keep both functionality from kernel X and Y in the same file (because they interact with each other).
This is where things are not very clear:
- we need a way to enforce the bpf program from kernel Y to be loaded first
- to prevent kernel X to be loaded when kernel Y is, we could also change the report descriptor so that
.probe()
of kernel X fails when kernel Y is loaded (in addition to relying on bpffs)
One interesting way could be to be able to declare mutual exclusions, and priorities: "I want kernel Y loaded first and if it fails (and only if it fails), try kernel X"
But how do we declare that? in BTF, like HID_DEVICE
? Through naming conventions?
In udev it could be represented as HID_BPF_25=kernel_y.bpf.o,kernel_x.bpf.o
.
But then that doesn't work really well with testing
and stable
being 2 different hwdb...