混部环境指的是当前服务器不是 XDP 程序独占的,部署有其它的网络服务。

如果服务器使用的是 Intel 网卡、而且 XDP 程序采用 Native 模式挂载到网卡上,那么在挂载和卸载 XDP 程序时,会导致网络中断,这会影响到其它网络服务。

本文介绍了一种无损升级 XDP 程序的思路,能够解决这个问题。

XDP 部署方式

XDP 程序采用 Native 模式挂载到网卡上,并且 pin 到指定 bpffs 路径上。

将 XDP 程序 pin 到 bpffs 是为了预防用户态程序异常退出导致 XDP 程序被卸载;意即,即使用户态程序异常退出,XDP 程序仍然能够继续运行。

而在项目实战中,会将所有 bpf 对象都 pin 到 bpffs 路径上,这样能够方便管理所有 bpf 对象。

不过,这种部署方式有一个缺点:在升级 XDP 程序时,如果 bpf map 的 key/value size 发生变化,那么就需要将 XDP 程序卸载,将所有 bpf 对象 unpin 掉。

所以,当遇到混部环境时,这种部署方式就会导致网络中断,影响到其它网络服务。

无损升级 XDP 程序的思路

能够无损升级 Native 模式的 XDP 程序的前提,是网卡驱动支持原子更新 XDP 程序。

支持原子更新 XDP 程序的网卡驱动有:mlx5、ixgbe、i40e。ice 驱动还没支持。

所以,只要网卡驱动支持原子更新 XDP 程序,就能够无损升级 XDP 程序。

思路:

  1. 将 bpf 对象所在的目录 mv 到新的目录;
  2. 将 XDP link 对象克隆到原有的路径下;
  3. 在原有路径下,重新生成所有 bpf 对象。
  4. 使用克隆的 XDP link 去更新 XDP 程序。
  5. 删除新的目录。

不过,其中第 2 步是如何克隆 XDP link 对象呢?

如果直接使用 cp 命令,会得到错误:cp: cannot open 'xdp' for reading: Input/output error

这是因为 bpffs 文件系统不支持 cp 命令。

不过,却支持 mv 命令,因为 mv 命令只是修改了文件的路径,而没有修改文件的 inode。

如何绕过这个错误呢?

克隆 XDP link 对象的思路是:LoadPinnedLink() 然后 NewFromID()

因此,弄了个小工具:bpfbakbpfbak 能够克隆 pinned bpf 对象,然后 pin 到另一个路径上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ ./bpfbak -h
bpfbak is a tool to backup eBPF objects

Usage:
  bpfbak [flags]

Flags:
      --auto-mount           automatically mount bpffs at the destination directory or --mount-bpffs
  -d, --dst string           destination filepath to backup the bpf object
  -h, --help                 help for bpfbak
      --mount-bpffs string   path to the directory where bpffs is mounted
  -s, --src string           source bpf object to be backed up
      --unpin-src            unpin the source bpf object after backing up

效果展示:

1
2
3
4
5
6
7
$ ./bpfbak -s ./test-bpffs-dir/traceroute/xdp -d ./test-bpffs-dir/bak/xdp
$ bpftool l s p ./test-bpffs-dir/bak/xdp
6: xdp  prog 67
    ifindex ens33(2)
$ bpftool l s p ./test-bpffs-dir/traceroute/xdp
6: xdp  prog 67
    ifindex ens33(2)

总结

本文介绍了一种无损升级 XDP 程序的思路,能够解决在混部环境下升级 XDP 程序导致网络中断的问题。

由此需求,衍生了一个小工具:bpfbak