#linux-kernel #packets #xdp #io #path #process #networking

packetvisor

Packetvisor 是基于 Rust 语言的原始数据包 I/O 框架。它可以通过 Linux 内核的 eXpress Data Path(XDP) 处理数据包的速度远快于标准套接字。

2 个稳定版本

1.0.1 2024 年 4 月 8 日
1.0.0 2024 年 4 月 4 日

#250 in Unix APIs

26 monthly downloads

GPL-3.0+

4MB
101K SLoC

C 75K SLoC // 0.1% comments Rust 21K SLoC // 0.0% comments Shell 4K SLoC // 0.1% comments Python 382 SLoC // 0.1% comments BASH 135 SLoC // 0.1% comments Gherkin (Cucumber) 133 SLoC // 0.1% comments RPM Specfile 126 SLoC // 0.0% comments Emacs Lisp 52 SLoC // 0.1% comments

Packetvisor(PV)

系统依赖

  • clang 版本 >= 11
  • llvm 版本 >= 11

bpftool & XDP-tools (submodules)

PV 使用 libxdpXDP-tools 中。

构建库

您可以使用 cargo build -r 命令来构建 PV 库,库文件将位于 target/release/

入门指南

本指南将引导您通过使用 PV 库编写的示例源代码进行编译和使用的过程。
以下说明将基于 Echo 示例。

请先安装依赖包。

# Install build dependencies
$ sudo apt-get install llvm clang libelf-dev gcc-multilib libpcap-dev m4 make curl

# Install Rust
$ curl https://sh.rustup.rs -sSf | sh
$ source "$HOME/.cargo/env"

然后编译示例源代码。

# Compile all examples.
$ cargo build -r --examples

# Compile the specific example.
$ cargo build -r --example echo

编译后的示例二进制文件位于 target/release/examples/ 目录。

在运行 Echo 示例之前,您需要创建一个 Linux 网络命名空间。
我们为此提供了两个脚本

  • examples/set_veth.sh : 创建两个 Linux 网络命名空间。
  • examples/unset_veth.sh : 删除之前创建的两个 Linux 网络命名空间。

运行 examples/set_veth.sh 脚本在主机内部创建了两个命名空间(test1 和 test2)。

# Host veth0 is connected to veth1 in the test1 namespace.
# Host veth2 is connected to veth3 in the test2 namespace.

+-----------+          +-----------+
|   test1   |          |   test2   |
+--[veth1]--+          +--[veth3]--+
      |                      |
+--[veth0]----------------[veth2]--+
|               Host               |
+----------------------------------+

在 Echo 示例测试中只使用了 test1 命名空间。

现在,打开两个终端。

  • 在一个终端(TERM1)中,在 test1 命名空间的 veth1 接口上运行 Echo。
  • 在另一个终端(TERM2)中,从主机发送 ARP、ICMP 和 UDP 数据包到 test1。

总结来说,主机和 test1 之间执行 ARP、ICMP 和 UDP Echo(Ping-Pong)。

请在 TERM1 和 TERM2 上执行以下命令。

# Working directory on TERM1 is packetvisor/.
(TERM1) $ sudo ip netns exec test1 /bin/bash
(TERM1) $ ./target/release/examples/echo veth1
-------------------------------------------------
(TERM2) $ sudo apt-get install arping 2ping

# ARP echo test
(TERM2) $ sudo arping 10.0.0.5
# ICMP echo test
(TERM2) $ ping 10.0.0.5
# UDP echo test
(TERM2) $ 2ping 10.0.0.5 --port 7

现在您可以在 TERM1 的日志中看到 ARP、ICMP 和 UDP(端口 7)数据包在 test1 命名空间中被回显了!


关于 XSK(XDP Socket)的描述

XSK 的元素

  • TX 环:包含要发送的包的描述符
  • RX 环:包含已接收的包的描述符
  • 完成环(= CQ,完成队列):用于保存成功发送的数据包块
  • 填充环(= FQ,填充队列):用于分配接收数据包的块

