Search code examples
cebpfbpflibbpf

BPF lib documentation


I have created an app with BPF library(https://github.com/libbpf/libbpf). Unfortunately it does not have documentation or at least I have not found it yet. Only thing I have found is this https://libbpf.readthedocs.io/en/latest/api.html, but it does not have everything I need.

I would like to know, what is void *ctx for and what are these ring_buffer_opts in this function.

LIBBPF_API struct ring_buffer *
ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx, const struct ring_buffer_opts *opts);

And here I would like to know what is void *ctx for.

typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);

I prefer link to the documentation, but I am glad for everything.


Solution

  • You have found the GitHub mirror for the project (the “original” sources are in the Linux kernel repository) and the official API documentation. The latter is generated from the source code, in particular from the comments in src/libbpf.h. It may be that the documentation is not entirely up-to-date, it seems that the description for a few functions is currently missing in the HTML-rendered documentation.

    However, not all functions have been documented yet, and the ring buffer API does not have much on this side to help you. So the best I can suggest is to look at the code and at existing examples. There are at least two selftests in the kernel repository which are using ring_buffer__new(): ringbuf.c and ringbuf_multi.c.

    The first one (ringbuf.c) calls it like this:

        ringbuf = ring_buffer__new(skel->maps.ringbuf.map_fd,
                       process_sample, NULL, NULL);
    

    It passes a pointer to a function called process_sample as the second argument, NULL as ctx for the third argument, and NULL as well for the options.

    The callback function, process_sample, is called by ring_buffer__poll() or ring_buffer__consume() on each sample to “process” them according to user's needs. In this example, the callback only works on the data from the sample, printing a line which content depends on whether this is the first or second sample retrieved. The callback needs no “context”: this is why the ctx argument, which is stored by ring_buffer__new() and then passed to the callback function as its first argument each time it runs, is NULL in this case.

    For the second example (ringbuf_multi.c), we get a ctx:

        ringbuf = ring_buffer__new(bpf_map__fd(skel->maps.ringbuf1),
                       process_sample, (void *)(long)1, NULL);
        [...]
        
        err = ring_buffer__add(ringbuf, bpf_map__fd(skel->maps.ringbuf2),
                      process_sample, (void *)(long)2);
    

    The callback function is named process_sample again, but it's a different one (it's defined in the same file as the rest of the example). We also pass a context, 1, and then we add an additional ring buffer, with a different context, 2. If you look at the checks that are performed under that, and at how process_sample is defined, it should give you a good overview of how the ctx works: it is some generic context that you can pass to each individual ring buffer, so that you can process your samples in a different way based on which ring buffer it falls into.

    As for the struct ring_buffer_opts * options, always at NULL in the examples, they seem to be unused for now. The code in ring_buffer__new() does not use them.