本文地址:https://www.ebpf.top/post/ubuntu_2104_bpf_env

1. 系统安装

1.1 Vagrant

Vagrant 是一款用于构建及配置虚拟开发环境的软件,基于 Ruby,主要以命令行的方式运行。Vagrant 由 HashiCorp 官方出品,相信提到大名鼎鼎的 HashiCorp 公司,大家还能够联想到著名的安全密码存储 Valut、服务注册发现 Consul、大规模调度系统 Normad 等等。

Vagrant 可基于官方提供的各种虚拟机打包文件(比如 VirtualBox 的 Box 文件)快速搭建各种系统的验证环境,也可以灵活通过配置式的文件管理多 VM 环境,同时具有平台适配性,是非常好的 VM 管理工具。但其自身并不提供虚拟化环境,需要配合 VirtualBox、WMware、KVM 等虚拟化技术,1.6 版本底层也支持使用容器,可以将容器替代完整的虚拟系统。

Vagrant 的架构使用 "Provisioners" 和 "Providers" 作为开发环境的构建模块。

|--vagrant
|--Providers 如:VirtualBox、Hyper-V、Docker、VMware、AWS
|--Boxex 如:Centos7。与镜像类似
|--Provisioners 如:'yum intall -y python' 等自定义自动化脚本

Vagrant 作为最外层的虚拟软件,目的是帮助开发者更容易地与 Providers 互动。Vagrantfile 记录 Providers 和 Provisioners 的相关信息。

Providers 作为服务,帮助 vagrant 使用 Boxes 建立和创建虚拟环境。Vagrant 提供的内嵌的 Provider 有 VirtualBox、Hyper-V、Docker、VMware 等。

在 Mac 系统中如果使用 Brew 管理包,则可以通过 brew 命令直接安装。其他系统的安装方式可参考 下载 Vagrant,查看详情。

$ brew install vagrant

在安装 vagrant 成功后,我们还需要安装底层的虚拟化软件(即上述架构中的 Providers)才能正常工作,这里我们使用 VirtualBox。

1.2 VirtualBox

Oracle VirtualBox 是德国公司 InnoTek 出品的虚拟机软件,现在由 Oracle 公司管理和发行,适用于多平台系统。用户可以在 VirtualBox 上安装并且运行 Solaris/Windows/Linux 等系统作为客户端操作系统。

在 Mac 系统上可以通过下载 dmg 文件进行安装。其他系统的安装参见 Oracle VM VirtualBox 基础包

在 Vagrant 和 VirtualBox 安装完成后,我们可以使用以下命令快速搭建一个 Ubuntu 的 VM:

$ vagrant init ubuntu/hirsute64
$ vagrant up

在启动成功后,我们可以通过 vagrant ssh 直接登录到 VM 系统中。

1.3 系统环境搭建

2021 年 4 月 22 号,Ubuntu 发布了 21.04 Hirsute Hippo 版本 [1],内核采用 5.11.0 版本。这里选择最新的 Ubuntu 发行版本,主要考虑 BPF 技术演进较快,新功能基本都需要高版本内核,采用最新发行的 Ubuntu 发行版本,方便后续的 BPF 功能学习和内核版本升级。更多 Ubuntu 版本发布的详情可参见官方 Wiki

这里我们使用 Vagrant 虚拟机的方式快速搭建环境,Hirsute Box 镜像 可在官方提供的 Vagrant Boxs 市场 中查询,ubuntu/hirsute64 Box 的镜像大小为 600M 左右。

$ vagrant init ubuntu/hirsute64
$ vagrant up # 如果 box 有更新,可以使用 update 子命令更新
#$ vagrant box update

如果从国外下载镜像过慢,可以通过其他方式下载 Box 文件,使用命令: vagrant box add <name> <boxpath> 然后导入到本地后再启动上述命令。为方便大家快速下载我已经上传了一份到 百度网盘,提取码【bgfg】。

$ vagrant box add ubuntu/hirsute64 ~/Downloads/ubuntu_2104.box
$ vagrant box list
ubuntu/hirsute64 (virtualbox, 20210923.0.0)

另外,我们也可以使用以下命令将正在运行的 VM 重新打包成 Box 文件:

$ vagrant package --output hirsute64_my.box

