1. 内核版本选择
-
补丁 Prepatch:
Prepatch 或 “RC” 内核是主线内核的预发布版本,主要针对其他内核开发者和 Linux 爱好者。它们必须从源码中编译,并且通常包含新的功能,这些功能必须在稳定发布之前进行测试。Prepatch 内核由 Linus Torvalds 维护和发布。
-
主线版 Mainline:
主线版本由 Linus Torvalds 维护。它是介绍所有新功能的版本,包含了所有令人兴奋的新开发的功能。新的主线内核每 2-3 个月发布一次。
-
稳定版 Stable:
每一个主线内核发布后,它都被认为是 “稳定的”。任何稳定内核的错误修复都会从主线版本上回溯,并由指定的稳定内核维护者应用。在下一个主线内核可用之前,通常只有几个错误修复内核的发布 – 除非它被指定为 “长期维护内核”。稳定的内核更新是根据需要发布的,通常一周一次。
-
长期版 Longterm:
通常会有几个 “长期维护 “的内核版本,目的是为旧内核树的错误进行后向(backporting)修正。只有重要的bug 修复才会被应用到这长期内核版本中,而且它们通常不会频繁发布,尤其是对于老的内核版本。
当前长期版本如下:
Version |
Maintainer |
Released |
Projected EOL |
5.4 |
Greg Kroah-Hartman & Sasha Levin |
2019-11-24 |
Dec, 2025 |
4.19 |
Greg Kroah-Hartman & Sasha Levin |
2018-10-22 |
Dec, 2024 |
4.14 |
Greg Kroah-Hartman & Sasha Levin |
2017-11-12 |
Jan, 2024 |
4.9 |
Greg Kroah-Hartman & Sasha Levin |
2016-12-11 |
Jan, 2023 |
4.4 |
Greg Kroah-Hartman & Sasha Levin |
2016-01-10 |
Feb, 2022 |
基于上述内核版本信息,我们选择最新 LTS 版本 5.4,5.4 版本最新版本为 5.4.75。
2. Ubuntu 20.04 系统搭建
本文的操作环境基于 VirtualBox + Vagrant 搭建,你需要提前安装好 VirtualBox 和 Vagrant,操作系统采用 Ubuntun 20.04 Focal Fossa,其内核版本为 5.4.0, Ubuntu 的完整发行版本列表参见:wikipedia。
版本 |
开发代号 |
发布日期 |
标准支持结束时间 |
延迟支持时间 |
内核版本 |
20.04 LTS |
Focal Fossa |
2020-04-23 |
2025-04 |
2030-04 |
5.4 |
采用 vagrant 安装命令如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$ vagrant init bento/ubuntu-20.04
$ vagrant up
$ vagrant ssh
$ cat /etc/issue
Ubuntu 20.04.1 LTS \n \l
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.1 LTS
Release: 20.04
Codename: focal
$ uname -rs
Linux 5.4.0-52-generic
$ uname -a
Linux vagrant 5.4.0-52-generic #57-Ubuntu SMP Thu Oct 15 10:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ sudo dpkg --get-selections |grep linux-image
linux-image-5.4.0-52-generic install
linux-image-generic install
|
内核升级方式【备选资料】
-
到 Ubuntu 网站 http://kernel.ubuntu.com/~kernel-ppa/mainline/
-
选择所需要的 Ubuntu 内核版本目录,比如最新的内核版本 v5.4.75 目录(发布日期 2020 年 11 月 05 日)
-
在介绍页面中,根据硬件的架构选择内核版本,X86 硬件架构 64 位操作系统应选择 AMD64
-
下载对应的 deb 包
1
2
3
4
5
6
7
8
9
|
$ wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.4.75/amd64/linux-headers-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
$ wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.4.75/amd64/linux-image-unsigned-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
$ wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.4.75/amd64/linux-modules-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
$ ls -hl
total 59M
-rw-r--r-- 1 root root 1.2M Nov 5 12:51 linux-headers-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
-rw-r--r-- 1 root root 8.5M Nov 5 12:50 linux-image-unsigned-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
-rw-r--r-- 1 root root 50M Nov 5 12:50 linux-modules-5.4.75-050475-generic_5.4.75-050475.202011051231_amd64.deb
|
-
安装新的内核
升级完成后,重启系统,再次检查内核版本,检查已经为最新的 5.4.75 版本。
1
2
|
# uname -sr
Linux 5.4.75-050475-generic
|
在操作系统环境准备好以后,我们需要安装 BPF 技术测试的必要系统组件,安装命令如下:
1
2
|
$ sudo apt update
$ sudo apt install build-essential git make libelf-dev clang llvm strace tar bpfcc-tools linux-headers-$(uname -r) gcc-multilib flex bison libssl-dev -y
|
3. 内核源码编译
3.1 apt 安装源码 【推荐】
一般情况下推荐采用 apt 方式的安装源码,安装简单而且只安装当前内核的源码,源码的大小在 200M 左右。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# 编译内核需要的依赖包
# sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev
# apt-cache search linux-source
linux-source - Linux kernel source with Ubuntu patches
linux-source-5.4.0 - Linux kernel source for version 5.4.0 with Ubuntu patches
linux-hwe-5.8-source-5.8.0 - Linux kernel source for version 5.8.0 with Ubuntu patches
# apt install linux-source-5.4.0
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:
kernel-package libqt3-dev
The following NEW packages will be installed:
linux-source-5.4.0
0 upgraded, 1 newly installed, 0 to remove and 38 not upgraded.
Need to get 135 MB of archives.
After this operation, 150 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal-updates/main amd64 linux-source-5.4.0 all 5.4.0-52.57 [135 MB]
Fetched 135 MB in 27s (5,015 kB/s)
Selecting previously unselected package linux-source-5.4.0.
(Reading database ... 81402 files and directories currently installed.)
Preparing to unpack .../linux-source-5.4.0_5.4.0-52.57_all.deb ...
Unpacking linux-source-5.4.0 (5.4.0-52.57) ...
Setting up linux-source-5.4.0 (5.4.0-52.57) ...
|
源码安装至 /usr/src/
目录下。
1
2
3
4
5
6
7
8
9
10
11
12
|
$ ls -hl
total 4.0K
drwxr-xr-x 4 root root 4.0K Nov 9 13:22 linux-source-5.4.0
lrwxrwxrwx 1 root root 45 Oct 15 10:28 linux-source-5.4.0.tar.bz2 -> linux-source-5.4.0/linux-source-5.4.0.tar.bz2
$ tar -jxvf linux-source-5.4.0.tar.bz2
$ cd linux-source-5.4.0
$ make scripts # 可选
$ cp -v /boot/config-$(uname -r) .config # make defconfig 或者 make menuconfig
$ make headers_install
$ make M=samples/bpf # 如果配置出错,可以使用 make oldconfig && make prepare 修复
|
3.2 内核代码 Git 下载
如果我们的学习过程中需要持续用到多个版本,那么可以从 Ubuntun 官方维护的 git 仓库下载整个仓库包,下载的源码大小在 3G 左右。
Ubuntun 内核代码安装教程参见:KernelGitGuide。在线内核版本参见这里,编译前可以先阅读 README.rst。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ lsb_release -cs
focal
$ git clone git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/$(lsb_release -cs)
# 源码下载完成后,通常为 master 分支,我们可以切换到我们系统的本地版本号
$ cat /proc/version_signature
Ubuntu 5.4.0-52.57-generic 5.4.65
$ git checkout -b temp Ubuntu-5.4.0-52.57
# 如果后续不需要可以通过 git branch -d temp 删除
$ git log
commit 3f9bcec55a41c263d2f43a7ebbd8256b85767fe5 (HEAD -> temp, tag: Ubuntu-5.4.0-52.57, origin/master, origin/HEAD, master)
Author: Stefan Bader <[email protected]>
Date: Thu Oct 15 12:28:28 2020 +0200
UBUNTU: Ubuntu-5.4.0-52.57
Signed-off-by: Stefan Bader <[email protected]>
|
源码下载以后,编译方式与 apt 按照的方式一致。
3.3 编译错误
3.3.1 scripts/mod/modpos 报错
1
2
3
4
5
6
7
8
|
WARNING: Symbol version dump ./Module.symvers
is missing; modules will have no dependencies and modversions.
Building modules, stage 2.
MODPOST 0 modules
/bin/sh: 1: scripts/mod/modpost: not found
make[1]: *** [scripts/Makefile.modpost:94: __modpost] Error 127
make: *** [Makefile:1670: modules] Error 2
|
可以通过 make scripts
来补全脚本:
3.3.2 ”asm/x.h” 头文件缺少
1
2
3
4
5
6
7
8
9
10
11
12
13
|
./include/linux/spinlock.h:60:10: fatal error: 'asm/mmiowb.h' file not found
#include <asm/mmiowb.h>
^~~~~~~~~~~~~~
1 error generated.
CC samples/bpf/syscall_nrs.s
In file included from ./include/uapi/linux/unistd.h:8,
from samples/bpf/syscall_nrs.c:2:
./arch/x86/include/asm/unistd.h:19:12: fatal error: asm/unistd_64_x32.h: No such file or directory
19 | # include <asm/unistd_64_x32.h>
| ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.build:99: samples/bpf/syscall_nrs.s] Error 1
make: *** [Makefile:1757: samples/bpf] Error 2
|
通过查找发现系统中的头文件有对应的文件:
1
2
3
4
5
|
$ sudo find / -name mmiowb.h
/usr/src/linux-headers-5.4.0-52-generic/arch/x86/include/generated/asm/mmiowb.h
$ sudo cat /usr/src/linux-headers-5.4.0-52-generic/arch/x86/include/generated/asm/mmiowb.h
#include <asm-generic/mmiowb.h>
|
在 include 文件中创建 asm 目录,并将该 /usr/src/linux-headers-5.4.0-52-generic/arch/x86/include/generated
目下的全部文件复制到 include/asm
目录下:
1
2
|
$ mkdir -p include/asm
$ sudo cp /usr/src/linux-headers-5.4.0-52-generic/arch/x86/include/generated/asm/* include/asm
|
参见: https://www.mail-archive.com/[email protected]/msg127370.html
3.3.3 “generated/x.h” 报错
1
2
3
4
5
|
./include/linux/page-flags-layout.h:6:10: fatal error: 'generated/bounds.h' file not found
#include <generated/bounds.h>
^~~~~~~~~~~~~~~~~~~~
^Cmake[1]: *** [samples/bpf/Makefile:286: samples/bpf/xdp_tx_iptunnel_kern.o] Interrupt
make: *** [Makefile:1757: samples/bpf] Interrupt
|
解决方式
1
|
$ cp -r /usr/src/linux-headers-5.4.0-52-generic/include/generated/* ./include/generated
|
关于 headers 与 headers.x.y-z-generic 的区别:
1
2
|
linux-headers-5.4.0-52 Header files related to Linux kernel version 5.4.0
linux-headers-5.4.0-52-generic Linux kernel headers for version 5.4.0 on x86/x86_64
|
3.3.4 其他报错
可参考 https://lore.kernel.org/lkml/[email protected]/T/
4. 编译 sample/bpf 样例
1
2
3
4
|
$ make M=samples/bpf
# 清理
$ make M=samples/bpf clean
|
5. “Hello BPF”
内核中的程序 hello_kern.c
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <linux/bpf.h>
#include "bpf_helpers.h"
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx)
{
char msg[] = "Hello BPF!\n";
bpf_trace_printk(msg, sizeof(msg));
return 0;
}
char _license[] SEC("license") = "GPL";
|
用户态的程序 hello_user.c
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>
#include "bpf_load.h"
int main(int argc, char **argv)
{
if( load_bpf_file("hello_kern.o") != 0)
{
printf("The kernel didn't load BPF program\n");
return -1;
}
read_trace_pipe();
return 0;
}
|
在对应的位置修改 Makefile 文件,添加以下三行:
1
2
3
|
hostprogs-y += hello
hello-objs := bpf_load.o hello_user.o
always += hello_kern.o
|
编译
1
2
|
# V=1 查看详细编译输出
# make M=samples/bpf V=1
|
编译后的效果
1
2
3
4
5
6
|
# ls -hl samples/bpf/hello*
-rwxr-xr-x 1 root root 404K Nov 10 10:01 samples/bpf/hello
-rw-r--r-- 1 root root 296 Nov 10 09:58 samples/bpf/hello_kern.c
-rw-r--r-- 1 root root 3.7K Nov 10 10:02 samples/bpf/hello_kern.o
-rw-r--r-- 1 root root 220 Nov 10 09:57 samples/bpf/hello_user.c
-rw-r--r-- 1 root root 2.2K Nov 10 10:01 samples/bpf/hello_user.o
|
运行 hello
程序,在另外一个终端执行 ls -hl
,则输出结果如下:
1
2
|
# ./hello
<...>-113094 [000] .... 8411.799754: 0: Hello BPF!
|
6. 参考