我在编译与TC一起安装的eBPF程序时遇到问题。目前,它仅执行一些基本的操作,这需要重新计算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帮助器,便能够编译和安装BPF对象(使用TC)。一旦我这样做,问题就会出现。
我正在内核树FWIW之外进行此操作。不知道这是否是一个问题。我包括了bpf头文件(linux / bpf.h),并且使用了iproute2包中的bpf_api.h头文件(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";
答案 0 :(得分:1)
编译器抛出该错误,因为deepCopy
将此助手定义为:
bpf_api.h
而不是static int l3_csum_replace(struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags);
。如果您从代码中的助手名称中删除了bpf_l3_csum_replace
前缀,它将按预期进行编译,而无需手动添加原型。
详细信息和调试
如果您遵循bpf_
中的原型定义,则会看到它使用了bpf_api.h
,后者本身使用了BPF_FUNC
:
__BPF_FUNC
根据此代码段,该形式的任何帮助程序定义:
#ifndef __BPF_FUNC
# define __BPF_FUNC(NAME, ...) \
(* NAME)(__VA_ARGS__) __maybe_unused
#endif
#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...) \
__BPF_FUNC(NAME, __VA_ARGS__) = (void *) BPF_FUNC_##NAME
#else
#endif
将扩展为:
static return_type BPF_FUNC(name, ... args ...);
因此,不会附加任何static return_type name(... args ...);
前缀。