0

我正在浏览 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()我们将光标移动以太网标头的大小,因为ethernet_t包含所有以太网标头信息。然后,光标现在位于数据包以太网标头末尾的地址,如果我们使用ethernet_t标头中声明的变量,例如type: ethernet->type,我们可以访问保存在的信息,type因为结构ethernet会读取保存在的值那个地址?对不起,我的解释不是很好。我只是在寻找一般解释,或者我的理论是否正确。谢谢!

4

1 回答 1

1

你的理解对我来说听起来是正确的。只需将其视为用于连续解析数据包的不同标头的“光标”。cursor_advance()定义为:

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

它添加_len_cursor, 并返回_cursor我们添加之前的值_len

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

注意:我不相信这种机制在 BPF 程序中被广泛使用,除了 BCC 中可用的少数网络示例。skb->data相反,程序通常使用和浏览数据包标头skb->data_end

于 2020-02-17T09:53:01.243 回答