eBPF 地图:如何从命令行使用 bpftool 进行更新

Anu*_*lly 2 kernel c

我正在使用tc将我的eBPF(使用 clang 编译的 C 代码)附加到网络。

我正在使用eBPF Maps来存储一些数据。

具体来说,我用于从 BPF 程序内部bpf_map_update_elem更新eBPF 映射,但我还想程序外部更改映射的内容。

地图结构

struct rt_val {
    int ifaceno;
    int macaddr[6];
};
union key_4 {
    __u32 b32[2];
    __u8 b8[8];
};
struct bpf_map_def SEC("maps") lpm_map_fwd = {
    .type = BPF_MAP_TYPE_LPM_TRIE,
    .key_size = 8,
    .value_size = sizeof(struct rt_val),
    .max_entries = 50,
    .map_flags = BPF_F_NO_PREALLOC,
};
Run Code Online (Sandbox Code Playgroud)

地图更新和查找都很好。

但我想从程序执行外部动态更改 eBPF Map 的内容。

任何有关相同的意见/建议将不胜感激!

资源:

系统细节:

  • uname -r:4.15.0-47-通用
  • OS:Ubuntu 18

Qeo*_*ole 5

您已经找到了从用户空间更新 eBPF 映射所需的所有工具。

bpf()

系统bpf(cmd, attr, size)调用用于执行更新。作为第一个参数传递cmd的指示您要执行什么类型的操作:在您的情况下,这将是BPF_MAP_UPDATE_ELEM. 然后您链接的手册页解释了如何构建attr:在您的情况下(用于地图更新),它应该是:

struct {    /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY commands */
        __u32         map_fd;
        __aligned_u64 key;
        union {
                __aligned_u64 value;
                /* [...] */
        };
        __u64         flags;
};
Run Code Online (Sandbox Code Playgroud)

这意味着您应该构建一个union bpf_attr并将文件描述符传递给映射、要更新的条目的键、该键的新值以及可能的一些标志。

可以获得地图的文件描述符:

  • 从BPF虚拟文件系统下的路径,如果地图已经预先固定,
  • 从地图的 id 中,bpf()使用以下命令再次调用系统调用BPF_MAP_GET_FD_BY_ID
  • (或者作为对创建地图的调用的返回值bpf(),但在您使用 tc 加载程序的情况下则不然)。

请注意,libbpf(随内核一起提供在 GitHub 上镜像)提供了bpf()系统调用的包装器,可以使事情变得更容易。

bpf工具

实际上,您不需要重新实现所有这些。正如您在标题中提到的,bpftool 允许您从命令行更新地图,而无需重新实现整个过程。

获取 bpftool

编辑:在 Ubuntu 19.10 (eoan) 上,bpftool 打包为linux-tools-common软件包的一部分。请阅读以下有关旧版本的说明。

截至撰写本文时,bpftool 尚未针对Debian/Ubuntu 进行打包,这意味着您必须从源代码构建它。它是随内核一起提供的,因此下载需要一些时间,但构建实际上非常简单:

struct {    /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY commands */
        __u32         map_fd;
        __aligned_u64 key;
        union {
                __aligned_u64 value;
                /* [...] */
        };
        __u64         flags;
};
Run Code Online (Sandbox Code Playgroud)

或者,此页面上打包有一个非官方版本(免责声明:来自我的公司)。打包的二进制文件是静态构建的,应该可以在所有 x86_64 Linux 机器上运行。

更新地图

之后,您可以使用它列出系统上当前存在的地图:

 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 $ cd linux
 $ cd tools/bpf/bpftool
 $ make
(# make install)
(# make doc doc-install)
Run Code Online (Sandbox Code Playgroud)

每个地图的 ID 将显示在左侧。找到与要更新的地图相关的 ID(或者如果地图已固定,请记下其路径,随选项一起显示-f),然后使用以下选项之一:

# bpftool -f map show
Run Code Online (Sandbox Code Playgroud)

例如:

# bpftool map update id <id> key <key> value <new_value>
# bpftool map update pinned <path> key <key> value <new_value>
Run Code Online (Sandbox Code Playgroud)

(注意:我会使用 s 数组__u8而不是ints 来在您的 中存储 MAC 地址struct rt_val。您的macaddr可能会占用 24 个字节。)

如果您不确定值如何存储在地图中,请立即将其转储到控制台中:

# bpftool map update id 17 key 0x1 0 0 0 0 0 0 0 value 0x1 0x2 0x3...
Run Code Online (Sandbox Code Playgroud)

更多资源

我不知道任何现有的 bpftool 教程,但您可以在该工具的手册页中找到所有详细信息。我还在Twitter 上写了一些有关它的提示。