RX 端过程

用户应在接收数据包并放入之前,预先分配空块或准备使用的块。以下步骤描述了如何通过 XSK 接收数据包。

  1. 用户通过 xsk_ring_prod__reserve() 通知内核在 FQ 中预留多少个槽位,然后该函数将返回预留槽位的数量和 index 值,即预留槽位在环中的第一个索引。
  2. 用户将 index 放入 xsk_ring_prod__fill_addr() 作为参数,函数将根据 index 返回槽位的指针。然后,用户通过迭代将块地址放入指针,就像 *xsk_ring_prod__fill_addr() = chunk_addr 这样,以与预留槽位的数量相同的方式进行分配。
  3. 在分配块之后,xsk_ring_prod__submit() 将通知内核有多少块被分配到 FQ 中的槽位。
  4. 当接收到一些数据包时,内核将根据 FQ 的分配信息将数据包复制到块中,并在 RX Ring 中创建数据包的描述符。
  5. 用户可以通过 xsk_ring_cons__peek() 了解接收了多少个数据包。该函数将返回接收到的数据包数量和 index 值,即接收到的槽位在环中的第一个索引。
  6. 通过 xsk_ring_cons__rx_desc(),用户可以通过将 index 放入函数作为参数来获取接收到的数据包的信息。
  7. 在获取所有接收到的数据包信息之后,用户应通过 xsk_ring_cons__release() 通知内核在 RX Ring 中消耗了多少个数据包。这样,内核将移动 RX 环的尾部,以便为未来数据包的描述符保存空间。

TX 端过程

与 RX 端过程相反,在通过 XSK 发送数据包之前,CQ 应有足够的空槽位,因为 CQ 会在数据包成功发送后被分配。如果在 CQ 中没有可分配的槽位,内核可能无法发送数据包。用户可以通过 CQ 了解哪些数据包已成功发送。以下步骤描述了如何通过 XSK 发送数据包。

  1. 要发送的数据包已在块中准备好。
  2. 用户应通过xsk_ring_prod__reserve()函数预留TX Ring的槽位。该函数将返回预留的槽位数和索引,其中索引表示预留槽位的第一索引。
  3. 当用户将index作为参数传递给xsk_ring_prod__tx_desc()函数时,该函数将返回与索引对应的描述符。然后,用户将待发送数据包的有效载荷地址和有效载荷长度放入描述符中。
  4. 所有描述符关于数据包的信息完成后,用户应通过xsk_ring_prod__submit()函数通知内核将发送多少个数据包。
  5. 单独调用xsk_ring_prod__submit()实际上不会发送任何数据包。调用sendto()将使内核发送这些数据包。
  6. 如果数据包发送成功,内核将在CQ中为已发送的数据包分配块。
  7. 用户可以通过将CQ作为参数传递给xsk_ring_cons__peek()函数,通过CQ了解发送了多少个数据包。该函数将返回发送的数据包数量和索引。索引表示CQ中第一个槽位的索引。
  8. xsk_ring_cons__comp_addr()将返回在CQ中分配的块地址。然后,用户可以在下次重用该块。
  9. 最后,用户应通过xsk_ring_cons__release()函数通知内核已消耗CQ中的多少个槽位。这样内核就会移动CQtail,以便将下一个数据包的块保存到环中。

许可证

本软件根据GPLv3或任何后续版本分发。

如果您需要除了GPLv3之外的其他许可证用于专有用途或专业支持,请通过contact at tsnlab dot com联系我们。

待办事项

制作一个安装程序,包括更改应用程序功能选项。使用以下命令:sudo setcap CAP_SYS_ADMIN,CAP_NET_ADMIN,CAP_NET_RAW,CAP_DAC_OVERRIDE+ep target/release/pv3_rust

依赖关系

~4.5–7.5MB
~142K SLoC