bpf_dynptr_slice_rdwr(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… bpf_dynptr_slice_rdwr β€” like, the Kernel API Manual (section 9) page you actually want to read 🫢

okay bestie, sit down, grab a strawberry πŸ“, because this one is LOWKEY important. We're talking about bpf_dynptr_slice_rdwr β€” it's a kernel API function, it lives in the 9 section of the manual, and it's the one that hands you a writable pointer into your dynptr data. Yes, writable. As in, you can actually touch it. Main character energy fr fr ✨


πŸŽ€ NAME πŸŽ€

bpf_dynptr_slice_rdwr β€” obtain a writable pointer to the dynptr data. That's it, that's the whole vibe. πŸ’…


✨ SYNOPSIS ✨

__bpf_kfunc void * bpf_dynptr_slice_rdwr (const struct bpf_dynptr *p ,
u64 offset , void *buffer__nullable , u64 buffer__szk );

Look at that signature. Four args. Not one of them is optional to understand. Let's go πŸ‘‘


🌸 ARGUMENTS 🌸

  • p β€” the dynptr whose data slice you're trying to retrieve. Your little data baddie. πŸ¦‹
  • offset β€” offset into the dynptr. i.e. where inside it you're pointing. πŸ“
  • buffer__nullable β€” a user-provided buffer that the contents get copied into. It may be NULL. Yes, nullable means nullable, she's allowed to be absent. πŸ™ˆ
  • buffer__szk β€” size (in bytes) of the buffer, if present. This is also, importantly, the length of the requested slice. And heads up: this must be a constant. Not a variable. Not vibes. A constant. πŸ”₯

πŸ‘‘ DESCRIPTION πŸ‘‘

So for non-skb and non-xdp type dynptrs, there is literally no difference between bpf_dynptr_slice and bpf_dynptr_data. Same function, different font, as far as those are concerned. Not kidding. πŸ’€

If buffer__nullable is NULL, the call will fail if buffer_opt was needed. (Yes, buffer_opt β€” that's what the page says, don't @ me.) 😭

Now the juicy part: the returned pointer is writable, and it may point to either:

  1. directly the dynptr data at the requested offset, or
  2. the buffer, if it's unable to obtain a direct data pointer to (example: the requested slice is to the paged area of an skb packet).

And in case number two β€” the one where the returned pointer is to the buffer β€” you are responsible for persisting writes through calling bpf_dynptr_write. Like, that's on you bestie. Nobody's doing it for you. 🫢

It usually looks something like this pattern:

struct eth_hdr *eth = bpf_dynptr_slice_rdwr(dynptr, 0, buffer, sizeof(buffer)); if (!eth) return TC_ACT_SHOT;

// mutate eth header //

if (eth == buffer) bpf_dynptr_write(ptr, 0, buffer, sizeof(buffer), 0);
⚠️ Please note that, as in the example above, the user must check that the returned pointer is not null before using it. Like, actually check. Touch the null pointer and it's over for you πŸ’€πŸ”΄

Also please note β€” and this one's iconic β€” in the case of skb and xdp dynptrs, bpf_dynptr_slice_rdwr does not change the underlying packet data pointers, so a call to bpf_dynptr_slice_rdwr will not invalidate any ctx->data/data_end pointers in the bpf program. Your pointers stay valid. She's considerate like that. πŸ’–


🌈 RETURN 🌈

  • NULL if the call failed (eg invalid dynptr) 😭
  • otherwise: a pointer to a data slice β€” which can be either a direct pointer to the data, or a pointer to the user provided buffer with its contents containing the data, if it was unable to obtain a direct pointer. Two possible outfits, same function. πŸ’…

🌟 SEE ALSO 🌟

Kernel file ./kernel/bpf/helpers.c and, like, the whole friend group:


okay that's the whole page, you ate that πŸ“πŸ’œ this gem is from ./kernel/bpf, dated October 2026, and yes it's bpf_dynptr_slice_rdwr(9) β€” go forth and mutate responsibly, bestie πŸ§šβ€β™€οΈβœ¨

πŸ“¦ where this page comes from