Что такое использование cursor_advance в BPF? - PullRequest
0 голосов
/ 16 февраля 2020

Я просматривал слайд по проекту 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() мы перемещаем курсор на размер заголовка ethe rnet, поскольку ethernet_t содержит всю информацию заголовка ethe rnet. Затем курсор теперь находится по адресу в конце заголовка ethe rnet пакета, и если мы используем переменные, объявленные в заголовке ethernet_t, такие как type, например: ethernet->type, мы можем получить доступ к информация, сохраненная в type, так как структура ethernet будет читать значения, сохраненные в этом адресе? Извините, мое объяснение не очень хорошее. Я просто ищу общее объяснение или если моя теория верна. Спасибо!

1 Ответ

1 голос
/ 17 февраля 2020

Ваше понимание звучит правильно для меня. Просто думайте об этом как о «курсоре», который используется для последовательного анализа различных заголовков вашего пакета. Макрос cursor_advance() равен , определен как:

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

. Он добавляет _len к _cursor и возвращает значение, которое _cursor было до того, как мы добавили _len.

Таким образом, первый вызов cursor_advance() возвращает начальное значение: ethernet указывает на начало пакета, и мы можем использовать его атрибуты для доступа к различным полям заголовка Ethe rnet. Но этот же вызов также перемещает cursor вперед на длину заголовка Ethe rnet, поэтому теперь он указывает на начало следующего заголовка (L3, например, IP). Второй вызов cursor_advance() возвращает указатель на уровень L3, который мы храним в ip. cursor также перемещен вперед и, предполагая, что пакет является IPv4, теперь будет указывать на заголовок L4.

Примечание: я не верю, что этот механизм широко используется в программах BPF, за исключением нескольких примеров работы в сети доступно в B CC. Вместо этого программы часто перемещаются по заголовкам пакетов с skb->data и skb->data_end.

...