From 886948d5557122a75cc476b9da5c81d05f41b9db Mon Sep 17 00:00:00 2001 From: yunwei37 Date: Sun, 8 Sep 2024 06:43:56 +0000 Subject: [PATCH] fix linter issues and add xdp in rust --- src/1-helloworld/README.md | 4 +- src/14-tcpstates/README_en.md | 1 - src/20-tc/README_en.md | 3 +- src/21-xdp/README.md | 2 - src/21-xdp/README_en.md | 6 +- src/22-android/README.md | 2 +- src/22-android/README_en.md | 2 +- src/41-xdp-tcpdump/.gitignore | 2 + src/41-xdp-tcpdump/Cargo.lock | 872 +++++++++++++++++++++++ src/41-xdp-tcpdump/Cargo.toml | 15 + src/41-xdp-tcpdump/Makefile | 141 ---- src/41-xdp-tcpdump/README.md | 2 +- src/41-xdp-tcpdump/build.rs | 35 + src/41-xdp-tcpdump/src/bpf/xdppass.bpf.c | 15 + src/41-xdp-tcpdump/src/main.rs | 58 ++ src/42-xdp-loadbalancer/README.md | 98 +-- src/42-xdp-loadbalancer/README_en.md | 4 +- src/6-sigsnoop/README_en.md | 5 +- src/8-exitsnoop/README_en.md | 2 +- src/bcc-documents/kernel-versions_en.md | 14 +- 20 files changed, 1046 insertions(+), 237 deletions(-) create mode 100644 src/41-xdp-tcpdump/.gitignore create mode 100644 src/41-xdp-tcpdump/Cargo.lock create mode 100644 src/41-xdp-tcpdump/Cargo.toml delete mode 100644 src/41-xdp-tcpdump/Makefile create mode 100644 src/41-xdp-tcpdump/build.rs create mode 100644 src/41-xdp-tcpdump/src/bpf/xdppass.bpf.c create mode 100644 src/41-xdp-tcpdump/src/main.rs diff --git a/src/1-helloworld/README.md b/src/1-helloworld/README.md index 9d016c2c..0d5e018f 100644 --- a/src/1-helloworld/README.md +++ b/src/1-helloworld/README.md @@ -17,7 +17,7 @@ 要开发eBPF程序,您需要安装以下软件和工具: - Linux 内核:由于eBPF是内核技术,因此您需要具备较新版本的Linux内核(至少 4.8 及以上版本,建议至少在 5.15 以上),以支持eBPF功能。 - - 建议使用最新的 Ubuntu 版本(例如 Ubuntu 23.10)以获得最佳的学习体验,较旧的内核 eBPF 功能支持可能相对不全。 + - 建议使用最新的 Ubuntu 版本(例如 Ubuntu 23.10)以获得最佳的学习体验,较旧的内核 eBPF 功能支持可能相对不全。 - LLVM 和 Clang:这些工具用于编译eBPF程序。安装最新版本的LLVM和Clang可以确保您获得最佳的eBPF支持。 eBPF 程序主要由两部分构成:内核态部分和用户态部分。内核态部分包含 eBPF 程序的实际逻辑,用户态部分负责加载、运行和监控内核态程序。 @@ -127,7 +127,7 @@ docker run -it -v `pwd`/:/src/ ghcr.io/eunomia-bpf/ecc-`uname -m`:latest ```console $ sudo ./ecli run package.json -Runing eBPF program... +Running eBPF program... ``` 运行这段程序后,可以通过查看 /sys/kernel/debug/tracing/trace_pipe 文件来查看 eBPF 程序的输出: diff --git a/src/14-tcpstates/README_en.md b/src/14-tcpstates/README_en.md index 06a2ba86..189474d3 100644 --- a/src/14-tcpstates/README_en.md +++ b/src/14-tcpstates/README_en.md @@ -299,7 +299,6 @@ $ sudo ./tcpstates SKADDR PID COMM LADDR LPORT RADDR RPORT OLDSTATE -> NEWSTATE MS ffff9bf61bb62bc0 164978 node 192.168.88.15 0 52.178.17.2 443 CLOSE -> SYN_SENT 0.000 ffff9bf61bb62bc0 0 swapper/0 192.168.88.15 41596 52.178.17.2 443 SYN_SENT -> ESTABLISHED 225.794". -format: Return only the translated content, not including the original text.``` "ffff9bf61bb62bc0 0 swapper/0 192.168.88.15 41596 52.178.17.2 443 ESTABLISHED -> CLOSE_WAIT 901.454 ffff9bf61bb62bc0 164978 node 192.168.88.15 41596 52.178.17.2 443 CLOSE_WAIT -> LAST_ACK 0.793 ffff9bf61bb62bc0 164978 node 192.168.88.15 41596 52.178.17.2 443 LAST_ACK -> LAST_ACK 0.086 diff --git a/src/20-tc/README_en.md b/src/20-tc/README_en.md index b682dae5..61afea2c 100644 --- a/src/20-tc/README_en.md +++ b/src/20-tc/README_en.md @@ -51,9 +51,8 @@ int tc_ingress(struct __sk_buff *ctx) char __license[] SEC("license") = "GPL"; ``` -This code defines an eBPF program that can capture and process packets through Linux TC (Transmission Control). In this program, we limit it to capture only IPv4 protocol packets, and then print out the total length and Time-To-Live (TTL) value of the packet using the bpf_printk function.Here is the translated text: +This code defines an eBPF program that can capture and process packets through Linux TC (Transmission Control). In this program, we limit it to capture only IPv4 protocol packets, and then print out the total length and Time-To-Live (TTL) value of the packet using the bpf_printk function. -" What needs to be noted is that we use some BPF library functions in the code, such as the functions bpf_htons and bpf_ntohs, which are used for conversion between network byte order and host byte order. In addition, we also use some comments to provide additional points and option information for TC. For example, at the beginning of this code, we use the following comments: ```c diff --git a/src/21-xdp/README.md b/src/21-xdp/README.md index ed0a8324..d6269faf 100644 --- a/src/21-xdp/README.md +++ b/src/21-xdp/README.md @@ -19,9 +19,7 @@ XDP 运行在比传统 Linux 网络组件(如 cBPF)更低的层级,在网 1. **缺乏内核集成**:DPDK 及其他内核绕过解决方案无法利用现有的内核网络功能,开发者必须在用户空间重新实现许多协议和功能。 2. **安全边界**:这些绕过技术破坏了内核的安全模型,使得难以利用内核提供的安全工具。 - 3. **用户空间与内核的转换开销**:当用户空间数据包处理需要与传统内核网络交互时(例如基于套接字的应用程序),数据包必须重新注入到内核中,增加了开销和复杂性。 - 4. **专用 CPU 使用**:为了处理高流量,DPDK 和类似解决方案通常需要专用的 CPU 核心来处理数据包,这限制了通用系统的可扩展性和效率。 另一个替代 XDP 的方法是使用 Linux 网络栈中的 **内核模块** 或 **挂钩**。虽然这种方法可以很好地集成现有的内核功能,但它需要大量的内核修改,且由于在数据包处理管道的后期运行,无法提供与 XDP 相同的性能优势。 diff --git a/src/21-xdp/README_en.md b/src/21-xdp/README_en.md index dcbded23..ef6928cb 100644 --- a/src/21-xdp/README_en.md +++ b/src/21-xdp/README_en.md @@ -156,8 +156,8 @@ For those interested in further exploring eBPF, visit our tutorial code reposito For more information, you can refer to: -+ -+ -+ +- +- +- > The original link of this article: diff --git a/src/22-android/README.md b/src/22-android/README.md index 7125175d..07d71146 100644 --- a/src/22-android/README.md +++ b/src/22-android/README.md @@ -1,4 +1,4 @@ -# 在 Andorid 上使用 eBPF 程序 +# 在 Android 上使用 eBPF 程序 > 本文主要记录了笔者在 Android Studio Emulator 中测试高版本 Android Kernel 对基于 libbpf 的 CO-RE 技术支持程度的探索过程、结果和遇到的问题。 > 测试采用的方式是在 Android Shell 环境下构建 Debian 环境,并基于此尝试构建 eunomia-bpf 工具链、运行其测试用例。 diff --git a/src/22-android/README_en.md b/src/22-android/README_en.md index 38c202a8..f1f660bf 100644 --- a/src/22-android/README_en.md +++ b/src/22-android/README_en.md @@ -1,6 +1,6 @@ # eBPF Tutorial by Example: Using eBPF Programs on Android -> This article mainly documents the author's exploration process, results, and issues encountered while testing the level of support for CO-RE technology based on the libbpf library on high version Android kernels in the Android Studio Emulator. +> This article mainly documents the author's exploration process, results, and issues encountered while testing the level of support for CO-RE technology based on the libbpf library on high version Android kernels in the Android Studio Emulator. > The test was conducted by building a Debian environment in the Android Shell environment and attempting to build the eunomia-bpf toolchain and run its test cases based on this. ## Background diff --git a/src/41-xdp-tcpdump/.gitignore b/src/41-xdp-tcpdump/.gitignore new file mode 100644 index 00000000..3a1b4489 --- /dev/null +++ b/src/41-xdp-tcpdump/.gitignore @@ -0,0 +1,2 @@ +/src/bpf/.output +/target diff --git a/src/41-xdp-tcpdump/Cargo.lock b/src/41-xdp-tcpdump/Cargo.lock new file mode 100644 index 00000000..56032cc0 --- /dev/null +++ b/src/41-xdp-tcpdump/Cargo.lock @@ -0,0 +1,872 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cc" +version = "1.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap 0.11.0", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "textwrap 0.16.1", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck 0.4.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix 0.29.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libbpf-cargo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9bdbd32bc3fd6a2b6ca7a73cf1a4976c1da51be8367849226573348f338ec0" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap 3.2.25", + "libbpf-sys", + "memmap2", + "num_enum", + "regex", + "scroll", + "scroll_derive", + "semver", + "serde", + "serde_json", + "tempfile", + "thiserror", +] + +[[package]] +name = "libbpf-rs" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae623007dfcd01956d889e06f2c003106573158fe61e88450e9f448466d6dbed" +dependencies = [ + "bitflags 1.3.2", + "lazy_static", + "libbpf-sys", + "nix 0.24.3", + "num_enum", + "strum_macros", + "thiserror", + "vsprintf", +] + +[[package]] +name = "libbpf-sys" +version = "1.4.5+v1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cabee52b6f7e73308d6fd4f8e6bbbdcb97670f49f6e581c5897e4d2410b6019" +dependencies = [ + "cc", + "nix 0.29.0", + "pkg-config", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustix" +version = "0.38.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap 2.34.0", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.5.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsprintf" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aec2f81b75ca063294776b4f7e8da71d1d5ae81c2b1b149c8d89969230265d63" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "xdp" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctrlc", + "libbpf-cargo", + "libbpf-rs", + "libc", + "structopt", +] diff --git a/src/41-xdp-tcpdump/Cargo.toml b/src/41-xdp-tcpdump/Cargo.toml new file mode 100644 index 00000000..b4bb3de5 --- /dev/null +++ b/src/41-xdp-tcpdump/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "xdp" +version = "0.1.0" +authors = ["Yusheng Zheng "] +edition = "2021" + +[dependencies] +anyhow = "1.0" +ctrlc = { version = "3.0", features = ["termination"] } +libc = "0.2" +libbpf-rs = "0.19" +structopt = "0.3" + +[build-dependencies] +libbpf-cargo = "0.13" diff --git a/src/41-xdp-tcpdump/Makefile b/src/41-xdp-tcpdump/Makefile deleted file mode 100644 index eac2df7a..00000000 --- a/src/41-xdp-tcpdump/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -OUTPUT := .output -CLANG ?= clang -LIBBPF_SRC := $(abspath ../third_party/libbpf/src) -BPFTOOL_SRC := $(abspath ../third_party/bpftool/src) -LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) -BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) -BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool -LIBBLAZESYM_SRC := $(abspath ../third_party/blazesym/) -LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym.a) -LIBBLAZESYM_HEADER := $(abspath $(OUTPUT)/blazesym.h) -ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ - | sed 's/arm.*/arm/' \ - | sed 's/aarch64/arm64/' \ - | sed 's/ppc64le/powerpc/' \ - | sed 's/mips.*/mips/' \ - | sed 's/riscv64/riscv/' \ - | sed 's/loongarch64/loongarch/') -VMLINUX := ../third_party/vmlinux/$(ARCH)/vmlinux.h -# Use our own libbpf API headers and Linux UAPI headers distributed with -# libbpf to avoid dependency on system-wide headers, which could be missing or -# outdated -INCLUDES := -I$(OUTPUT) -I../third_party/libbpf/include/uapi -I$(dir $(VMLINUX)) -CFLAGS := -g -Wall -ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) - -APPS = funclatency - -CARGO ?= $(shell which cargo) -ifeq ($(strip $(CARGO)),) -BZS_APPS := -else -BZS_APPS := -APPS += $(BZS_APPS) -# Required by libblazesym -ALL_LDFLAGS += -lrt -ldl -lpthread -lm -endif - -# Get Clang's default includes on this system. We'll explicitly add these dirs -# to the includes list when compiling with `-target bpf` because otherwise some -# architecture-specific dirs will be "missing" on some architectures/distros - -# headers such as asm/types.h, asm/byteorder.h, asm/socket.h, asm/sockios.h, -# sys/cdefs.h etc. might be missing. -# -# Use '-idirafter': Don't interfere with include mechanics except where the -# build would have failed anyways. -CLANG_BPF_SYS_INCLUDES ?= $(shell $(CLANG) -v -E - &1 \ - | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') - -ifeq ($(V),1) - Q = - msg = -else - Q = @ - msg = @printf ' %-8s %s%s\n' \ - "$(1)" \ - "$(patsubst $(abspath $(OUTPUT))/%,%,$(2))" \ - "$(if $(3), $(3))"; - MAKEFLAGS += --no-print-directory -endif - -define allow-override - $(if $(or $(findstring environment,$(origin $(1))),\ - $(findstring command line,$(origin $(1)))),,\ - $(eval $(1) = $(2))) -endef - -$(call allow-override,CC,$(CROSS_COMPILE)cc) -$(call allow-override,LD,$(CROSS_COMPILE)ld) - -.PHONY: all -all: $(APPS) - -.PHONY: clean -clean: - $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) $(APPS) - -$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): - $(call msg,MKDIR,$@) - $(Q)mkdir -p $@ - -# Build libbpf -$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf - $(call msg,LIB,$@) - $(Q)$(MAKE) -C $(LIBBPF_SRC) BUILD_STATIC_ONLY=1 \ - OBJDIR=$(dir $@)/libbpf DESTDIR=$(dir $@) \ - INCLUDEDIR= LIBDIR= UAPIDIR= \ - install - -# Build bpftool -$(BPFTOOL): | $(BPFTOOL_OUTPUT) - $(call msg,BPFTOOL,$@) - $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap - - -$(LIBBLAZESYM_SRC)/target/release/libblazesym.a:: - $(Q)cd $(LIBBLAZESYM_SRC) && $(CARGO) build --features=cheader,dont-generate-test-files --release - -$(LIBBLAZESYM_OBJ): $(LIBBLAZESYM_SRC)/target/release/libblazesym.a | $(OUTPUT) - $(call msg,LIB, $@) - $(Q)cp $(LIBBLAZESYM_SRC)/target/release/libblazesym.a $@ - -$(LIBBLAZESYM_HEADER): $(LIBBLAZESYM_SRC)/target/release/libblazesym.a | $(OUTPUT) - $(call msg,LIB,$@) - $(Q)cp $(LIBBLAZESYM_SRC)/target/release/blazesym.h $@ - -# Build BPF code -$(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard %.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) - $(call msg,BPF,$@) - $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ - $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ - -c $(filter %.c,$^) -o $(patsubst %.bpf.o,%.tmp.bpf.o,$@) - $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) - -# Generate BPF skeletons -$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) - $(call msg,GEN-SKEL,$@) - $(Q)$(BPFTOOL) gen skeleton $< > $@ - -# Build user-space code -$(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h - -$(OUTPUT)/%.o: %.c $(wildcard %.h) | $(OUTPUT) - $(call msg,CC,$@) - $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ - -$(patsubst %,$(OUTPUT)/%.o,$(BZS_APPS)): $(LIBBLAZESYM_HEADER) - -$(BZS_APPS): $(LIBBLAZESYM_OBJ) - -# Build application binary -$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) - $(call msg,BINARY,$@) - $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@ - -# delete failed targets -.DELETE_ON_ERROR: - -# keep intermediate (.skel.h, .bpf.o, etc) targets -.SECONDARY: diff --git a/src/41-xdp-tcpdump/README.md b/src/41-xdp-tcpdump/README.md index 33a0e99f..6cf898ec 100644 --- a/src/41-xdp-tcpdump/README.md +++ b/src/41-xdp-tcpdump/README.md @@ -1 +1 @@ -# Write a +# Write a tcpdump in XDP to capture packets diff --git a/src/41-xdp-tcpdump/build.rs b/src/41-xdp-tcpdump/build.rs new file mode 100644 index 00000000..6f336964 --- /dev/null +++ b/src/41-xdp-tcpdump/build.rs @@ -0,0 +1,35 @@ +use std::env; +use std::path::Path; +use std::path::PathBuf; + +use libbpf_cargo::SkeletonBuilder; + +const SRC: &str = "src/bpf/xdppass.bpf.c"; + +fn main() { + let mut out = + PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR must be set in build script")); + out.push("xdppass.skel.rs"); + + let arch = env::var("CARGO_CFG_TARGET_ARCH") + .expect("CARGO_CFG_TARGET_ARCH must be set in build script"); + + SkeletonBuilder::new() + .source(SRC) + .clang_args(format!( + "-I{}", + Path::new("../third_party/vmlinux") + .join(match arch.as_ref() { + "aarch64" => "arm64", + "loongarch64" => "loongarch", + "powerpc64" => "powerpc", + "riscv64" => "riscv", + "x86_64" => "x86", + _ => &arch, + }) + .display() + )) + .build_and_generate(out) + .unwrap(); + println!("cargo:rerun-if-changed={}", SRC); +} diff --git a/src/41-xdp-tcpdump/src/bpf/xdppass.bpf.c b/src/41-xdp-tcpdump/src/bpf/xdppass.bpf.c new file mode 100644 index 00000000..f0bf3956 --- /dev/null +++ b/src/41-xdp-tcpdump/src/bpf/xdppass.bpf.c @@ -0,0 +1,15 @@ +#include "vmlinux.h" +#include + +SEC("xdp") +int xdp_pass(struct xdp_md *ctx) +{ + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + int pkt_sz = data_end - data; + + bpf_printk("packet size: %d", pkt_sz); + return XDP_PASS; +} + +char __license[] SEC("license") = "GPL"; diff --git a/src/41-xdp-tcpdump/src/main.rs b/src/41-xdp-tcpdump/src/main.rs new file mode 100644 index 00000000..90f2f3fa --- /dev/null +++ b/src/41-xdp-tcpdump/src/main.rs @@ -0,0 +1,58 @@ +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::{thread, time}; + +use anyhow::{bail, Result}; +use structopt::StructOpt; + +mod xdppass { + include!(concat!(env!("OUT_DIR"), "/xdppass.skel.rs")); +} +use xdppass::*; + +#[derive(Debug, StructOpt)] +struct Command { + /// Interface index to attach XDP program + #[structopt(default_value = "0")] + ifindex: i32, +} + +fn bump_memlock_rlimit() -> Result<()> { + let rlimit = libc::rlimit { + rlim_cur: 128 << 20, + rlim_max: 128 << 20, + }; + + if unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &rlimit) } != 0 { + bail!("Failed to increase rlimit"); + } + + Ok(()) +} + +fn main() -> Result<()> { + let opts = Command::from_args(); + + bump_memlock_rlimit()?; + + let skel_builder = XdppassSkelBuilder::default(); + let open_skel = skel_builder.open()?; + let mut skel = open_skel.load()?; + let link = skel.progs_mut().xdp_pass().attach_xdp(opts.ifindex)?; + skel.links = XdppassLinks { + xdp_pass: Some(link), + }; + + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + })?; + + while running.load(Ordering::SeqCst) { + eprint!("."); + thread::sleep(time::Duration::from_secs(1)); + } + + Ok(()) +} diff --git a/src/42-xdp-loadbalancer/README.md b/src/42-xdp-loadbalancer/README.md index ed57cf91..06fc527c 100644 --- a/src/42-xdp-loadbalancer/README.md +++ b/src/42-xdp-loadbalancer/README.md @@ -1,94 +1,44 @@ -# eBPF 实战教程 21:通过 XDP 实现可编程的包处理 +# eBPF 开发者教程: 简单的 XDP 负载均衡器 -在本教程中,我们将介绍 XDP(eXpress Data Path),并通过一个小例子来帮助您入门。稍后,我们将探索更多高级的 XDP 应用程序,如负载均衡、防火墙以及其他现实世界中的用例。如果您对 eBPF 或 XDP 感兴趣,请在 [Github](https://github.com/eunomia-bpf/bpf-developer-tutorial) 上给我们一个 Star! +在本教程中,我们将指导您如何使用eBPF(扩展的Berkeley Packet Filter)实现一个简单的XDP(eXpress Data Path)负载均衡器。只需使用C语言和libbpf库,无需外部依赖,这是一个适合开发者的实践指南,帮助您充分利用Linux内核的强大功能来构建高效的网络应用程序。 -## 什么是 XDP? +## 为什么选择XDP? -XDP 是 Linux 内核中的高性能可编程数据路径,专为网络接口级别的包处理而设计。通过将 eBPF 程序直接附加到网络设备驱动程序上,XDP 能够在数据包到达内核的网络栈之前拦截并处理它们。这使得 XDP 能以极低的延迟处理数据包,特别适合用于 DDoS 防护、负载均衡和流量过滤等任务。实际上,XDP 每核处理速度可以高达 **每秒 2400 万包(Mpps)**。 +`XDP`(eXpress Data Path)是Linux中的一个高速、内核级网络框架,它允许在网络堆栈的最早阶段,即在网络接口卡(NIC)上处理数据包。这使得XDP可以进行超低延迟和高吞吐量的数据包处理,非常适合用于负载均衡、DDoS保护和流量过滤等任务。 -### 为什么选择 XDP? +XDP的关键特性: -XDP 运行在比传统 Linux 网络组件(如 cBPF)更低的层次,它在网络设备驱动程序的软中断上下文中运行,能够在数据包经过内核的标准网络栈之前处理它们,绕过创建代表网络数据包的 `skb_buff` 结构。对于诸如丢弃恶意包或负载均衡等简单但频繁的操作,这种早期阶段的处理可以显著提升性能。 +1. **快速数据包处理**:XDP直接在网络接口卡(NIC)级别处理数据包,减少了延迟,并通过避免通常的网络堆栈开销来提高性能。 +2. **高效**:由于在数据包进入内核之前处理它们,XDP最大限度地减少了CPU使用率,能够在高流量负载下保持系统的快速响应。 +3. **可定制的eBPF**:XDP程序使用eBPF编写,允许您为特定的用例创建自定义的数据包处理逻辑,例如丢弃、重定向或转发数据包。 +4. **低CPU开销**:支持零拷贝数据包转发,XDP占用更少的系统资源,非常适合在最少CPU负载的情况下处理高流量。 +5. **简单操作**:XDP程序返回预定义的操作,例如丢弃、通过或重定向数据包,提供对流量处理的控制。 -与其他数据包处理机制相比,XDP 在性能和可用性之间取得了平衡,既利用了 Linux 内核的安全性和可靠性,又通过可编程的 eBPF 提供了灵活性。 +### 使用XDP的项目 -## XDP 与其他方法的比较 +- `Cilium` 是一个为云原生环境(如Kubernetes)设计的开源网络工具。它使用XDP高效处理数据包过滤和负载均衡,提升了高流量网络中的性能。 +- `Katran` 由Facebook开发,是一个负载均衡器,它使用XDP处理数百万的连接,且CPU使用率低。它高效地将流量分发到服务器,在Facebook内部被用于大规模的网络环境。 +- `Cloudflare` 使用XDP来防御DDoS攻击。通过在NIC级别过滤恶意流量,Cloudflare可以在攻击数据包进入内核之前将其丢弃,最大限度地减少对网络的影响。 -在 XDP 之前,有多种其他方案试图通过绕过内核来加速数据包处理。其中一个显著的例子是 **DPDK**(数据平面开发套件)。DPDK 允许用户空间应用程序直接控制网络设备,从而实现非常高的性能。然而,这种方法也有其权衡之处: +### 为什么选择XDP而不是其他方法? -1. **缺乏内核集成**:DPDK 等绕过内核的解决方案无法利用现有的内核网络功能,开发人员需要在用户空间重新实现许多协议和功能。 +与传统工具如`iptables`或`tc`相比,XDP具有以下优势: -2. **安全边界**:这些绕过技术打破了内核的安全模型,难以利用内核提供的安全工具。 - -3. **用户空间与内核的切换成本**:当用户空间数据包处理需要与传统的内核网络交互(如基于套接字的应用程序)时,数据包必须重新注入内核,这会增加开销和复杂性。 - -4. **专用 CPU 使用**:为了处理高流量,DPDK 等解决方案通常需要专门分配一个或多个 CPU 核心来专门处理数据包,这限制了通用系统的可扩展性和效率。 - -另一种替代 XDP 的方法是使用 **内核模块** 或 Linux 网络栈中的 **钩子**。虽然这种方法与现有的内核功能很好地集成,但它需要对内核进行大量修改,并且由于它在数据包处理管道的后期操作,无法提供与 XDP 相同的性能提升。 - -### XDP + eBPF 的优势 - -XDP 和 eBPF 的组合在绕过内核的解决方案(如 DPDK)和内核集成解决方案之间提供了一个折中方案。以下是 XDP + eBPF 的优势: - -- **高性能**:通过在网卡驱动程序层早期拦截数据包,XDP 能够以接近线速的性能执行数据包的丢弃、重定向或负载均衡操作,同时保持较低的资源使用率。 - -- **内核集成**:与 DPDK 不同,XDP 在 Linux 内核中工作,允许与现有的内核网络栈和工具(如 `iptables`、`nftables` 或套接字)无缝交互。无需在用户空间重新实现网络协议。 - -- **安全性**:eBPF 虚拟机(VM)确保用户定义的 XDP 程序在沙箱环境中运行,避免不稳定的代码影响内核。eBPF 的安全模型防止恶意或错误的代码破坏系统,为可编程数据包处理提供了一个安全的环境。 - -- **无需专用 CPU**:XDP 允许在无需专门分配 CPU 核心的情况下进行数据包处理,这提高了系统的整体效率,允许更灵活的资源分配。 - -总的来说,XDP + eBPF 提供了一个高性能、灵活且安全的可编程数据包处理解决方案,消除了完全绕过内核的方案的缺点,同时保留了内核的安全性和功能。 - ---- - -## XDP 的项目和应用案例 - -XDP 已经被用于多个高知名度的项目中,展示了它在现实网络场景中的强大功能和灵活性: - -### 1. **Cilium** - -- **描述**:Cilium 是一个开源的网络、安全和可观测性工具,专为云原生环境(特别是 Kubernetes)设计。它利用 XDP 实现高性能的数据包过滤和负载均衡。 -- **用例**:Cilium 将数据包过滤和安全策略卸载到 XDP,以实现高吞吐量和低延迟的流量管理,而不牺牲可扩展性。 -- **链接**:[Cilium](https://cilium.io/) - -### 2. **Katran** - -- **描述**:Katran 是 Facebook 开发的四层负载均衡器,经过优化以实现高可扩展性和高性能。它使用 XDP 来处理数据包转发,开销极小。 -- **用例**:Katran 每秒处理数百万个数据包,将流量高效地分发到后端服务器,XDP 实现了低延迟和高性能的负载均衡,适用于大规模数据中心。 -- **链接**:[Katran GitHub](https://github.com/facebookincubator/katran) - -### 3. **Cloudflare 的 XDP DDoS 保护** - -- **描述**:Cloudflare 已经实现了 XDP 用于实时 DDoS 缓解。通过在 NIC 层处理数据包,Cloudflare 可以在攻击流量到达网络栈之前将其过滤掉,最大限度地减少 DDoS 攻击对系统的影响。 -- **用例**:Cloudflare 利用 XDP 在管道的早期丢弃恶意数据包,保护其基础设施免受大规模 DDoS 攻击,同时保持对合法流量的高可用性。 -- **链接**:[Cloudflare 博客关于 XDP](https://blog.cloudflare.com/tag/xdp/) - -这些项目展示了 XDP 在安全、负载均衡和云原生网络等不同领域的可扩展性和高效性。 - ---- - -### 为什么选择 XDP 而不是其他方法? - -与 `iptables`、`nftables` 或 `tc` 等传统方法相比,XDP 具有几个明显的优势: - -- **速度和低开销**:XDP 直接在网卡驱动程序中操作,绕过了内核的大部分开销,从而实现了更快的数据包处理。 - -- **定制性**:XDP 允许开发者通过 eBPF 创建自定义的包处理程序,提供了比传统工具(如 `iptables`)更灵活和细粒度的控制。 - -- **资源效率**:与 DPDK 等用户空间解决方案不同,XDP 不需要为数据包处理专门分配整个 CPU 核心,因此在高性能网络中是更高效的选择。 +- **速度**:它直接在NIC驱动程序中操作,数据包处理速度远快于传统方法。 +- **灵活性**:通过eBPF,您可以编写自定义的数据包处理逻辑,以满足特定需求。 +- **效率**:XDP使用更少的资源,非常适合需要处理高流量而不使系统过载的环境。 ## 项目:构建一个简单的负载均衡器 -在这个项目中,我们将专注于使用 XDP 构建一个负载均衡器。负载均衡器通过将传入的网络流量高效地分配到多个后端服务器,防止任何一台服务器过载。通过结合 XDP 和 eBPF,我们可以构建一个在 Linux 网络栈边缘运行的负载均衡器,确保即使在高流量条件下也能保持高性能。 +在本项目中,我们将专注于使用XDP构建一个负载均衡器。负载均衡器通过将传入的网络流量高效地分发到多个后端服务器,防止单个服务器过载。结合XDP和eBPF,我们可以构建一个运行在Linux网络堆栈边缘的负载均衡器,确保即使在高流量情况下也能保持高性能。 -我们将要实现的负载均衡器将具备以下功能: +我们将实现的负载均衡器将具备以下功能: - 监听传入的网络数据包。 -- 根据数据包的源 IP 和端口计算哈希值,从而将流量分配到多个后端服务器。 -- 根据计算的哈希值将数据包转发到相应的后端服务器。 +- 根据数据包的源IP和端口计算哈希值,从而将流量分发到多个后端服务器。 +- 根据计算出的哈希值将数据包转发到相应的后端服务器。 -我们将保持设计简单但功能强大,展示如何利用 eBPF 的能力来创建一个轻量级的负载均衡解决方案。 +我们将保持设计简单但强大,向您展示如何利用eBPF的能力来创建一个轻量级的负载均衡解决方案。 ## kernel eBPF code diff --git a/src/42-xdp-loadbalancer/README_en.md b/src/42-xdp-loadbalancer/README_en.md index 3121c2c6..c792e8f7 100644 --- a/src/42-xdp-loadbalancer/README_en.md +++ b/src/42-xdp-loadbalancer/README_en.md @@ -7,7 +7,7 @@ In this tutorial, we will guide you through the process of implementing a simple `XDP` (eXpress Data Path) is a fast, in-kernel networking framework in Linux that allows packet processing at the earliest point in the network stack, right in the network interface card (NIC). This enables ultra-low-latency and high-throughput packet handling, making XDP ideal for tasks like load balancing, DDoS protection, and traffic filtering. -### Key Features of XDP +Key Features of XDP 1. **Fast Packet Processing**: XDP handles packets directly at the NIC level, reducing latency and improving performance by avoiding the usual networking stack overhead. 2. **Efficient**: Because it processes packets before they reach the kernel, XDP minimizes CPU usage and handles high traffic loads without slowing down the system. @@ -15,7 +15,7 @@ In this tutorial, we will guide you through the process of implementing a simple 4. **Low CPU Overhead**: With support for zero-copy packet forwarding, XDP uses fewer system resources, making it perfect for handling high traffic with minimal CPU load. 5. **Simple Actions**: XDP programs return predefined actions like dropping, passing, or redirecting packets, providing control over how traffic is handled. -### Projects That Use XDP +Projects That Use XDP - `Cilium` is an open-source networking tool for cloud-native environments like Kubernetes. It uses XDP to efficiently handle packet filtering and load balancing, improving performance in high-traffic networks. - `Katran`, developed by Facebook, is a load balancer that uses XDP to handle millions of connections with low CPU usage. It distributes traffic efficiently across servers and is used internally at Facebook for large-scale networking. diff --git a/src/6-sigsnoop/README_en.md b/src/6-sigsnoop/README_en.md index cffe5efc..7af9ca57 100755 --- a/src/6-sigsnoop/README_en.md +++ b/src/6-sigsnoop/README_en.md @@ -87,8 +87,9 @@ int kill_exit(struct trace_event_raw_sys_exit *ctx) char LICENSE[] SEC("license") = "Dual BSD/GPL"; ``` -The above code defines an eBPF program for capturing system calls that send signals to processes, including kill, tkill, and tgkill. It captures the enter and exit events of system calls by using tracepoints, and executes specified probe functions such as `probe_entry` and `probe_exit` when these events occur.Instructions: Translate the following Chinese text to English -while maintaining the original formatting: "In the probe function, we use the bpf_map to store the captured event information, including the process ID of the sending signal, the process ID of the receiving signal, the signal value, and the name of the executable for the current task. When the system call exits, we retrieve the event information stored in the bpf_map and use bpf_printk to print the process ID, process name, sent signal, and return value of the system call. +The above code defines an eBPF program for capturing system calls that send signals to processes, including kill, tkill, and tgkill. It captures the enter and exit events of system calls by using tracepoints, and executes specified probe functions such as `probe_entry` and `probe_exit` when these events occur. + +In the probe function, we use the bpf_map to store the captured event information, including the process ID of the sending signal, the process ID of the receiving signal, the signal value, and the name of the executable for the current task. When the system call exits, we retrieve the event information stored in the bpf_map and use bpf_printk to print the process ID, process name, sent signal, and return value of the system call. Finally, we also need to use the SEC macro to define the probe and specify the name of the system call to be captured and the probe function to be executed. diff --git a/src/8-exitsnoop/README_en.md b/src/8-exitsnoop/README_en.md index 40daf8c3..9983cbe5 100644 --- a/src/8-exitsnoop/README_en.md +++ b/src/8-exitsnoop/README_en.md @@ -144,7 +144,7 @@ Run: ```console $ sudo ./ecli run package.json TIME PID PPID EXIT_CODE DURATION_NS COMM". -format: Return only the translated content, not including the original text.21:40:09 42050 42049 0 0 which +21:40:09 42050 42049 0 0 which 21:40:09 42049 3517 0 0 sh 21:40:09 42052 42051 0 0 ps 21:40:09 42051 3517 0 0 sh diff --git a/src/bcc-documents/kernel-versions_en.md b/src/bcc-documents/kernel-versions_en.md index d2691c63..956a3b33 100644 --- a/src/bcc-documents/kernel-versions_en.md +++ b/src/bcc-documents/kernel-versions_en.md @@ -9,6 +9,7 @@ Kernel version | Commit ## JIT compiling The list of supported architectures for your kernel can be retrieved with: + ```sh git grep HAVE_EBPF_JIT arch/ ``` @@ -34,6 +35,7 @@ LoongArch | 6.1 | [`5dc615520c4d`](https://github.com/ Several (but not all) of these *main features* translate to an eBPF program type. The list of such program types supported in your kernel can be found in file [`include/uapi/linux/bpf.h`](https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h): + ```sh git grep -W 'bpf_prog_type {' include/uapi/linux/bpf.h ``` @@ -43,7 +45,7 @@ Feature | Kernel version | Commit `AF_PACKET` (libpcap/tcpdump, `cls_bpf` classifier, netfilter's `xt_bpf`, team driver's load-balancing mode…) | 3.15 | [`bd4cf0ed331a`](https://github.com/torvalds/linux/commit/bd4cf0ed331a275e9bf5a49e6d0fd55dffc551b8) Kernel helpers | 3.15 | [`bd4cf0ed331a`](https://github.com/torvalds/linux/commit/bd4cf0ed331a275e9bf5a49e6d0fd55dffc551b8) `bpf()` syscall | 3.18 | [`99c55f7d47c0`](https://github.com/torvalds/linux/commit/99c55f7d47c0dc6fc64729f37bf435abf43f4c60) -Maps (_a.k.a._ Tables; details below) | 3.18 | [`99c55f7d47c0`](https://github.com/torvalds/linux/commit/99c55f7d47c0dc6fc64729f37bf435abf43f4c60) +Maps (*a.k.a.* Tables; details below) | 3.18 | [`99c55f7d47c0`](https://github.com/torvalds/linux/commit/99c55f7d47c0dc6fc64729f37bf435abf43f4c60) BPF attached to sockets | 3.19 | [`89aa075832b0`](https://github.com/torvalds/linux/commit/89aa075832b0da4402acebd698d0411dcc82d03e) BPF attached to `kprobes` | 4.1 | [`2541517c32be`](https://github.com/torvalds/linux/commit/2541517c32be2531e0da59dfd7efc1ce844644f5) `cls_bpf` / `act_bpf` for `tc` | 4.1 | [`e2e9b6541dd4`](https://github.com/torvalds/linux/commit/e2e9b6541dd4b31848079da80fe2253daaafb549) @@ -123,12 +125,13 @@ LSM | 5.7 | [`fc611f47f218`](https://github.com/torv lookup listening socket | 5.9 | [`e9ddbb7707ff`](https://github.com/torvalds/linux/commit/e9ddbb7707ff5891616240026062b8c1e29864ca) | BPF_PROG_TYPE_SK_LOOKUP Allow executing syscalls | 5.15 | [`79a7f8bdb159`](https://github.com/torvalds/linux/commit/79a7f8bdb159d9914b58740f3d31d602a6e4aca8) | BPF_PROG_TYPE_SYSCALL -## Maps (_a.k.a._ Tables, in BCC lingo) +## Maps (*a.k.a.* Tables, in BCC lingo) ### Map types The list of map types supported in your kernel can be found in file [`include/uapi/linux/bpf.h`](https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h): + ```sh git grep -W 'bpf_map_type {' include/uapi/linux/bpf.h ``` @@ -170,6 +173,7 @@ user ringbuf | 6.1 | [`583c1f420173`](https://github.com/tor Some (but not all) of these *API features* translate to a subcommand beginning with `BPF_MAP_`. The list of subcommands supported in your kernel can be found in file [`include/uapi/linux/bpf.h`](https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h): + ```sh git grep -W 'bpf_cmd {' include/uapi/linux/bpf.h ``` @@ -222,7 +226,7 @@ Generic XDP | 4.12 | [`b5cdae3291f7`](https://github.com/torvalds/linux/commit/b The list of helpers supported in your kernel can be found in file."[`include/uapi/linux/bpf.h`](https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h): ```sh -git grep ' FN(' include/uapi/linux/bpf.h +git grep ' FN(' include/uapi/linux/bpf.h ``` Alphabetical order @@ -463,7 +467,9 @@ Note: GPL-only BPF helpers require a GPL-compatible license. The current license Check the list of GPL-compatible licenses in your [kernel source code](https://github.com/torvalds/linux/blob/master/include/linux/license.h). ## Program Types + The list of program types and supported helper functions can be retrieved with: + ```sh git grep -W 'func_proto(enum bpf_func_id func_id' kernel/ net/ drivers/ ``` @@ -492,4 +498,4 @@ git grep -W 'func_proto(enum bpf_func_id func_id' kernel/ net/ drivers/ |Function Group| Functions| |------------------|-------| |Base functions| `BPF_FUNC_map_lookup_elem()`
`BPF_FUNC_map_update_elem()`
`BPF_FUNC_map_delete_elem()`
`BPF_FUNC_map_peek_elem()`
`BPF_FUNC_map_pop_elem()`
`BPF_FUNC_map_push_elem()`
`BPF_FUNC_get_prandom_u32()`
`BPF_FUNC_get_smp_processor_id()`
`BPF_FUNC_get_numa_node_id()`
`BPF_FUNC_tail_call()`
`BPF_FUNC_ktime_get_boot_ns()`
`BPF_FUNC_ktime_get_ns()`
`BPF_FUNC_trace_printk()`
`BPF_FUNC_spin_lock()`
`BPF_FUNC_spin_unlock()` ||`Tracing functions`|`BPF_FUNC_map_lookup_elem()`
`BPF_FUNC_map_update_elem()`
`BPF_FUNC_map_delete_elem()`
`BPF_FUNC_probe_read()`
`BPF_FUNC_ktime_get_boot_ns()`
`BPF_FUNC_ktime_get_ns()`
`BPF_FUNC_tail_call()`
`BPF_FUNC_get_current_pid_tgid()`
`BPF_FUNC_get_current_task()`
`BPF_FUNC_get_current_uid_gid()`
`BPF_FUNC_get_current_comm()`
`BPF_FUNC_trace_printk()`
`BPF_FUNC_get_smp_processor_id()`
`BPF_FUNC_get_numa_node_id()`
`BPF_FUNC_perf_event_read()`
`BPF_FUNC_probe_write_user()`
`BPF_FUNC_current_task_under_cgroup()`
`BPF_FUNC_get_prandom_u32()`
`BPF_FUNC_probe_read_str()`
`BPF_FUNC_get_current_cgroup_id()`
`BPF_FUNC_send_signal()`
`BPF_FUNC_probe_read_kernel()`
`BPF_FUNC_probe_read_kernel_str()`
`BPF_FUNC_probe_read_user()`
`BPF_FUNC_probe_read_user_str()`
`BPF_FUNC_send_signal_thread()`
`BPF_FUNC_get_ns_current_pid_tgid()`
`BPF_FUNC_xdp_output()`
`BPF_FUNC_get_task_stack()`| -|`LWT functions`| `BPF_FUNC_skb_load_bytes()`
`BPF_FUNC_skb_pull_data()`
`BPF_FUNC_csum_diff()`
`BPF_FUNC_get_cgroup_classid()`
`BPF_FUNC_get_route_realm()`
`BPF_FUNC_get_hash_recalc()`
`BPF_FUNC_perf_event_output()`
`BPF_FUNC_get_smp_processor_id()`
`BPF_FUNC_skb_under_cgroup()`| \ No newline at end of file +|`LWT functions`| `BPF_FUNC_skb_load_bytes()`
`BPF_FUNC_skb_pull_data()`
`BPF_FUNC_csum_diff()`
`BPF_FUNC_get_cgroup_classid()`
`BPF_FUNC_get_route_realm()`
`BPF_FUNC_get_hash_recalc()`
`BPF_FUNC_perf_event_output()`
`BPF_FUNC_get_smp_processor_id()`
`BPF_FUNC_skb_under_cgroup()`|