On Wed, Mar 19, 2025 at 8:35 AM Francisco Soares Carvalho <francisco.s.carvalho@xxxxxx> wrote: > > Dear Linux Kernel team, > > I hope this message finds you well, I am seeking your assistance in the correct usage of the function bpf_dynptr_slice() please. > > The program being developed is supposed to captures all the packets that pass through the Prerouting stage of the Netfilter packet flow, so the program is required to be of ebpf Netfilter program type. As the objective is to copy large portions of the captured packets to user-space for processing, without consuming them, a ringbuffer map type is used for storage and communication. > > According to the ebpf official page (Link to the Netfilter program type page: https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_NETFILTER/), this program type needs to read the packet with the dynptr interface, plus (Link to the bpf_dynptr_from_skb() function page: https://docs.ebpf.io/linux/kfuncs/bpf_dynptr_from_skb/) the correct and only way to access the packets captured is through the bpf_dynptr_slice() or bpf_dynptr_read() functions ("For reads and writes through the bpf_dynptr_read() and bpf_dynptr_write() interfaces, reading and writing from/to data in the head as well as from/to non-linear paged buffers is supported. Data slices through the bpf_dynptr_data API are not supported; instead bpf_dynptr_slice() and bpf_dynptr_slice_rdwr() should be used."). > > In order to write to the ringbuffer, the api provided needs to be respected (Link to the list of functions that ringbuffer maps support: https://docs.ebpf.io/linux/map-type/BPF_MAP_TYPE_RINGBUF/), so the bpf_dynptr_read() function can't be used, as it can't write to the ringbuffer, so it would need space to store the packet information, and some (most) of the packets need more space than the ebpf verifier allows (512 Bytes, this limit can be changed, however it is not the first option in this program). So, the bpf_dynptr_slice() was chosen. > > I think I understand the description presented in the official page and the signature of the function, but if you see any mistakes or misunderstandings, please feel free to correct them. The current problem is with the verifier. According to it, the 4^th argument of bpf_dynptr_slice() needs to be a known constant at compile time (figure 1 in attachments). However, the packets received don't have the same size, and the data part's sizes the user-space will need also varies. The following attempts were tried in a Ubuntu 24.04.01 LTS with a kernel version 6.8.0-52: > > 1. Switch case with the possible sizes, with the maximum size as 1099 bytes per packet. (the clang optimizer placed a variable instead of the values of the 4^th argument) > 2. Place bpf_dynptr_size() in the 4^th argument > 3. Declare const unsigned int size=sz and use size as the 4^th argument > 4. Create a function that returned an unsigned int and use it in the 4^th argument, and use it in the declaration of the const unsigned int size > > The only way the code works is with brute force: Do the function, if it fails subtract one and do it again, always with the explicit value in the fourth argument, never with a variable. (figure 2 attached). This is not an optimal solution, but a better one wasn't found. > > What is the intended way of doing this? > > Thank you very much for your time and assistance, and I'm looking forward to your response. > I won't go into too many details, but you can find an example of how to do this with bpf_dynptr_slice() at [0], I wrote it as a demo a while ago. But, good news, just recently we've got a generic bpf_dynptr_copy() which is perfect for situations like this. Check it out as well. [0] https://github.com/libbpf/libbpf-bootstrap/commit/046fad60df3e39540937b5ec6ee86054f33d3f28 [1] https://lore.kernel.org/bpf/20250226183201.332713-3-mykyta.yatsenko5@xxxxxxxxx/ > Francisco Carvalho, > email: francisco.s.carvalho@xxxxxx >