├── 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 | [![Build Status](https://travis-ci.com/libbpf/libbpf.svg?branch=master)](https://travis-ci.com/github/libbpf/libbpf) 24 | [![Total alerts](https://img.shields.io/lgtm/alerts/g/libbpf/libbpf.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/libbpf/libbpf/alerts/) 25 | [![Coverity](https://img.shields.io/coverity/scan/18195.svg)](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 | --------------------------------------------------------------------------------