Ваше понимание звучит правильно для меня. Просто думайте об этом как о «курсоре», который используется для последовательного анализа различных заголовков вашего пакета. Макрос 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
.