cursor_advance 在 BPF 中的具体用法是什么?

What exactly is usage of cursor_advance in BPF?

我正在浏览 IOvisor 项目的幻灯片,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;
}

此代码在示例中。 我经常使用 cursor_advance(),现在我想弄清楚它到底做了什么。 我怀疑 cursor 是一个指针,我们在其中保存我们正在解析的数据包的地址。 然后,使用 cursor_advance() 我们将光标移动以太网的大小 header,因为 ethernet_t 包含所有以太网 header 信息。 然后,光标现在位于数据包以太网末尾的地址 header 如果我们使用 ethernet_t header 中声明的变量,例如 type,就像: ethernet->type,我们可以访问保存在 type 的信息,因为结构 ethernet 会读取保存在该地址中的值? 对不起,我的解释不是很好。 我只是在寻找一般性解释,或者我的理论是否正确。 谢谢!

你的理解对我来说是正确的。只需将其视为用于连续解析数据包的不同 header 的“游标”。 cursor_advance() 宏是 defined 为:

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

它将 _len 添加到 _cursor,并且 returns 是 _cursor 在我们添加 _len 之前的值。

所以第一次调用cursor_advance() returns初始值:ethernet指向数据包的开头,我们可以利用它的属性来访问数据包的不同字段以太网 header。但同样的调用也将 cursor 向前移动了以太网的长度 header,所以现在它指向下一个 header(L3,例如 IP)的开头。第二次调用cursor_advance()returns指向L3层的指针,我们将其存储在ip中。 cursor 也向前移动,假设数据包是 IPv4,现在将指向 L4 header。

注意:除了 BCC 中可用的几个网络示例之外,我不认为这种机制在 BPF 程序中被广泛使用。相反,程序通常使用 skb->dataskb->data_end.

浏览数据包 headers