如果上述安装顺利,我们可以通过 ssh 的方式登录到新创建的 VM 机器中。

$ vagrant ssh
Welcome to Ubuntu 21.04 (GNU/Linux 5.11.0-36-generic x86_64) * Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage System information as of Sat Sep 25 11:22:52 UTC 2021 System load: 0.0 Processes: 105
Usage of /: 3.4% of 38.71GB Users logged in: 0
Memory usage: 18% IPv4 address for enp0s3: 10.0.2.15
Swap usage: 0% * Super-optimized for small spaces - read how we shrank the memory
footprint of MicroK8s to make it the smallest full K8s around. https://ubuntu.com/blog/microk8s-memory-optimisation 0 updates can be applied immediately. Last login: Sat Sep 25 08:13:09 2021 from 10.0.2.2
vagrant@ubuntu-hirsute:~$ uname -a
Linux ubuntu-hirsute 5.11.0-36-generic #40-Ubuntu SMP Fri Sep 17 18:15:22 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

通过检查 CONFIG_DEBUG_INFO_BTF 内核编译选项确认系统是否已经支持 BTF 能力,这是 BPF CO-RE (Compile Once – Run Everywhere) 能力的基础。

$ grep CONFIG_DEBUG_INFO_BTF /boot/config-5.11.0-36-generic
CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=y

至此,我们的 BPF VM 环境已基本准备完成。

2. BPF 程序编译

对于我们编译 BPF 程序而言需要系统已经安装了必备的 linux-headers 包。在 Ubuntu/Debian/Arch/Manjaro 发行版系统中需要安装 linux-headers 包,而在 CentOS/Fedora 发行版系统中需要安装 kernel-headers 和 kernel-devel 两个包。

首先我们在 VM 中安装 linux-headers 包:

$ sudo apt update
$ sudo apt install linux-headers-$(uname -r)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
linux-headers-5.11.0-36-generic is already the newest version (5.11.0-36.40).

如果是通过内核升级版本的场景,务必确认 linux-headers 版本与当前运行的内核版本一致。

为了能够编译 BPF 程序,我们还需要安装编译所依赖的工具包:

$ sudo apt install -y bison flex build-essential git cmake make libelf-dev  clang llvm strace tar libfl-dev libssl-dev libedit-dev zlib1g-dev  python  python3-distutils

