У меня проблема с компиляцией программы eBPF, которую я устанавливаю с помощью TC. На данный момент он выполняет только некоторые основные операции, которые требуют пересчета контрольной суммы IP.
Я заметил, что в помощниках BPF есть функция bpf_l3_csum_replace, которая, кажется, и нужна. Однако, когда я пытаюсь использовать любую из встроенных функций, сопоставленных с помощью макроса BPF_FUNC, я получаю неявную ошибку объявления:
... предупреждение: неявное объявление 'bpf_l3_csum_replace' недопустимо в
C99.
Затем следует ошибка от верификатора:
... Вызов глобальной функции 'bpf_l3_csum_replace' не поддерживается. Только
разрешены вызовы предварительно определенных помощников BPF.
Моя строка компиляции:
clang -target bpf -nostdinc -I/usr/include -I/usr/lib64/clang/5.0.2/include -O2 -emit-llvm -c <file> -o - | llc -march=bpf -filetype=obj -o <output>
Следует отметить, что я могу компилировать и устанавливать объект BPF (используя TC), если я не использую ни одного из «предопределенных» помощников bpf. Эта проблема возникает, как только я это сделаю.
Я делаю это вне дерева ядра, FWIW. Не уверен, что это проблема. Я включаю заголовок bpf (linux / bpf.h) и использую заголовок bpf_api.h из пакета iproute2 (мне не очень повезло с заголовком bpf_helpers.h).
Я все еще относительно новичок в eBPF, поэтому я не удивлюсь, если что-то упущу. Любая помощь будет оценена.
Редактировать: Код
#define KBUILD_NAME "testbpf"
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/filter.h>
#include <linux/pkt_cls.h>
#include "bpf_api.h"
#define _htonl __builtin_bswap32
struct eth_hdr {
unsigned char h_dest[ETH_ALEN];
unsigned char h_source[ETH_ALEN];
unsigned short h_proto;
};
#define IP_CSUM_OFFSET (ETH_HLEN + offsetof(struct iphdr, check))
#define TOS_OFF (ETH_HLEN + offsetof(struct iphdr, tos))
#define PROTO_OFF (ETH_HLEN + offsetof(struct iphdr, protocol))
__section("ingress") int bpf_prog(struct __sk_buff *skb)
{
void *data = (void *) (long)skb->data;
struct eth_hdr *eth = data;
void *data_end = (void*) (long) skb->data_end;
if (data+sizeof(*eth) > data_end)
return BPF_H_DEFAULT;
if (eth->h_proto == htons(ETH_P_ARP))
return BPF_H_DEFAULT;
// ipv4
if (eth->h_proto == htons(ETH_P_IP))
{
struct iphdr *ip = data+sizeof(*eth);
if (data+sizeof(*ip)+sizeof(*eth) > data_end)
return BPF_H_DEFAULT;
__u8 proto = ip->protocol;
__u8 old_tos = ip->tos;
// mangle our tos; not meant to achieve anything
ip->tos = 0x04;
if (proto == IPPROTO_ICMP)
ip->tos = 0x00;
if (proto == IPPROTO_TCP)
ip->tos = 0x04;
if (proto == IPPROTO_UDP)
ip->tos = 0x08;
// update our csum and return
bpf_l3_csum_replace(skb, IP_CSUM_OFFSET, old_tos, ip->tos, 2); // ISSUE here
return BPF_H_DEFAULT;
}
return BPF_H_DEFAULT;
}
char __license[] __section("license") = "GPL";