在用户空间读取 ebpf BPF_MAP_TYPE_HASH 的更新值 |可以使用 read() linux 函数获取通过 map 共享的 object 的当前值
reading updated value of ebpf's BPF_MAP_TYPE_HASH in userspace | Can read() linux function be used to get current value of object shared through map
所以我有一个内核 ebpf 程序,它将 xdp 挂钩附加到接口 eno1,并且在其中我有一个映射 ip_map
,它是我与用户空间共享的 BPF_MAP_TYPE_HASH 类型。所以在我的用户空间中,我得到了地图的文件描述符,但现在我想获得更新的值
struct share_me
我在我的用户空间加载程序中借助 BPF_MAP_TYPE_HASH 类型映射分享。
任何人都请帮我解释一下,关于我该怎么做,
所以我假设如果我的 map_fd
指向 BPF_MAP_TYPE_HASH 指向我的 MAP 那么我可以这样做 int sizeof_share_me_read=read(map_fd,&share_me,sizeof(struct share_me));
这样我就可以读取当前更新的值我的 map_fd(BPF_MAP_TYPE_HASH)
从内核 ebpf 程序共享,它将在 share_me object 的 struct iphdr dest_ip
成员中包含当前数据包的 IP header。谁能帮我解决这个问题
user.c
/* SPDX-License-Identifier: GPL-2.0 */
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/bpf.h>
#include <bpf/xsk.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if_link.h>
#include <linux/if_ether.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include "../common/common_params.h"
#include "../common/common_user_bpf_xdp.h"
#include "../common/common_libbpf.h"
int main()
{
struct bpf_object *bpf_obj;
struct bpf_program *bpf_prog;
bpf_obj = load_bpf_object_file("af_xdp_kern.o", 0);
if (!bpf_obj) {
printf("ERR: loading file:\n");
exit(EXIT_FAIL_BPF);
}
bpf_prog = bpf_program__next(NULL, bpf_obj);
if (!bpf_prog)
{
printf("bpf_program_next:\n");
exit(0);
}
int prog_fd = bpf_program__fd(bpf_prog);
if (prog_fd <= 0) {
}
int err = xdp_link_attach(if_nametoindex("eno1"), 0, prog_fd);
if(err)
{
printf("xdp_link_attach\n");
exit(0);
}
struct bpf_map *map1 = bpf_object__find_map_by_name(bpf_obj, "ip_map");
int map_fd = bpf_map__fd(map1);
if(map_fd<0)
{
printf("map fd <0\n");
exit(0);
}
return 0;
}
kernel.c
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
void *memcpy(void *, const void *, unsigned long);
int IPPROTO_UDP = 17;
struct share_me
{
struct iphdr dest_ip;
};
struct bpf_map_def SEC("maps") ip_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(int),
.value_size = sizeof(struct share_me),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") xdp_stats_map = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(__u32),
.max_entries = 64,
};
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;
if(((void *)ip+sizeof(*ip))<=data_end)
{
struct iphdr ip_temp=(struct iphdr)*ip;
memcpy(&me.dest_ip,&ip_temp,sizeof(ip_temp));
bpf_map_lookup_elem(&ip_map, &index);
bpf_map_update_elem(&ip_map,&index,&me,0);
if ((void *)ip + sizeof(*ip) <= data_end)
{
if (ip->protocol == IPPROTO_UDP)
{
struct udphdr *udp = (void *)ip + sizeof(*ip);
if ((void *)udp + sizeof(*udp) <= data_end)
{
//u64 value = htons(udp->dest);
//counter.increment(value);
}
}
}
}
}
pkt_count = bpf_map_lookup_elem(&xdp_stats_map, &index);
if (pkt_count) {
/* We pass every other packet */
if ((*pkt_count)++ & 1)
return XDP_DROP;
}
/* A set entry here means that the correspnding queue_id
* has an active AF_XDP socket bound to it. */
if (bpf_map_lookup_elem(&xsks_map, &index))
return bpf_redirect_map(&xsks_map, index, 0);
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
现在你有了map fd,你需要使用libbpf's bpf_map_lookup_elem
函数来读取值:
int key = 0;
struct share_me value = {};
if (bpf_map_lookup_elem(map_fd, &key, &value))
// Print errno.
所以我有一个内核 ebpf 程序,它将 xdp 挂钩附加到接口 eno1,并且在其中我有一个映射 ip_map
,它是我与用户空间共享的 BPF_MAP_TYPE_HASH 类型。所以在我的用户空间中,我得到了地图的文件描述符,但现在我想获得更新的值
struct share_me
我在我的用户空间加载程序中借助 BPF_MAP_TYPE_HASH 类型映射分享。
任何人都请帮我解释一下,关于我该怎么做,
所以我假设如果我的 map_fd
指向 BPF_MAP_TYPE_HASH 指向我的 MAP 那么我可以这样做 int sizeof_share_me_read=read(map_fd,&share_me,sizeof(struct share_me));
这样我就可以读取当前更新的值我的 map_fd(BPF_MAP_TYPE_HASH)
从内核 ebpf 程序共享,它将在 share_me object 的 struct iphdr dest_ip
成员中包含当前数据包的 IP header。谁能帮我解决这个问题
user.c
/* SPDX-License-Identifier: GPL-2.0 */
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/bpf.h>
#include <bpf/xsk.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if_link.h>
#include <linux/if_ether.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include "../common/common_params.h"
#include "../common/common_user_bpf_xdp.h"
#include "../common/common_libbpf.h"
int main()
{
struct bpf_object *bpf_obj;
struct bpf_program *bpf_prog;
bpf_obj = load_bpf_object_file("af_xdp_kern.o", 0);
if (!bpf_obj) {
printf("ERR: loading file:\n");
exit(EXIT_FAIL_BPF);
}
bpf_prog = bpf_program__next(NULL, bpf_obj);
if (!bpf_prog)
{
printf("bpf_program_next:\n");
exit(0);
}
int prog_fd = bpf_program__fd(bpf_prog);
if (prog_fd <= 0) {
}
int err = xdp_link_attach(if_nametoindex("eno1"), 0, prog_fd);
if(err)
{
printf("xdp_link_attach\n");
exit(0);
}
struct bpf_map *map1 = bpf_object__find_map_by_name(bpf_obj, "ip_map");
int map_fd = bpf_map__fd(map1);
if(map_fd<0)
{
printf("map fd <0\n");
exit(0);
}
return 0;
}
kernel.c
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>
void *memcpy(void *, const void *, unsigned long);
int IPPROTO_UDP = 17;
struct share_me
{
struct iphdr dest_ip;
};
struct bpf_map_def SEC("maps") ip_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(int),
.value_size = sizeof(struct share_me),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") xsks_map = {
.type = BPF_MAP_TYPE_XSKMAP,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 64, /* Assume netdev has no more than 64 queues */
};
struct bpf_map_def SEC("maps") xdp_stats_map = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(__u32),
.max_entries = 64,
};
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;
if(((void *)ip+sizeof(*ip))<=data_end)
{
struct iphdr ip_temp=(struct iphdr)*ip;
memcpy(&me.dest_ip,&ip_temp,sizeof(ip_temp));
bpf_map_lookup_elem(&ip_map, &index);
bpf_map_update_elem(&ip_map,&index,&me,0);
if ((void *)ip + sizeof(*ip) <= data_end)
{
if (ip->protocol == IPPROTO_UDP)
{
struct udphdr *udp = (void *)ip + sizeof(*ip);
if ((void *)udp + sizeof(*udp) <= data_end)
{
//u64 value = htons(udp->dest);
//counter.increment(value);
}
}
}
}
}
pkt_count = bpf_map_lookup_elem(&xdp_stats_map, &index);
if (pkt_count) {
/* We pass every other packet */
if ((*pkt_count)++ & 1)
return XDP_DROP;
}
/* A set entry here means that the correspnding queue_id
* has an active AF_XDP socket bound to it. */
if (bpf_map_lookup_elem(&xsks_map, &index))
return bpf_redirect_map(&xsks_map, index, 0);
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
现在你有了map fd,你需要使用libbpf's bpf_map_lookup_elem
函数来读取值:
int key = 0;
struct share_me value = {};
if (bpf_map_lookup_elem(map_fd, &key, &value))
// Print errno.