$ clang --version
Ubuntu clang version 12.0.0-3ubuntu1~21.04.2
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin $ llc --version
LLVM (http://llvm.org/):
LLVM version 12.0.0 Optimized build.
Default target: x86_64-pc-linux-gnu
Host CPU: haswell Registered Targets:
...
bpf - BPF (host endian)
bpfeb - BPF (big endian)
bpfel - BPF (little endian)
...

通过上述 clang/llvm 版本信息查看,我们可以知道在 Ubuntu 21.04 版本中,安装的为 12.0 的版本,这可以满足我们对于 CO-RE 能力的要求(>= 9.0 版本)。

我们使用 libbpf-bootstrap 来进行编译验证,同时使用 --recursive 参数将 libbpf-bootstrap 仓库中的依赖子模块 libbpf 同时下载到本地。

$ git clone --recursive https://github.com/libbpf/libbpf-bootstrap.git
Cloning into 'libbpf-bootstrap'...
remote: Enumerating objects: 260, done.
remote: Counting objects: 100% (172/172), done.
remote: Compressing objects: 100% (96/96), done.
remote: Total 260 (delta 74), reused 149 (delta 64), pack-reused 88
Receiving objects: 100% (260/260), 1.65 MiB | 280.00 KiB/s, done.
Resolving deltas: 100% (118/118), done.
Submodule 'libbpf' (https://github.com/libbpf/libbpf.git) registered for path 'libbpf' # 子模块 libbpf 下载
Cloning into '/home/vagrant/libbpf-bootstrap/libbpf'...
remote: Enumerating objects: 6174, done.
remote: Counting objects: 100% (1222/1222), done.
remote: Compressing objects: 100% (336/336), done.
remote: Total 6174 (delta 965), reused 942 (delta 866), pack-reused 4952
Receiving objects: 100% (6174/6174), 3.59 MiB | 547.00 KiB/s, done.
Resolving deltas: 100% (4087/4087), done.
Submodule path 'libbpf': checked out '8bf016110e683df2727a22ed90c9c9860c966544' $ cd libbpf-bootstrap/examples/c
~/libbpf-bootstrap/examples/c$ make

如没有错误提示,且通过下述的 ls 命令可查看到对应的二进制文件,则表明编译成功。

$ ls -hl
-rwxrwxr-x 1 vagrant vagrant 1.4M Sep 25 13:30 bootstrap
-rwxrwxr-x 1 vagrant vagrant 1.3M Sep 25 13:30 fentry
-rwxrwxr-x 1 vagrant vagrant 1.3M Sep 25 13:30 kprobe
-rwxrwxr-x 1 vagrant vagrant 1.3M Sep 25 13:30 minimal
-rwxrwxr-x 1 vagrant vagrant 1.3M Sep 25 13:30 uprobe # 通过 bootstrap 程序运行验证
~/libbpf-bootstrap/examples/c$ sudo ./bootstrap
TIME EVENT COMM PID PPID FILENAME/EXIT CODE
13:41:14 EXEC ls 16473 7633 /usr/bin/ls
13:41:14 EXIT ls 16473 7633 [0] (1ms) # 用户空间程序与内核中的 BPF 通信的唯一入口是 bpf() 系统调用,可以通过 strace 查看整个交互流程
~/libbpf-bootstrap/examples/c$ sudo strace -e bpf ./bootstrap
bpf(BPF_PROG_LOAD, {prog_type=BPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=2, insns=0x7fffd2d6e3c0, license="GPL", log_level=0, log_size=0, log_buf=NULL, kern_version=KERNEL_VERSION(0, 0, 0), prog_flags=0, prog_name="", prog_ifindex=0, expected_attach_type=BPF_CGROUP_INET_INGRESS, prog_btf_fd=0, func_info_rec_size=0, func_info=NULL, func_info_cnt=0, line_info_rec_size=0, line_info=NULL, line_info_cnt=0, attach_btf_id=0, attach_prog_fd=0}, 128) = 3
bpf(BPF_BTF_LOAD, {btf="\237\353\1\0\30\0\0\0\0\0\0\0\20\0\0\0\20\0\0\0\5\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=NULL, btf_size=45, btf_log_size=0, btf_log_level=0}, 128) = 3
...

至此我们可以将 VM 导出为 Box 文件以便作为后续的基础,需要在 VM Vagrant 文件所在的目录操作运行,导出过程会自动关闭 VM 虚拟机。

ubuntu_21_04$ vagrant package --output ubuntu_21_04_bpf.box
==> default: Attempting graceful shutdown of VM...
==> default: Clearing any previously set forwarded ports...
==> default: Exporting VM...

ubuntu_21_04_bpf.box 文件已经上传 百度云盘,提取码【if2j】,文件大小 1.1G。

3. 内核代码安装和 sample/bpf 模块编译

安装 Ubuntu 21.04 源代码,并解压源代码:

$ sudo apt-cache search linux-source
linux-source - Linux kernel source with Ubuntu patches
linux-source-5.11.0 - Linux kernel source for version 5.11.0 with Ubuntu patches $ sudo apt install linux-source-5.11.0
$ sudo cd /usr/src
$ sudo tar -jxvf linux-source-5.11.0.tar.bz2
$ sudo cd /usr/src/linux-source-5.11.0

源码编译 sample/bpf 模块:( 为方便编译,统一切换成 root 用户 )

# cp -v /boot/config-$(uname -r) .config
# make oldconfig && make prepare
# make headers_install
# apt-get install libcap-dev // 解决 sys/capability.h: No such file or directory
# make M=samples/bpf // 编译最后,可能会报部分 WARNING,可以忽略
samples/bpf/Makefile:231: WARNING: Detected possible issues with include path.
samples/bpf/Makefile:232: WARNING: Please install kernel headers locally (make headers_install).
WARNING: Symbol version dump "Module.symvers" is missing.
Modules may not have dependencies or modversions.
MODPOST samples/bpf/Module.symvers
WARNING: modpost: Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped. # ls -hl samples/bpf/ // 查看是否生产需要的样例代码,如果生成了可执行文件,这表明编译成功 # ./tracex1
libbpf: elf: skipping unrecognized data section(4) .rodata.str1.1
libbpf: elf: skipping unrecognized data section(17) .eh_frame
libbpf: elf: skipping relo section(18) .rel.eh_frame for section(17) .eh_frame
<...>-36521 [000] d.s1 2056.935795: bpf_trace_printk: skb 00000000a32b8f51 len 84
<...>-36521 [000] d.s1 2056.935817: bpf_trace_printk: skb 0000000094918e19 len 84

4. 附加 BPF 样例编译

在 samples/bpf 目录包含接近 60 个相关的程序,给与我们学习提供了便利,同时也提供了一个组织编译的 Makefile 框架。如果我们用 C 语言编写的 BPF 程序编译可以直接在该目录提供的环境中进行编译。

如果是需要单独编译的场景,也可以参考 BCC 仓库中的 libbpf-tools 下的样例。

samples/bpf 下的程序一般组成方式是 xyz_user.c 和 xyz_kern.c:

  • xyz_user.c 为用户空间的程序用于设置 BPF 程序的相关配置、加载 BPF 程序至内核、设置 BPF 程序中的 map 值和读取 BPF 程序运行过程中发送至用户空间的消息等。目前 xyz_user.c 与 xyz_kern.c 程序在交互实现都是基于 bpf() 系统调用完成的。直接使用 bpf() 系统调用涉及的参数和细节比较多,使用门槛较高,因此为了方便用户空间程序更加易用,内核提供了 libbpf 库封装了对于 bpf() 系统调用的细节。
  • xyz_kern.c 为 BPF 程序代码,通过 clang 编译成字节码加载至内核中,在对应事件触发的时候运行,可以接受用户空间程序发送的各种数据,并将运行时产生的数据发送至用户空间程序。

完整的样例代码参见 hello_world_bpf_ex

hello_user.c

#include <stdio.h>
#include <unistd.h>
#include <bpf/libbpf.h>
#include "trace_helpers.h" int main(int ac, char **argv)
{
struct bpf_link *link = NULL;
struct bpf_program *prog;
struct bpf_object *obj;
char filename[256]; snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failed\n");
return 0;
} prog = bpf_object__find_program_by_name(obj, "bpf_hello");
if (!prog) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
} /* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failed\n");
goto cleanup;
} link = bpf_program__attach(prog);
if (libbpf_get_error(link)) {
fprintf(stderr, "ERROR: bpf_program__attach failed\n");
link = NULL;
goto cleanup;
} read_trace_pipe(); cleanup:
bpf_link__destroy(link);
bpf_object__close(obj);
return 0;
}

hello_kern.c

#include <uapi/linux/bpf.h>
#include <linux/version.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog1(struct pt_regs *ctx)
{
char fmt[] = "Hello %s !\n";
char comm[16];
bpf_get_current_comm(&comm, sizeof(comm));
bpf_trace_printk(fmt, sizeof(fmt), comm); return 0;
} char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;

Makefile 文件修改

# diff -u Makefile.old Makefile
--- Makefile.old 2021-09-26 03:16:16.883348130 +0000
+++ Makefile 2021-09-26 03:20:46.732277872 +0000
@@ -55,6 +55,7 @@
tprogs-y += xdp_sample_pkts
tprogs-y += ibumad
tprogs-y += hbm
+tprogs-y += hello # Libbpf dependencies
LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a
@@ -113,6 +114,7 @@
xdp_sample_pkts-objs := xdp_sample_pkts_user.o
ibumad-objs := ibumad_user.o
hbm-objs := hbm.o $(CGROUP_HELPERS)
+hello-objs := hello_user.o $(TRACE_HELPERS) # Tell kbuild to always build the programs
always-y := $(tprogs-y)
@@ -174,6 +176,7 @@
always-y += hbm_out_kern.o
always-y += hbm_edt_kern.o
always-y += xdpsock_kern.o
+always-y += hello_kern.o ifeq ($(ARCH), arm)
# Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux

在当前目录重新运行 make 命令即可。编译完成后,启动命令后在其他窗口执行 ls -hl ,显示效果如下:

$ sudo ./hello
<...>-46054 [000] d... 7627.000940: bpf_trace_printk: Hello bash ! $ ldd hello
linux-vdso.so.1 (0x00007ffd71306000)
libelf.so.1 => /lib/x86_64-linux-gnu/libelf.so.1 (0x00007f99d67fd000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f99d67e1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f99d65f5000)
/lib64/ld-linux-x86-64.so.2 (0x00007f99d6cf1000)

5. 系统内核升级

5.1 Ubuntu 内核官方包升级

mainline 为 Ubuntu 提供可视化的内核升级工具,早期版本为 ukuu 。该工具支持的特性如下:

  • 从 Ubuntu Mainline PPA 中获取可用的内核列表
  • 当有新的内核更新时,可以选择观察并显示通知
  • 自动下载和安装软件包
  • 方便地显示可用和已安装的内核
  • 从界面上安装 / 卸载内核
  • 对于每个内核,相关的软件包(头文件和模块)会同时安装或卸载

使用 Vagrant 快速搭建一个 VM 环境:

$ vagrant box add  ubuntu/hirsute64-ukuu ~/Downloads/ubuntu_21_04_bpf.box
$ mkdir ubuntu_21_04_ukuu && cd ubuntu_21_04_ukuu
$ vagrant init ubuntu/hirsute64-ukuu
$ vagrant up

可以通过以下命令自动安装:

$ sudo add-apt-repository ppa:cappelikan/ppa
$ sudo apt update
$ sudo apt install mainline $ mainline -h
mainline 1.0.15
Distribution: Ubuntu 21.04
Architecture: amd64
Running kernel: 5.11.0-36-generic mainline 1.0.15 - Ubuntu Mainline Kernel Installer

list 子命令会显示出来当前系统支持升级的或者已经安装的系统:

$ mainline --list
mainline 1.0.15
Distribution: Ubuntu 21.04
Architecture: amd64
Running kernel: 5.11.0-36-generic
Fetching index from kernel.ubuntu.com...
OK Fetching index... ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100 % ----------------------------------------------------------------------
Found installed: 5.11.0.36.38
Found installed: 5.11.0-36.40
----------------------------------------------------------------------
---------------------------------------------------------------------- ======================================================================
Available Kernels
======================================================================
5.14.8
5.14.7 $ sudo mainline --install 5.14.7 # 则会启动对应的内核安装
mainline 1.0.15
Distribution: Ubuntu 21.04
Architecture: amd64
Running kernel: 5.11.0-36-generic
Fetching index from kernel.ubuntu.com...
OK Fetching index... ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100 % ----------------------------------------------------------------------
Found installed: 5.11.0.36.38
Found installed: 5.11.0-36.40
----------------------------------------------------------------------
---------------------------------------------------------------------- Downloading: 'amd64/linux-headers-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb'...
OK Downloading: 'amd64/linux-image-unsigned-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb'...
OK Downloading: 'amd64/linux-headers-5.14.7-051407_5.14.7-051407.202109221210_all.deb'...
OK Downloading: 'amd64/linux-modules-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb'...
OK
...

通过上述输出我们也可以看出,和手工安装的过程类似,同样需要 4 个主要文件,( 手动安装可以到 http://kernel.ubuntu.com/~kernel-ppa/mainline/ 这里下载 ):

  • linux-headers-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb(通用头文件) 和 amd64/linux-headers-5.14.7-051407_5.14.7-051407.202109221210_all.deb(基础头文件)
  • amd64/linux-image-unsigned-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb
  • amd64/linux-modules-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb

在本次升级到 5.14.7 的过程中,modules 和 linux images 成功,但是安装 linux-headers-5.14.7-051407-generic 头文件的时候,遇到了以下的问题:

dpkg: dependency problems prevent configuration of linux-headers-5.14.7-051407-generic:
linux-headers-5.14.7-051407-generic depends on libc6 (>= 2.34); however:
Version of libc6:amd64 on system is 2.33-0ubuntu5. dpkg: error processing package linux-headers-5.14.7-051407-generic (--install):
dependency problems - leaving unconfigured
....
Errors were encountered while processing:
linux-headers-5.14.7-051407-generic
E: Installation completed with errors

错误提示的大意是我们安装的 linux-headers-5.14.7-051407 需要 libc 的版本 >= 2.34,而我们系统的 libc 版本为 2.33。而 linux-headers 是我们 BPF 需要的环境 linux-headers,所以还需要手动修复安装。

$ sudo reboot
...
$ uname -a
Linux ubuntu-hirsute 5.14.7-051407-generic #202109221210 SMP Wed Sep 22 15:15:48 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

系统重启后已经证明我们成功升级了系统,这里我们继续手工修复 linux-headers 问题,首先尝试使用手工安装:

$ sudo apt install linux-headers-$(uname -r)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
linux-headers-5.14.7-051407-generic is already the newest version (5.14.7-051407.202109221210).
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
linux-headers-5.14.7-051407-generic : Depends: libc6 (>= 2.34) but 2.33-0ubuntu5 is to be installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).

错误提示我们使用 apt --fix-broken install 来修订错误,该命令其实做的事情就是删除存在问题的头文件包:

$ sudo apt --fix-broken install
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Correcting dependencies... Done
The following packages will be REMOVED:
linux-headers-5.14.7-051407-generic
0 upgraded, 0 newly installed, 1 to remove and 4 not upgraded.
1 not fully installed or removed.
After this operation, 23.3 MB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 162397 files and directories currently installed.)
Removing linux-headers-5.14.7-051407-generic (5.14.7-051407.202109221210) ... $ dpkg -l |grep -i linux-headers-5.14.7
ii linux-headers-5.14.7-051407 5.14.7-051407.202109221210 all Header files related to Linux kernel version 5.14.7

从网上搜索 libc-2.34 版本的安装包,下载并安装:

$ wget http://launchpadlibrarian.net/560614488/libc6_2.34-0ubuntu3_amd64.deb

# 因为本地已经安装了 libc6_2.33,安装会提示冲突,这里使用 --force-all 参数
$ sudo dpkg -i --force-all libc6_2.34-0ubuntu3_amd64.deb $ dpkg -l|grep libc6
ii libc6:amd64 2.34-0ubuntu3 amd64 GNU C Library: Shared libraries

Ubunt 5.14.7 主线 下载安装出错的 linux-headers-5.14.7-051407-generic,然后手工进行安装:

$sudo dpkg -i linux-headers-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb
Selecting previously unselected package linux-headers-5.14.7-051407-generic.
(Reading database ... 152977 files and directories currently installed.)
Preparing to unpack linux-headers-5.14.7-051407-generic_5.14.7-051407.202109221210_amd64.deb ...
Unpacking linux-headers-5.14.7-051407-generic (5.14.7-051407.202109221210) ...
Setting up linux-headers-5.14.7-051407-generic (5.14.7-051407.202109221210) ...

这种强制安装的 pkg 的方式,会影响到其他依赖包的管理,一般不推荐。 这种情况一般是我们升级的内核版本比较新,其他的对应组件还未能完全更新。如果是升级到 Ubuntu 的官方新发布版本(比如从 20.04 升级到 21.04),建议通过官方提供的方式升级,内核和其他依赖包都可以一起升级,保证整体完整型,可参考 如何升级到 Ubuntu 20.04

5.2 内核源码编译升级内核(进阶版)

某些情况我们需要更新版本的内核,如果 Ubuntu 官方还未提供该版本的安装包及内核源码,那么我们就需要通过源码编译和安装的方式进行。本文从 Ubuntu 环境中编译,其他的 Linux 发行版可以参考 内核源码编译指南

5.2.1 源码下载及编译工具安装

基于 Ubuntu 21.04 的系统,我们从 内核网站 上选择 5.14.7 版本进行编译。

$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.7.tar.xz
$ xz -d linux-5.14.7.tar.xz
$ tar xvf linux-5.14.7.tar

安装必要的内核编译工具:

$ sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev -y

Linux BTF 功能需要 pahole 工具 (>= 1.16) ,该工具位于 dwarves 包中,需要提前进行安装。

$ sudo apt install dwarves -y

5.2.2 源码编译

编译前需要将系统中运行的 config 文件复制到内核编译目录中为 .config 文件。

$ cd linux-5.14.7/
~/linux-5.14.7$ cp -v /boot/config-5.11.0-36-generic .config
'/boot/config-5.11.0-36-generic' -> '.config' $ make menuconfig

因为当前目录已经存在 .config 文件,make menuconfig 会直接使用 .config 作为默认值,通过图形界面修改值以后,默认会将当前的 .config 备份成 .config.old,并生成新的 .config 文件。

这里如果采用 make oldconfig,那么则是通过命令界面配置内核,会自动载入既有的 .config 配置文件,并且只有在遇到先前没有设定过的选项时,才会要求我们手动设定。同样也会将老的 .config 备份成 .config.old 文件。

运行 make 命令编译, -j 参数可指定并行 CPU 核数:

$ make -j $(getconf _NPROCESSORS_ONLN)

如果编译过程中遇到 No rule to make target 'debian/canonical-certs.pem' 的错误,可以通过禁用证书或者将运行系统中源码的相关证书复制到当前目录下的 debian 目录。

** 方案 1:复制系统中的证书 **

将当前运行系统源码中的 /usr/src/linux-source-5.11.0/debian/canonical-certs.pem 和 /usr/src/linux-source-5.11.0/debian/canonical-revoked-certs.pem 复制到当前 debian 目录中:

$ mkdir debian
$ cp /usr/src/linux-source-5.11.0/debian/canonical-certs.pem ./debain/
$ cp /usr/src/linux-source-5.11.0/debian/canonical-revoked-certs.pem ./debain/

** 方案 2:采用禁用 SYSTEM_TRUSTED_KEYS 的方式 **

$ scripts/config --disable SYSTEM_TRUSTED_KEYS  # 关闭禁止证书,修订 No rule to make target 'debian/canonical-certs.pem'

待证书设置以后,就可以运行 make 命令进行编译。

编译的时长使用的 CPU 核数相关,编译大概占用 20G 左右的产品空间。

5.2.3 内核安装和启动选择

编译成功后,使用以下命令安装内核:

$ sudo make modules_install && make install && make headers_install
$ sudo reboot
[....]
$ uname -a
Linux ubuntu-hirsute 5.14.7 #1 SMP Sun Sep 26 11:32:44 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

reboot 重启后,我们使用使用 uname 查看,发现系统内核已经更新为了 5.14.7 版本。

Ubuntu 21.04 采用 GRUB2 来管理启动菜单,对应的文件为 /boot/grub/grub.cfg ,该文件为 update-grub 命令依据 /etc/default/grub 文件自动生成。如果需要调整菜单选项,这需要通过 /etc/default/grub 文件修改,然后通过运行 update-grub 命令生效。

/etc/default/grub 文件中的:

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0

GRUB_DEFAULT 指定了默认启动的菜单选项,0 表示第一个菜单选项。

GRUB_TIMEOUT 选项表明了启动菜单显示的时间,方便用于用户选择,默认为 0,在调试新的内核时建议设置成一个非 0 值,同时需要将 GRUB_TIMEOUT_STYLE 的值从 hidden 调整为 menu:

GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5

然后通过 update-grub 命令更新生效,再重新启动就可以看到启动菜单。其他参数详细配置可参见 Grub 配置

todo: 在 VirtualBox 中能看到停顿,但是未能够看到启动界面

5.2.4 其他 - 编译内核以后磁盘管理

Virtualbox 底层使用 vmdk 的磁盘格式,当前会存在只是单向增大不会自动收缩的问题(即使我们在编译内核后,删除了编译相关的问题),请参见 VirtualBox VM 空间瘦身记(vmdk)

6. 参考



  1. Ubuntu 21.04 is here

基于 Ubuntu 21.04 BPF 开发环境全攻略的更多相关文章

  1. Linux一键安装web环境全攻略phpstudy版

    此教程主要是应对阿里云Linux云服务器ecs的web环境安装,理论上不限于阿里云服务器,此教程对所有Linux云服务器都具有参考价值. 写这篇文章的目的:网上有很多关于Linux一键安装web环境全 ...

  2. CH01基于Ubuntu系统的ZYNQ-7000开发环境的搭建

    1.1概述 实验环境: Windows 10 专业版 Vmware workstation 14.1.1 Ubuntu 16.04.3 Xilinx SDx 2017.4 实验内容: 国内Window ...

  3. ubuntu 14.04 java开发环境搭建 jdk 以及 inteliJ IDEA安装

    1.安装包 jdk1.7.0_71 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-188026 ...

  4. Linux一键安装web环境全攻略(阿里云服务器)

    摘自阿里云服务器官网,此处 一键安装包下载: 点此下载 安装须知 1.此安装包可在阿里云所有linux系统上部署安装,此安装包包含的软件及版本为: nginx:1.0.15.1.2.5.1.4.4 a ...

  5. Linux一键安装web环境全攻略(阿里云ECS服务器)

    摘自阿里云服务器官网,此处 一键安装包下载: 点此下载 安装须知 1.此安装包可在阿里云所有linux系统上部署安装,此安装包包含的软件及版本为: nginx:1.0.15.1.2.5.1.4.4 a ...

  6. [linux] [nginx] 一键安装web环境全攻略phpstudy版,超详细!

    找到运行中的服务器(实例). 打开这个主要是看它的IP,是公网ip,公网ip,公网ip,重要的事情说三遍. 接下来我们可以不用在阿里云上操作了,直接用客户端操作,这两个客户端就是Xshell 5和Xf ...

  7. Ubuntu虚拟机+ROS+Android开发环境配置笔记

    Ubuntu虚拟机+ROS+Android开发环境配置笔记 虚拟机设置: 1.本地环境:Windows 7:VMWare:联网 2.虚拟环境 :Ubuntu 14.04. 比較稳定,且支持非常多ROS ...

  8. Python黑帽编程1.2 基于VS Code构建Python开发环境

    Python黑帽编程1.2  基于VS Code构建Python开发环境 0.1  本系列教程说明 本系列教程,采用的大纲母本为<Understanding Network Hacks Atta ...

  9. 【转】基于Ubuntu 14.04 LTS编译Android4.4.2源代码

    原文网址:http://blog.csdn.net/gobitan/article/details/24367439 基于Ubuntu 14.04 LTS编译Android4.4.2源代码       ...

随机推荐

  1. C++CLR类库封装Native类库并用C#调用 - 草稿

    1.创建Native类库 新建项目->其他语言->Visual C++->Win32控制台应用程序->DLL     添加头文件       添加源文件       选择生成路 ...

  2. 使用Spark开发应用程序,并将作业提交到服务器

    1.pycharm编写spark应用程序 由于一些原因在windows上配置未成功(应该是可以配置成功的).我是在linux上直接使用pycharm,在linux的好处是,环境可能导致的一切问题不复存 ...

  3. opencv入门系列教学(四)处理鼠标事件

    一.鼠标事件的简单演示 opencv中的鼠标事件,值得是任何与鼠标相关的任何事物,例如左键按下,左键按下,左键双击等.我们先来看看鼠标事件有哪些,在python中执行下面代码: import cv2 ...

  4. Python3-sqlalchemy-orm 查询、修改

    #-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...

  5. vue element-ui el-date-picker 数据可以更改,但是前端不显示的更改后的数据问题

    template: <el-form-item label="有效时间:" prop="validTime">                    ...

  6. Linux命令进阶篇之一

    利用file命令查看那文件的类型 cd /etc 这里面的文件 命令:file 语法:file [-bLvz] 文件 解释:-b:显示结果,但是不显示文件名称 -L:直接显示符号链接所指向的文件的类型 ...

  7. git02

    Git Gui的使用 Ssh key 介绍及使用 Ssh key介绍 我理解的就是每台电脑上会产生出一个ssh key,然后自己有一个远程账户,但是自己有可能有很多台电脑, 包括家里的电脑还有公司的电 ...

  8. shell脚本之case语句

    case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行 ...

  9. Java中使用DOM4J来生成xml文件和解析xml文件

    一.前言 现在有不少需求,是需要我们解析xml文件中的数据,然后导入到数据库中,当然解析xml文件也有好多种方法,小编觉得还是DOM4J用的最多最广泛也最好理解的吧.小编也是最近需求里遇到了,就来整理 ...

  10. JAVA安全基础之代理模式(一)

    JAVA安全基础之代理模式(一) 代理模式是java的一种很常用的设计模式,理解代理模式,在我们进行java代码审计时候是非常有帮助的. 静态代理 代理,或者称为 Proxy ,简单理解就是事情我不用 ...