所以我创建了一个BPF_MAP_TYPE_ARRAY类型的地图。
struct share_me
{
struct iphdr dest_ip;
};
struct bpf_map_def SEC("maps") ip_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(struct share_me),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};因此,ip_map是我的地图,它的定义部分和SEC精灵部分用于在上述定义中创建地图。
在我的ebpf程序功能中,我正在做
SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx)
{
int index = ctx->rx_queue_index;
__u32 *pkt_count;
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
struct ethhdr *eth = data;
struct share_me me;
if ((void *)eth + sizeof(*eth) <= data_end)
{
struct iphdr *ip = data + sizeof(*eth);
//me.dest_ip=ip;
memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
bpf_map_lookup_elem(&ip_map, &index);
bpf_map_update_elem(&ip_map,&index,&me,0); 因此,我使用struct对象更新ip_map键的当前值。
这就是我在使用空间程序中所做的。
bpf_obj = load_bpf_and_xdp_attach(&cfg);
if (!bpf_obj) {
/* Error handling done in load_bpf_and_xdp_attach() */
exit(EXIT_FAILURE);
}
/* We also need to load the xsks_map */
map1 = bpf_object__find_map_by_name(bpf_obj, "ip_map");
xsks_map_fd = bpf_map__fd(map);
map_fd = bpf_map__fd(map1);
if(map_fd<0)
{
printf("map_fd <0\n");
exit(0);
}
if (xsks_map_fd < 0) {
fprintf(stderr, "ERROR: no xsks map found: %s\n",
strerror(xsks_map_fd));
exit(EXIT_FAILURE);
}这是load_bpf_and_xdp_attach函数,只是bpf/libbpf的包装器,所以调用load_bpf_object_file等等,
struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg)
{
struct bpf_program *bpf_prog;
struct bpf_object *bpf_obj;
int offload_ifindex = 0;
int prog_fd = -1;
int err;
/* If flags indicate hardware offload, supply ifindex */
if (cfg->xdp_flags & XDP_FLAGS_HW_MODE)
offload_ifindex = cfg->ifindex;
/* Load the BPF-ELF object file and get back libbpf bpf_object */
if (cfg->reuse_maps)
bpf_obj = load_bpf_object_file_reuse_maps(cfg->filename,
offload_ifindex,
cfg->pin_dir);
else
bpf_obj = load_bpf_object_file(cfg->filename, offload_ifindex);
if (!bpf_obj) {
fprintf(stderr, "ERR: loading file: %s\n", cfg->filename);
exit(EXIT_FAIL_BPF);
}
/* At this point: All XDP/BPF programs from the cfg->filename have been
* loaded into the kernel, and evaluated by the verifier. Only one of
* these gets attached to XDP hook, the others will get freed once this
* process exit.
*/
if (cfg->progsec[0])
/* Find a matching BPF prog section name */
bpf_prog = bpf_object__find_program_by_title(bpf_obj, cfg->progsec);
else
/* Find the first program */
bpf_prog = bpf_program__next(NULL, bpf_obj);
if (!bpf_prog) {
fprintf(stderr, "ERR: couldn't find a program in ELF section '%s'\n", cfg->progsec);
exit(EXIT_FAIL_BPF);
}
strncpy(cfg->progsec, bpf_program__title(bpf_prog, false), sizeof(cfg->progsec));
prog_fd = bpf_program__fd(bpf_prog);
if (prog_fd <= 0) {
fprintf(stderr, "ERR: bpf_program__fd failed\n");
exit(EXIT_FAIL_BPF);
}
/* At this point: BPF-progs are (only) loaded by the kernel, and prog_fd
* is our select file-descriptor handle. Next step is attaching this FD
* to a kernel hook point, in this case XDP net_device link-level hook.
*/
err = xdp_link_attach(cfg->ifindex, cfg->xdp_flags, prog_fd);
if (err)
exit(err);
return bpf_obj;
}但我错了
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
; int index = ctx->rx_queue_index;
0: (61) r2 = *(u32 *)(r1 +16)
; int index = ctx->rx_queue_index;
1: (63) *(u32 *)(r10 -4) = r2
; void *data_end = (void *)(long)ctx->data_end;
2: (61) r2 = *(u32 *)(r1 +4)
; void *data = (void *)(long)ctx->data;
3: (61) r1 = *(u32 *)(r1 +0)
; if ((void *)eth + sizeof(*eth) <= data_end)
4: (07) r1 += 14
; if ((void *)eth + sizeof(*eth) <= data_end)
5: (2d) if r1 > r2 goto pc+25
R1_w=pkt(id=0,off=14,r=14,imm=0) R2_w=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm????
; memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
6: (61) r2 = *(u32 *)(r1 +16)
invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14)
R1 offset is outside of the packet
processed 7 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'xdp_sock'
libbpf: failed to load object 'af_xdp_kern.o'
ERR: loading BPF-OBJ file(af_xdp_kern.o) (-22): Invalid argument
ERR: loading file: af_xdp_kern.o因此,在加载ebpf程序时,我得到了invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14) R1 offset is outside of the packet,我有点确定由于我使用struct值作为BPF_MAP_TYPE_ARRY值类型的映射而引起的错误。
所以我想知道如果我使用libbpf允许struct作为MAP键的值,那里还有其他的映射类型吗?
发布于 2022-01-16 11:11:00
TL;DR..问题在于,从验证者的角度来看,您正在使不受约束地访问数据包。您需要检查数据包是否足够长,以便首先实际包含IP报头。
读取验证器错误消息.
; memcpy(&me.dest_ip,ip,sizeof(struct iphdr));
6: (61) r2 = *(u32 *)(r1 +16)
invalid access to packet, off=30 size=4, R1(id=0,off=30,r=14)
R1 offset is outside of the packet指令6上的验证器错误,它对应于memcpy语句。它指出,您正在对数据包进行无效访问,而R1中的偏移量保持在该数据包已知界限之外。
您检查了数据包是否至少足够长以容纳以太网报头,但从未检查它是否足够长以容纳IP报头。因此,验证器会看到您试图访问以太网标头以外的字节(最多可以偏移30)和错误。
更新数据包边界检查.
如果您从一开始就知道需要同时读取以太网和IP报头,则可以从以下位置更新检查:
if ((void *)eth + sizeof(*eth) <= data_end)至:
if ((void *)eth + sizeof(*eth) + sizeof(struct iphdr) <= data_end)https://stackoverflow.com/questions/70721661
复制相似问题