文章目录
- 前言
- 环境准备
- 加载XDP程序
- 源码
- 构建过程
- 运行
前言
前置阅读要求:
- ebpf教程(3):使用cmake构建ebpf项目-CSDN博客
- [译] [论文] XDP (eXpress Data Path):在操作系统内核中实现快速、可编程包处理(ACM,2018)
- xdp-tools/lib/libxdp/README.org at master · xdp-project/xdp-tools
在阅读完上面的文档后,我们大概知道XDP(eXpress Data Path)允许在数据包进入内核协议栈之前进行处理,这减少了不必要的开销。由于处理发生在内核的早期阶段,XDP 能够显著提高网络处理性能,特别是对于高流量的场景。
本文是XDP的hello world – 加载XDP程序。
环境准备
# 安装依赖
apt install libxdp-dev xdp-tools# 当前的libxdp版本
pkg-config --modversion libxdp
1.4.2# 当前的内核版本(ubuntu24的内核)
uname -r
6.8.0-31-generic
我当前的网络拓扑如下图所示。当然本文的示例对网络拓扑没有要求,把程序加载到网卡上即可。
加载XDP程序
源码
下面的示例代码修改自:
- xdp-tutorial/basic01-xdp-pass/README.org at master · xdp-project/xdp-tutorial
- xdp-tutorial/basic02-prog-by-name/README.org at master · xdp-project/xdp-tutorial
bpf程序的生命周期:open–create–attach–detach。
本文的 BPF ELF 文件中有两个XDP程序,可以选择按照名称加载。
首先是XDP程序。两个程序,分别是放行或者阻止数据包。
// xdp_kernel_prog.c
#include <linux/types.h>#include <bpf/bpf_helpers.h>
#include <linux/bpf.h>SEC("xdp")
int xdp_pass_func(struct xdp_md *ctx) {bpf_printk("%s", "Pkt pass...");return XDP_PASS;
}SEC("xdp")
int xdp_drop_func(struct xdp_md *ctx) {bpf_printk("%s", "Pkt drop...");return XDP_DROP;
}char _license[] SEC("license") = "GPL";
下面是加载XDP程序的用户层程序。
示例代码中,我使用了argp库,我喜欢用这个库来处理命令行参数。它的使用可见:一步步了解Argp-CSDN博客
#include <argp.h>
#include <net/if.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>#include <bpf/libbpf.h>
#include <xdp/libxdp.h>#define PROG_NAME_MAXSIZE 32static char ifname[IF_NAMESIZE] = {};
static const char *filename = "xdp_kernel_prog.o";
static char prog_name[PROG_NAME_MAXSIZE] = {};
static volatile bool exiting = false;static int parse_opt(int key, char *arg, struct argp_state *state) {switch (key) {case 'd':snprintf(ifname, sizeof(ifname), "%s", arg);break;case 'p':snprintf(prog_name, sizeof(prog_name), "%s", arg);break;}return 0;
}static void sig_handler(int sig) { exiting = true; }int main(int argc, char *argv[]) {int ret = 0;struct bpf_object *obj;struct argp_option options[] = {{"dev", 'd', "DEV NAME", 0, "set the network card name"},{"prog", 'p', "program name", 0, "set the program"},{0},};struct argp argp = {.options = options,.parser = parse_opt,};argp_parse(&argp, argc, argv, 0, 0, 0);// check parameterprintf("choice dev: %s\n", ifname);int ifindex = if_nametoindex(ifname);if (ifindex == 0) {perror("if_nametoindex failed");exit(EXIT_FAILURE);}printf("%s's index %d\n", ifname, ifindex);/* Cleaner handling of Ctrl-C */signal(SIGINT, sig_handler);signal(SIGTERM, sig_handler);obj = bpf_object__open(filename);if (obj == NULL) {perror("bpf_object__open failed");exit(EXIT_FAILURE);}struct xdp_program_opts prog_opts = {};prog_opts.sz = sizeof(struct xdp_program_opts);prog_opts.obj = obj;prog_opts.prog_name = prog_name;struct xdp_program *prog = xdp_program__create(&prog_opts);if (prog == NULL) {perror("xdp_program__create failed.");exit(EXIT_FAILURE);}ret = xdp_program__attach(prog, ifindex, XDP_MODE_UNSPEC, 0);if (ret != 0) {perror("xdp_program__attach failed.");exit(EXIT_FAILURE);}while (!exiting) {sleep(1);}cleanup:struct xdp_multiprog *mp = xdp_multiprog__get_from_ifindex(ifindex);ret = xdp_multiprog__detach(mp);if (ret != 0) {perror("xdp_multiprog__detach failed.");exit(EXIT_FAILURE);}bpf_object__close(obj);
}
构建过程
构建过程还是稍微有点麻烦了。CMake文件修改自:libbpf-bootstrap/tools/cmake at master · libbpf/libbpf-bootstrap
cmake_minimum_required(VERSION 3.10)project(xdp-load-prog)find_package(PkgConfig)
pkg_check_modules(LIBBPF REQUIRED libbpf)
pkg_check_modules(LIBXDP REQUIRED libxdp)# Get clang bpf system includes
execute_process(COMMAND bash -c "clang -v -E - < /dev/null 2>&1 |sed -n '/<...> search starts here:/,/End of search list./{ s| \\(/.*\\)|-idirafter \\1|p }'"OUTPUT_VARIABLE CLANG_SYSTEM_INCLUDES_outputERROR_VARIABLE CLANG_SYSTEM_INCLUDES_errorRESULT_VARIABLE CLANG_SYSTEM_INCLUDES_resultOUTPUT_STRIP_TRAILING_WHITESPACE)
if(${CLANG_SYSTEM_INCLUDES_result} EQUAL 0)separate_arguments(CLANG_SYSTEM_INCLUDES UNIX_COMMAND ${CLANG_SYSTEM_INCLUDES_output})message(STATUS "BPF system include flags: ${CLANG_SYSTEM_INCLUDES}")
else()message(FATAL_ERROR "Failed to determine BPF system includes: ${CLANG_SYSTEM_INCLUDES_error}")
endif()set(BPF_C_FILE ${CMAKE_CURRENT_SOURCE_DIR}/xdp_kernel_prog.c)
set(BPF_O_FILE ${CMAKE_CURRENT_BINARY_DIR}/xdp_kernel_prog.o)
add_custom_command(OUTPUT ${BPF_O_FILE}COMMAND clang -g -O2 -target bpf ${CLANG_SYSTEM_INCLUDES} -c ${BPF_C_FILE} -o ${BPF_O_FILE}COMMAND_EXPAND_LISTSVERBATIMDEPENDS ${BPF_C_FILE}COMMENT "[clang] Building BPF file: ${BPF_C_FILE}")add_custom_target(generate_bpf_obj ALLDEPENDS ${BPF_O_FILE}
)add_executable(xdp_load xdp_loader.c)
target_link_libraries(xdp_load PRIVATE ${LIBBPF_LIBRARIES} ${LIBXDP_LIBRARIES})
运行
# 查看help信息
./xdp_load --help
Usage: xdp_load [OPTION...]-d, --dev=DEV NAME set the network card name-p, --prog=program name set the program-?, --help Give this help list--usage Give a short usage messageMandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.
放行指定网卡的所有数据包。
./xdp_load --dev=ens19 --prog=xdp_pass_func# 查看是否附加成功
xdp-loader status ens19
CURRENT XDP PROGRAM STATUS:Interface Prio Program name Mode ID Tag Chain actions
--------------------------------------------------------------------------------------
ens19 xdp_dispatcher native 403 4d7e87c0d30db711 => 50 xdp_pass_func 412 2d69c152cb7a3b4b XDP_PASS# 向网卡发送数据后,查看trace信息
cat /sys/kernel/debug/tracing/trace_pipe<idle>-0 [004] ..s2. 24810.751471: bpf_trace_printk: Pkt pass...<idle>-0 [004] ..s2. 24811.768707: bpf_trace_printk: Pkt pass...<idle>-0 [004] ..s2. 24815.992664: bpf_trace_printk: Pkt pass...
丢弃指定网卡的所有数据包。
./xdp_load --dev=ens19 --prog=xdp_drop_funcxdp-loader status ens19
CURRENT XDP PROGRAM STATUS:Interface Prio Program name Mode ID Tag Chain actions
--------------------------------------------------------------------------------------
ens19 xdp_dispatcher native 423 4d7e87c0d30db711 => 50 xdp_drop_func 433 510776c6b1cf234d XDP_PASScat /sys/kernel/debug/tracing/trace_pipe<idle>-0 [004] ..s2. 24902.015467: bpf_trace_printk: Pkt drop...<idle>-0 [004] ..s2. 24903.032696: bpf_trace_printk: Pkt drop...<idle>-0 [004] ..s2. 24907.128676: bpf_trace_printk: Pkt drop...<idle>-0 [004] ..s2. 24908.152674: bpf_trace_printk: Pkt drop...