我正在写一个ebpf程序来读取tc上的数据包.下面的代码被简化,以更好地理解问题.假设我有一个ebpf map,其值是如下定义的 struct :
struct value {
int index;
char flags[MAX_FLAGS_LEN];
};
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 32);
__type(key, __u8);
__type(value, struct value);
} output_map SEC(".maps");
如果我的ebpf程序在主要部分全部写出来,它会工作得很好,如下所示.
SEC("classifier")
int tc_ingress(struct __sk_buff *skb)
{
__u8 key = 1;
struct value *value;
value = bpf_map_lookup_elem(&output_map, &key);
if (value == NULL){
struct value initial_value = {
.index = 1,
.flags = ","
};
bpf_map_update_elem(&output_map, &key, &initial_value, BPF_NOEXIST);
} else {
if (value->index >= sizeof(value->flags)){
goto out;
}
}
if (value->index < sizeof(value->flags)){
value->flags[value->index] = ',';
value->index++;
}
if (value->index < sizeof(value->flags)){
value->flags[value->index] = ',';
value->index++;
}
bpf_printk("Flags: %d", value->flags);
out:
return TC_ACT_OK;
}
但是,当我重构代码时,如下所示:
static __always_inline void store_flags(struct value *value){
if (value->index < sizeof(value->flags)){
value->flags[value->index] = ',';
value->index++;
}
if (value->index < sizeof(value->flags)){
value->flags[value->index] = ',';
value->index++;
}
}
SEC("classifier")
int tc_ingress(struct __sk_buff *skb)
{
__u8 key = 1;
struct value *value;
value = bpf_map_lookup_elem(&output_map, &key);
if (value == NULL){
struct value initial_value = {
.index = 1,
.flags = ","
};
bpf_map_update_elem(&output_map, &key, &initial_value, BPF_NOEXIST);
} else {
if (value->index >= sizeof(value->flags)){
goto out;
}
}
store_flags(value);
bpf_printk("Flags: %d", value->flags);
out:
return TC_ACT_OK;
}
我会得到这个错误:
permission denied:invalid access to map value,value_size = 20 off = 20 size = 1:R4 max value超出允许的内存范围(省略了52行)
有谁知道解决办法吗?
Edit: Dylan's answer contains detailed reasoning why it happened. Modifying the code to this fixed it.
static __always_inline void store_flags(struct value *value){
int index = value->index;
if (index < sizeof(value->flags)){
value->flags[index] = ',';
index++;
}
if (index < sizeof(value->flags)){
value->flags[index] = ',';
index++;
}
value->index=index;
}
SEC("classifier")
int tc_ingress(struct __sk_buff *skb)
{
__u8 key = 1;
struct value *value;
value = bpf_map_lookup_elem(&output_map, &key);
if (value == NULL){
struct value initial_value = {
.index = 1,
.flags = ","
};
bpf_map_update_elem(&output_map, &key, &initial_value, BPF_NOEXIST);
} else {
store_flags(value);
}
bpf_printk("Flags: %d", value->flags);
return TC_ACT_OK;
}