1

I was looking through a slide by IOvisor project, https://events.static.linuxfound.org/sites/events/files/slides/iovisor-lc-bof-2016.pdf

#include <bcc/proto.h>

struct IPKey { u32 dip; u32 sip; };
BPF_TABLE("hash", struct IPKey, int, mytable, 1024);

int recv_packet(struct __sk_buff *skb) {
    struct IPKey key;
    u8 *cursor = 0;
    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
    struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));

    key.dip = ip->dst;
    key.sip = ip->src;
    int *leaf = mytable.lookup(&key);
    if (leaf)
        *(leaf)++;
    return 0;
}

This code is amongst the examples. I've been using cursor_advance() quite often and now I'm trying to figure out what exactly it does. I suspect that cursor is a pointer where we save the address of the packet we are parsing. Then, with cursor_advance() we move the cursor by the size of the ethernet header, since ethernet_t contains all the ethernet header information. Then, the cursor now at the address at the end of the ethernet header of the packet and if we use variables declared in the ethernet_t header, such as type, like : ethernet->type, we can access the information saved at type since the struct ethernet would read the values saved in that address? I'm sorry my explanation is not really good. I'm just looking for a general explanation or if my theory is correct. Thanks!

Qeole
  • 8,284
  • 1
  • 24
  • 52
Rosè
  • 345
  • 2
  • 13

1 Answers1

4

Your understanding sounds correct to me. Just think of it as a “cursor” used to successively parse the different headers of your packet. The cursor_advance() macro is defined as:

#define cursor_advance(_cursor, _len) \
        ({ void *_tmp = _cursor; _cursor += _len; _tmp; })

It adds _len to the _cursor, and returns the value _cursor had before we added _len.

So the first call to cursor_advance() returns the initial value: ethernet points to the beginning of the packet, and we can use its attributes to access the different fields of the Ethernet header. But this same call also moves the cursor forwards by the length of the Ethernet header, so now it points to the beginning of the next header (L3, e.g. IP). The second call to cursor_advance() returns the pointer to the L3 layer, which we store in ip. The cursor is also moved forward and, assuming the packet is IPv4, would now point at the L4 header.

Note: I do not believe this mechanism is widely used in BPF programs aside from the few networking examples available in BCC. Instead, programs often navigate through packet headers with skb->data and skb->data_end.

Qeole
  • 8,284
  • 1
  • 24
  • 52
  • Thanks for your insight! I will look into more examples in BCC too :D Thanks a million! – Rosè Feb 18 '20 at 10:10
  • Hi Qeole, but from the first three line of code [http_filter 38-44](https://github.com/iovisor/bcc/blob/master/examples/networking/http_filter/http-parse-complete.c#L38-L44) that how can he use cursor_advance function to assign the value to ethernet->type, since he hasn't use the skb as param in any way? could you please do me a favor to explain a little more? – Martin T Y Ho Nov 28 '22 at 07:52
  • 1
    @MartinTYHo I don't remember for sure but I believe this is because it's a socket filter, and the BPF program in that case does not work from a context buffer (i.e. the `skb` is actually unused), but works directly with the beginning of the packet data as context. So address `0` (where the `cursor` points to) would be the beginning of packet data - the Ethernet header, without requiring loading it from `ctx->data` like for TC or XDP programs. – Qeole Dec 05 '22 at 13:36
  • thanks Qeole, I've figured out by setting the debug flag to 4, and I've seen that bcc would do some inline expansion stuff, it's a little tricky like black magic lol... by the way, it seems that bpf_map_type_hash is not concurrently safe under kernel version 5.1, so what would you suggest to use for the lower kernnel version? And since bpf_map_type_percpu_hash could only lookup for the value of current cpu, I think it's a little difficult for me to work it out T_T – Martin T Y Ho Dec 14 '22 at 16:03
  • I don't remember, I haven't worked with BCC too much recently. You could maybe open an issue on the BCC project to ask – Qeole Dec 15 '22 at 20:54