storage size of 'value' isn't known问题出现的可能原因之一

本文深入探讨了在使用C++语言进行编程时遇到编译错误时的排查方法,包括但不限于检查结构体类型、变量名、头文件包含情况及预编译声明等问题。通过详细的分析步骤,帮助开发者快速定位并解决编译过程中遇到的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有可能是头文件没有包含起来,所以会出现这种问题
可以从以下几个方面来查找原因:
1、若是结构体类型,类型是否写错;
2、变量名是否写错;
2、头文件是否包含进来;
3、头文件的预编译声明是否有问题!
使用上面代码编译出现以下问题:make -C ../../ /root/bpf/linux-4.19.90/samples/bpf/ BPF_SAMPLES_PATH=/root/bpf/linux-4.19.90/samples/bpf make[1]: Entering directory '/root/bpf/linux-4.19.90' CALL scripts/checksyscalls.sh DESCEND objtool make -C /root/bpf/linux-4.19.90/samples/bpf/../../tools/lib/bpf/ RM='rm -rf' LDFLAGS= srctree=/root/bpf/linux-4.19.90/samples/bpf/../../ O= Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h' HOSTCC /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.o /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c: In function ‘print_violation’: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:53:26: warning: implicit declaration of function ‘localtime’; did you mean ‘st_atime’? [-Wimplicit-function-declaration] struct tm *tm_info = localtime(&ts); ^~~~~~~~~ st_atime /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:53:26: warning: initialization makes pointer from integer without a cast [-Wint-conversion] /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:55:5: warning: implicit declaration of function ‘strftime’ [-Wimplicit-function-declaration] strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info); ^~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:55:5: warning: incompatible implicit declaration of built-in function ‘strftime’ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:55:5: note: include ‘<time.h>’ or provide a declaration of ‘strftime’ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c: At top level: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:69:13: warning: function declaration isn’t a prototype [-Wstrict-prototypes] static void read_violations() { ^~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c: In function ‘read_violations’: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:77:12: error: variable ‘attr’ has initializer but incomplete type struct perf_event_attr attr = { ^~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:78:10: error: ‘struct perf_event_attr’ has no member named ‘sample_type’ .sample_type = PERF_SAMPLE_RAW, ^~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:78:24: error: ‘PERF_SAMPLE_RAW’ undeclared (first use in this function) .sample_type = PERF_SAMPLE_RAW, ^~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:78:24: note: each undeclared identifier is reported only once for each function it appears in /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:78:24: warning: excess elements in struct initializer /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:78:24: note: (near initialization for ‘attr’) /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:79:10: error: ‘struct perf_event_attr’ has no member named ‘type’ .type = PERF_TYPE_SOFTWARE, ^~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:79:17: error: ‘PERF_TYPE_SOFTWARE’ undeclared (first use in this function) .type = PERF_TYPE_SOFTWARE, ^~~~~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:79:17: warning: excess elements in struct initializer /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:79:17: note: (near initialization for ‘attr’) /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:80:10: error: ‘struct perf_event_attr’ has no member named ‘config’ .config = PERF_COUNT_SW_BPF_OUTPUT, ^~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:80:19: error: ‘PERF_COUNT_SW_BPF_OUTPUT’ undeclared (first use in this function) .config = PERF_COUNT_SW_BPF_OUTPUT, ^~~~~~~~~~~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:80:19: warning: excess elements in struct initializer /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:80:19: note: (near initialization for ‘attr’) /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:81:10: error: ‘struct perf_event_attr’ has no member named ‘size’ .size = sizeof(attr), ^~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:81:23: error: invalid application ofsizeof’ to incomplete type ‘struct perf_event_attr’ .size = sizeof(attr), ^ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:81:17: warning: excess elements in struct initializer .size = sizeof(attr), ^~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:81:17: note: (near initialization for ‘attr’) /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:82:10: error: ‘struct perf_event_attr’ has no member named ‘wakeup_events’ .wakeup_events = 1, ^~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:82:26: warning: excess elements in struct initializer .wakeup_events = 1, ^ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:82:26: note: (near initialization for ‘attr’) /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:77:28: error: storage size of ‘attr’ isn’t known struct perf_event_attr attr = { ^~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:85:23: error: ‘__NR_perf_event_open’ undeclared (first use in this function); did you mean ‘bpf_perf_event_ret’? perf_fd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0); ^~~~~~~~~~~~~~~~~~~~ bpf_perf_event_ret /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:100:11: warning: implicit declaration of function ‘mmap’ [-Wimplicit-function-declaration] buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); ^~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:100:33: error: ‘PROT_READ’ undeclared (first use in this function); did you mean ‘IPPROTO_RAW’? buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); ^~~~~~~~~ IPPROTO_RAW /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:100:45: error: ‘PROT_WRITE’ undeclared (first use in this function); did you mean ‘PROT_READ’? buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); ^~~~~~~~~~ PROT_READ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:100:57: error: ‘MAP_SHARED’ undeclared (first use in this function) buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); ^~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:101:16: error: ‘MAP_FAILED’ undeclared (first use in this function); did you mean ‘MAP_SHARED’? if (buf == MAP_FAILED) { ^~~~~~~~~~ MAP_SHARED /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:113:55: error: dereferencing pointer to incomplete type ‘struct perf_event_mmap_page’ __u64 data_head = __sync_fetch_and_add(&header->data_head, 0); ^~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:131:5: warning: implicit declaration of function ‘munmap’ [-Wimplicit-function-declaration] munmap(buf, mmap_size); ^~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c: In function ‘load_xdp’: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:194:15: warning: implicit declaration of function ‘if_nametoindex’ [-Wimplicit-function-declaration] ifindex = if_nametoindex(iface); ^~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:214:31: warning: implicit declaration of function ‘bpf_object__find_program_by_name’; did you mean ‘bpf_object__find_program_by_title’? [-Wimplicit-function-declaration] prog_fd = bpf_program__fd(bpf_object__find_program_by_name(obj, "xdp_whitelist")); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ bpf_object__find_program_by_title /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:214:31: warning: passing argument 1 of ‘bpf_program__fd’ makes pointer from integer without a cast [-Wint-conversion] In file included from /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:11:0: ./tools/lib/bpf/libbpf.h:128:5: note: expected ‘struct bpf_program *’ but argument is of type ‘int’ int bpf_program__fd(struct bpf_program *prog); ^~~~~~~~~~~~~~~ /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c: At top level: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.c:238:13: warning: function declaration isn’t a prototype [-Wstrict-prototypes] static void unload_xdp() { ^~~~~~~~~~ make[2]: *** [scripts/Makefile.host:107: /root/bpf/linux-4.19.90/samples/bpf/xdp_whitelist_user.o] Error 1 make[1]: *** [Makefile:1695: /root/bpf/linux-4.19.90/samples/bpf/] Error 2 make[1]: Leaving directory '/root/bpf/linux-4.19.90' make: *** [Makefile:224: all] Error 2
最新发布
07-22
<think>根据编译错误,主要问题集中在以下几个方面: 1. 缺少头文件:如`<time.h>`(解决localtime和strftime的隐式声明问题)、`<sys/mman.h>`(解决mmap、munmap的隐式声明问题)、`<linux/perf_event.h>`(解决perf_event_attr结构体不完整的问题)。 2. 使用了未声明的常量:如`PERF_SAMPLE_RAW`、`PERF_TYPE_SOFTWARE`、`PERF_COUNT_SW_BPF_OUTPUT`等,这些需要包含`<linux/perf_event.h>`。 3. `__NR_perf_event_open`未定义:需要包含`<sys/syscall.h>`。 4. 函数声明不是原型:在函数定义时,参数列表应明确为`(void)`而不是空括号。 5. 结构体`perf_event_attr`的使用:由于内核版本(4.19)与头文件版本可能不一致,需要确保包含正确的头文件。 此外,在用户态程序中,我们使用了libbpf的API,需要确保链接到正确的库。 下面我们修正用户态程序(xdp_whitelist_user.c)的代码,解决上述问题。 ### 修正后的用户态程序 (`xdp_whitelist_user.c`) ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/syscall.h> // For syscall, __NR_perf_event_open #include <sys/mman.h> // For mmap, munmap, PROT_READ, PROT_WRITE, MAP_SHARED #include <time.h> // For localtime, strftime #include <netinet/in.h> #include <arpa/inet.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> #include <linux/if_link.h> #include <linux/perf_event.h> // For perf_event_attr, PERF_TYPE_SOFTWARE, etc. // 与内核一致的结构定义 struct flow_key { __u32 src_ip; __u32 dst_ip; __u16 src_port; __u16 dst_port; __u8 protocol; }; struct violation_event { struct flow_key key; unsigned char src_mac[6]; unsigned char dst_mac[6]; __u64 timestamp; }; // 全局变量 static int ifindex = -1; static int prog_fd = -1; static int map_fd = -1; static int perf_fd = -1; static struct bpf_object *obj = NULL; // 打印MAC地址 static void print_mac(const unsigned char *mac) { printf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } // 打印违规事件 static void print_violation(const struct violation_event *e) { char src_ip[INET_ADDRSTRLEN]; char dst_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &e->key.src_ip, src_ip, sizeof(src_ip)); inet_ntop(AF_INET, &e->key.dst_ip, dst_ip, sizeof(dst_ip)); time_t ts = e->timestamp / 1000000000; struct tm *tm_info = localtime(&ts); char time_buf[20]; strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info); printf("\n[!] VIOLATION DETECTED (%s)\n", time_buf); printf(" SRC: %s:%d (MAC: ", src_ip, ntohs(e->key.src_port)); print_mac(e->src_mac); printf(")\n"); printf(" DST: %s:%d (MAC: ", dst_ip, ntohs(e->key.dst_port)); print_mac(e->dst_mac); printf(")\n"); printf(" PROTO: %s\n", e->key.protocol == IPPROTO_TCP ? "TCP" : e->key.protocol == IPPROTO_UDP ? "UDP" : "OTHER"); } // 读取性能事件 static void read_violations(void) { struct perf_event_mmap_page *header; struct violation_event *events; char *buf = NULL; size_t page_size = sysconf(_SC_PAGESIZE); size_t mmap_size = page_size * 8; // 8 pages buffer // 设置性能事件 struct perf_event_attr attr = { .sample_type = PERF_SAMPLE_RAW, .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_BPF_OUTPUT, .size = sizeof(struct perf_event_attr), .wakeup_events = 1, }; perf_fd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0); if (perf_fd < 0) { fprintf(stderr, "Failed to open perf event: %s\n", strerror(errno)); return; } // 将perf事件附加到BPF映射 int key = 0; if (bpf_map_update_elem(map_fd, &key, &perf_fd, BPF_ANY) < 0) { fprintf(stderr, "Failed to attach perf event: %s\n", strerror(errno)); close(perf_fd); return; } // 内存映射 buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); if (buf == MAP_FAILED) { fprintf(stderr, "Failed to mmap perf buffer: %s\n", strerror(errno)); close(perf_fd); return; } header = (struct perf_event_mmap_page *)buf; events = (struct violation_event *)(buf + page_size); printf("Monitoring for violations... (Ctrl+C to stop)\n"); while (1) { __u64 data_head = __sync_fetch_and_add(&header->data_head, 0); __u64 data_tail = header->data_tail; if (data_head == data_tail) { usleep(1000); // 1ms sleep continue; } while (data_tail < data_head) { struct violation_event *e = (struct violation_event *)((char *)events + (data_tail % (mmap_size - page_size))); print_violation(e); data_tail += sizeof(*e); } __sync_synchronize(); header->data_tail = data_tail; } munmap(buf, mmap_size); close(perf_fd); } // 添加白名单规则 static void add_rule(const char *src_ip, const char *dst_ip, uint16_t src_port, uint16_t dst_port, uint8_t proto) { struct flow_key key = {0}; uint8_t value = 1; inet_pton(AF_INET, src_ip, &key.src_ip); inet_pton(AF_INET, dst_ip, &key.dst_ip); key.src_port = htons(src_port); key.dst_port = htons(dst_port); key.protocol = proto; if (bpf_map_update_elem(bpf_map__fd(bpf_object__find_map_by_name(obj, "whitelist_map")), &key, &value, BPF_ANY) < 0) { fprintf(stderr, "Failed to add rule: %s\n", strerror(errno)); return; } printf("Added rule: %s:%d -> %s:%d/%s\n", src_ip, src_port, dst_ip, dst_port, proto == IPPROTO_TCP ? "tcp" : "udp"); } // 删除白名单规则 static void del_rule(const char *src_ip, const char *dst_ip, uint16_t src_port, uint16_t dst_port, uint8_t proto) { struct flow_key key = {0}; inet_pton(AF_INET, src_ip, &key.src_ip); inet_pton(AF_INET, dst_ip, &key.dst_ip); key.src_port = htons(src_port); key.dst_port = htons(dst_port); key.protocol = proto; if (bpf_map_delete_elem(bpf_map__fd(bpf_object__find_map_by_name(obj, "whitelist_map")), &key) < 0) { fprintf(stderr, "Failed to delete rule: %s\n", strerror(errno)); return; } printf("Deleted rule: %s:%d -> %s:%d/%s\n", src_ip, src_port, dst_ip, dst_port, proto == IPPROTO_TCP ? "tcp" : "udp"); } // 加载XDP程序 static int load_xdp(const char *iface) { struct rlimit rlim = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY, }; // 设置资源限制 if (setrlimit(RLIMIT_MEMLOCK, &rlim)) { fprintf(stderr, "setrlimit failed: %s\n", strerror(errno)); return -1; } // 获取接口索引 ifindex = if_nametoindex(iface); if (!ifindex) { fprintf(stderr, "Failed to get ifindex: %s\n", strerror(errno)); return -1; } // 加载BPF对象 obj = bpf_object__open("xdp_whitelist.o"); if (libbpf_get_error(obj)) { fprintf(stderr, "Failed to open BPF object\n"); return -1; } // 加载BPF程序 if (bpf_object__load(obj)) { fprintf(stderr, "Failed to load BPF object\n"); return -1; } // 获取程序FD struct bpf_program *prog = bpf_object__find_program_by_name(obj, "xdp_whitelist"); if (!prog) { fprintf(stderr, "Failed to find BPF program\n"); return -1; } prog_fd = bpf_program__fd(prog); if (prog_fd < 0) { fprintf(stderr, "Failed to get prog FD\n"); return -1; } // 附加XDP程序 if (bpf_set_link_xdp_fd(ifindex, prog_fd, XDP_FLAGS_UPDATE_IF_NOEXIST) < 0) { fprintf(stderr, "Failed to attach XDP program\n"); return -1; } // 获取映射FD(违规事件映射) struct bpf_map *map = bpf_object__find_map_by_name(obj, "violation_events"); if (!map) { fprintf(stderr, "Failed to find violation_events map\n"); return -1; } map_fd = bpf_map__fd(map); if (map_fd < 0) { fprintf(stderr, "Failed to get map FD\n"); return -1; } printf("XDP program loaded on %s (ifindex %d)\n", iface, ifindex); return 0; } // 卸载XDP程序 static void unload_xdp(void) { if (ifindex > 0) { bpf_set_link_xdp_fd(ifindex, -1, XDP_FLAGS_UPDATE_IF_NOEXIST); printf("XDP program unloaded\n"); } if (obj) { bpf_object__close(obj); } } int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: %s <interface> [options]\n", argv[0]); fprintf(stderr, "Options:\n"); fprintf(stderr, " -a <src_ip> <dst_ip> <src_port> <dst_port> <proto> Add rule\n"); fprintf(stderr, " -d <src_ip> <dst_ip> <src_port> <dst_port> <proto> Delete rule\n"); fprintf(stderr, " -m Monitor violations\n"); return 1; } const char *iface = argv[1]; // 加载XDP程序 if (load_xdp(iface) < 0) { return 1; } // 处理命令行参数 int opt_idx = 2; while (opt_idx < argc) { if (strcmp(argv[opt_idx], "-a") == 0 && argc > opt_idx + 5) { uint8_t proto = (strcmp(argv[opt_idx + 5], "tcp") == 0) ? IPPROTO_TCP : IPPROTO_UDP; add_rule(argv[opt_idx + 1], argv[opt_idx + 2], atoi(argv[opt_idx + 3]), atoi(argv[opt_idx + 4]), proto); opt_idx += 6; } else if (strcmp(argv[opt_idx], "-d") == 0 && argc > opt_idx + 5) { uint8_t proto = (strcmp(argv[opt_idx + 5], "tcp") == 0) ? IPPROTO_TCP : IPPROTO_UDP; del_rule(argv[opt_idx + 1], argv[opt_idx + 2], atoi(argv[opt_idx + 3]), atoi(argv[opt_idx + 4]), proto); opt_idx += 6; } else if (strcmp(argv[opt_idx], "-m") == 0) { read_violations(); opt_idx++; } else { fprintf(stderr, "Invalid option: %s\n", argv[opt_idx]); opt_idx++; } } unload_xdp(); return 0; } ``` ### 修正说明 1. **添加必要的头文件**: - `<sys/syscall.h>`:用于`__NR_perf_event_open` - `<sys/mman.h>`:用于`mmap`, `munmap`, `PROT_READ`, `PROT_WRITE`, `MAP_SHARED`, `MAP_FAILED` - `<time.h>`:用于`localtime`, `strftime` - `<linux/perf_event.h>`:用于`perf_event_attr`和相关常量 2. **修正函数声明**: - 将`read_violations()`和`unload_xdp()`的参数列表改为`(void)`,以符合严格的原型要求。 3. **修正`perf_event_attr`初始化**: - 使用`struct perf_event_attr`时,确保`size`字段设置为结构体大小。 - 使用正确的常量:`PERF_SAMPLE_RAW`, `PERF_TYPE_SOFTWARE`, `PERF_COUNT_SW_BPF_OUTPUT`。 4. **修正`bpf_object__find_program_by_name`的用法**: - 先获取`bpf_program`指针,再通过`bpf_program__fd`获取文件描述符,避免隐式声明和类型转换问题。 5. **错误处理**: - 增加了对`bpf_object__find_program_by_name`和`bpf_object__find_map_by_name`返回值的检查。 ### 编译步骤 1. 编译BPF程序(确保使用正确的内核头文件路径): ```bash clang -O2 -target bpf -I /path/to/kernel-headers/ -c xdp_whitelist.c -o xdp_whitelist.o ``` 2. 编译用户态程序(链接libbpf): ```bash gcc -o xdp_whitelist_ctl xdp_whitelist_user.c -I /path/to/libbpf/include -L /path/to/libbpf/lib -lbpf -lelf -lz ``` 如果使用系统自带的libbpf,可能只需要: ```bash gcc -o xdp_whitelist_ctl xdp_whitelist_user.c -lbpf -lelf -lz ``` ### 注意事项 1. 内核头文件路径:编译BPF程序时,需要指定内核头文件的路径,通常为`/usr/include/`或`/lib/modules/$(uname -r)/build`。 2. 用户态程序链接:确保链接`libbpf`、`libelf`和`libz`。 3. 权限:运行用户态程序需要root权限。 4. 卸载XDP程序:程序退出时会自动卸载XDP程序,但也可以手动卸载(例如,`ip link set dev eth0 xdp off`)。 §§相关问题§§: 1. 如何扩展此程序以支持IPv6五元组过滤? 2. 在内核4.19上使用XDP时,如何确保BPF程序的兼容性? 3. 如何优化高负载下的违规事件记录性能? 4. 如何实现持久化存储违规事件记录?</think>根据您提供的编译错误,主要问题集中在用户态程序 `xdp_whitelist_user.c` 中。以下是完整的问题分析和修复方案: ### 问题分析与修复方案 #### 1. 缺少头文件 ```c // 在文件开头添加以下头文件 #include <time.h> // 解决 localtime 和 strftime 问题 #include <sys/mman.h> // 解决 mmap, munmap 问题 #include <linux/perf_event.h> // 解决 perf_event_attr 问题 #include <sys/syscall.h> // 解决 __NR_perf_event_open 问题 ``` #### 2. 函数声明不完整 ```c // 将函数声明改为完整形式 static void read_violations(void); // 添加 void 参数 static void unload_xdp(void); // 添加 void 参数 ``` #### 3. perf_event_attr 结构体初始化 ```c // 修正后的 perf_event_attr 初始化 struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .size = sizeof(struct perf_event_attr), .config = PERF_COUNT_SW_BPF_OUTPUT, .sample_type = PERF_SAMPLE_RAW, .sample_period = 1, .wakeup_events = 1, }; ``` #### 4. 常量未定义问题 确保在头文件包含后定义缺失的常量: ```c #ifndef PERF_COUNT_SW_BPF_OUTPUT #define PERF_COUNT_SW_BPF_OUTPUT 10 #endif ``` #### 5. 其他问题修复 ```c // 修正 bpf_program__find_by_name 的使用 struct bpf_program *prog = bpf_object__find_program_by_name(obj, "xdp_whitelist"); prog_fd = bpf_program__fd(prog); ``` ### 完整修复后的用户态程序 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <sys/resource.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <bpf/libbpf.h> #include <bpf/bpf.h> #include <linux/if_link.h> #include <time.h> // 添加 #include <sys/mman.h> // 添加 #include <linux/perf_event.h> // 添加 #include <sys/syscall.h> // 添加 // 确保常量定义 #ifndef PERF_COUNT_SW_BPF_OUTPUT #define PERF_COUNT_SW_BPF_OUTPUT 10 #endif // 与内核一致的结构定义 struct flow_key { __u32 src_ip; __u32 dst_ip; __u16 src_port; __u16 dst_port; __u8 protocol; }; struct violation_event { struct flow_key key; unsigned char src_mac[6]; unsigned char dst_mac[6]; __u64 timestamp; }; // 打印MAC地址 static void print_mac(const unsigned char *mac) { printf("%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } // 打印违规事件 static void print_violation(const struct violation_event *e) { char src_ip[INET_ADDRSTRLEN]; char dst_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &e->key.src_ip, src_ip, sizeof(src_ip)); inet_ntop(AF_INET, &e->key.dst_ip, dst_ip, sizeof(dst_ip)); time_t ts = e->timestamp / 1000000000; struct tm *tm_info = localtime(&ts); char time_buf[20]; strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm_info); printf("\n[!] VIOLATION DETECTED (%s)\n", time_buf); printf(" SRC: %s:%d (MAC: ", src_ip, ntohs(e->key.src_port)); print_mac(e->src_mac); printf(")\n"); printf(" DST: %s:%d (MAC: ", dst_ip, ntohs(e->key.dst_port)); print_mac(e->dst_mac); printf(")\n"); printf(" PROTO: %s\n", e->key.protocol == IPPROTO_TCP ? "TCP" : e->key.protocol == IPPROTO_UDP ? "UDP" : "OTHER"); } // 读取性能事件 static void read_violations(void) { // 添加 void struct perf_event_mmap_page *header; struct violation_event *events; char *buf = NULL; size_t page_size = sysconf(_SC_PAGESIZE); size_t mmap_size = page_size * 8; // 8 pages buffer // 设置性能事件 struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .size = sizeof(struct perf_event_attr), .config = PERF_COUNT_SW_BPF_OUTPUT, .sample_type = PERF_SAMPLE_RAW, .sample_period = 1, .wakeup_events = 1, }; perf_fd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0); if (perf_fd < 0) { fprintf(stderr, "Failed to open perf event: %s\n", strerror(errno)); return; } // 将perf事件附加到BPF映射 int key = 0; if (bpf_map_update_elem(map_fd, &key, &perf_fd, BPF_ANY) < 0) { fprintf(stderr, "Failed to attach perf event: %s\n", strerror(errno)); close(perf_fd); return; } // 内存映射 buf = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0); if (buf == MAP_FAILED) { fprintf(stderr, "Failed to mmap perf buffer: %s\n", strerror(errno)); close(perf_fd); return; } header = (struct perf_event_mmap_page *)buf; events = (struct violation_event *)(buf + page_size); printf("Monitoring for violations... (Ctrl+C to stop)\n"); while (1) { __u64 data_head = __sync_fetch_and_add(&header->data_head, 0); __u64 data_tail = header->data_tail; if (data_head == data_tail) { usleep(1000); // 1ms sleep continue; } while (data_tail < data_head) { struct violation_event *e = (struct violation_event *)((char *)events + (data_tail % (mmap_size - page_size))); print_violation(e); data_tail += sizeof(*e); } __sync_synchronize(); header->data_tail = data_tail; } munmap(buf, mmap_size); close(perf_fd); } // 添加白名单规则 static void add_rule(const char *src_ip, const char *dst_ip, uint16_t src_port, uint16_t dst_port, uint8_t proto) { struct flow_key key = {0}; uint8_t value = 1; inet_pton(AF_INET, src_ip, &key.src_ip); inet_pton(AF_INET, dst_ip, &key.dst_ip); key.src_port = htons(src_port); key.dst_port = htons(dst_port); key.protocol = proto; if (bpf_map_update_elem(bpf_map__fd(bpf_object__find_map_by_name(obj, "whitelist_map")), &key, &value, BPF_ANY) < 0) { fprintf(stderr, "Failed to add rule: %s\n", strerror(errno)); return; } printf("Added rule: %s:%d -> %s:%d/%s\n", src_ip, src_port, dst_ip, dst_port, proto == IPPROTO_TCP ? "tcp" : "udp"); } // 删除白名单规则 static void del_rule(const char *src_ip, const char *dst_ip, uint16_t src_port, uint16_t dst_port, uint8_t proto) { struct flow_key key = {0}; inet_pton(AF_INET, src_ip, &key.src_ip); inet_pton(AF_INET, dst_ip, &key.dst_ip); key.src_port = htons(src_port); key.dst_port = htons(dst_port); key.protocol = proto; if (bpf_map_delete_elem(bpf_map__fd(bpf_object__find_map_by_name(obj, "whitelist_map")), &key) < 0) { fprintf(stderr, "Failed to delete rule: %s\n", strerror(errno)); return; } printf("Deleted rule: %s:%d -> %s:%d/%s\n", src_ip, src_port, dst_ip, dst_port, proto == IPPROTO_TCP ? "tcp" : "udp"); } // 全局变量 static int ifindex = -1; static int prog_fd = -1; static int map_fd = -1; static int perf_fd = -1; static struct bpf_object *obj = NULL; // 加载XDP程序 static int load_xdp(const char *iface) { struct rlimit rlim = { .rlim_cur = RLIM_INFINITY, .rlim_max = RLIM_INFINITY, }; // 设置资源限制 if (setrlimit(RLIMIT_MEMLOCK, &rlim)) { fprintf(stderr, "setrlimit failed: %s\n", strerror(errno)); return -1; } // 获取接口索引 ifindex = if_nametoindex(iface); if (!ifindex) { fprintf(stderr, "Failed to get ifindex: %s\n", strerror(errno)); return -1; } // 加载BPF对象 obj = bpf_object__open("xdp_whitelist.o"); if (libbpf_get_error(obj)) { fprintf(stderr, "Failed to open BPF object\n"); return -1; } // 加载BPF程序 if (bpf_object__load(obj)) { fprintf(stderr, "Failed to load BPF object\n"); return -1; } // 获取程序FD - 修正此处 struct bpf_program *prog = bpf_object__find_program_by_name(obj, "xdp_whitelist"); if (!prog) { fprintf(stderr, "Failed to find program\n"); return -1; } prog_fd = bpf_program__fd(prog); if (prog_fd < 0) { fprintf(stderr, "Failed to get prog FD\n"); return -1; } // 附加XDP程序 if (bpf_set_link_xdp_fd(ifindex, prog_fd, XDP_FLAGS_UPDATE_IF_NOEXIST) < 0) { fprintf(stderr, "Failed to attach XDP program\n"); return -1; } // 获取映射FD - 修正此处 struct bpf_map *map = bpf_object__find_map_by_name(obj, "violation_events"); if (!map) { fprintf(stderr, "Failed to find violation_events map\n"); return -1; } map_fd = bpf_map__fd(map); if (map_fd < 0) { fprintf(stderr, "Failed to get map FD\n"); return -1; } printf("XDP program loaded on %s (ifindex %d)\n", iface, ifindex); return 0; } // 卸载XDP程序 static void unload_xdp(void) { // 添加 void if (ifindex > 0) { bpf_set_link_xdp_fd(ifindex, -1, XDP_FLAGS_UPDATE_IF_NOEXIST); printf("XDP program unloaded\n"); } if (obj) { bpf_object__close(obj); } } int main(int argc, char **argv) { if (argc < 2) { fprintf(stderr, "Usage: %s <interface> [options]\n", argv[0]); fprintf(stderr, "Options:\n"); fprintf(stderr, " -a <src_ip> <dst_ip> <src_port> <dst_port> <proto> Add rule\n"); fprintf(stderr, " -d <src_ip> <dst_ip> <src_port> <dst_port> <proto> Delete rule\n"); fprintf(stderr, " -m Monitor violations\n"); return 1; } const char *iface = argv[1]; // 加载XDP程序 if (load_xdp(iface) < 0) { return 1; } // 处理命令行参数 int opt_idx = 2; while (opt_idx < argc) { if (strcmp(argv[opt_idx], "-a") == 0 && argc > opt_idx + 5) { uint8_t proto = (strcmp(argv[opt_idx + 5], "tcp") == 0) ? IPPROTO_TCP : IPPROTO_UDP; add_rule(argv[opt_idx + 1], argv[opt_idx + 2], atoi(argv[opt_idx + 3]), atoi(argv[opt_idx + 4]), proto); opt_idx += 6; } else if (strcmp(argv[opt_idx], "-d") == 0 && argc > opt_idx + 5) { uint8_t proto = (strcmp(argv[opt_idx + 5], "tcp") == 0) ? IPPROTO_TCP : IPPROTO_UDP; del_rule(argv[opt_idx + 1], argv[opt_idx + 2], atoi(argv[opt_idx + 3]), atoi(argv[opt_idx + 4]), proto); opt_idx += 6; } else if (strcmp(argv[opt_idx], "-m") == 0) { read_violations(); opt_idx++; } else { fprintf(stderr, "Invalid option: %s\n", argv[opt_idx]); opt_idx++; } } unload_xdp(); return 0; } ``` ### 关键修复点说明 1. **头文件缺失修复**: - 添加了 `<time.h>` 解决 `localtime` 和 `strftime` 问题 - 添加了 `<sys/mman.h>` 解决 `mmap` 和 `munmap` 问题 - 添加了 `<linux/perf_event.h>` 解决 `perf_event_attr` 问题 - 添加了 `<sys/syscall.h>` 解决 `__NR_perf_event_open` 问题 2. **函数声明修复**: - 将所有函数声明改为完整形式 `(void)` 而不仅仅是 `()` - 修正了函数原型不匹配的警告 3. **perf_event_attr 初始化修复**: - 使用正确的结构体初始化方式 - 确保所有字段都是 `perf_event_attr` 的有效成员 - 添加了必要的常量定义 4. **libbpf API 使用修复**: - 修正了 `bpf_object__find_program_by_name` 的使用方式 - 确保先获取程序指针再获取文件描述符 - 添加了错误检查逻辑 5. **常量定义修复**: - 为 `PERF_COUNT_SW_BPF_OUTPUT` 添加了备用定义 - 确保所有使用的常量都有明确定义 ### 编译和运行步骤 1. **编译 BPF 程序**: ```bash clang -O2 -target bpf -c xdp_whitelist.c -o xdp_whitelist.o ``` 2. **编译用户态程序**: ```bash gcc -o xdp_whitelist_ctl xdp_whitelist_user.c -lbpf -lelf -lz ``` 3. **运行程序**: ```bash # 加载并监控 sudo ./xdp_whitelist_ctl eth0 -m # 添加规则 sudo ./xdp_whitelist_ctl eth0 -a 192.168.1.100 10.0.0.1 8080 80 tcp # 删除规则 sudo ./xdp_whitelist_ctl eth0 -d 192.168.1.100 10.0.0.1 8080 80 tcp ``` ### 内核头文件版本问题解决方案 如果仍然遇到头文件版本不匹配的问题(如 `bpf.h` 版本不一致),可以尝试: 1. **使用系统头文件**: ```bash # 编译时指定内核头文件路径 clang -O2 -target bpf -I /lib/modules/$(uname -r)/build/arch/x86/include \ -I /lib/modules/$(uname -r)/build/include -c xdp_whitelist.c -o xdp_whitelist.o ``` 2. **统一头文件版本**: ```bash # 更新内核头文件 sudo apt-get install linux-headers-$(uname -r) ``` 3. **使用 BTF 支持(内核 5.10+)**: ```bash # 编译时添加 BTF 支持 clang -O2 -g -target bpf -D__TARGET_ARCH_x86 -I /usr/include/ -c xdp_whitelist.c -o xdp_whitelist.o ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值