Simplify to kernel-install-only; default to BBR + CAKE + ECN

Strip the project down to installing the BBRv3 kernel and nothing else, and
ship a single standard kernel (x86_64 + arm64, latest stable).

- install.sh: 1413 -> ~490 lines. Menu reduced to install latest / install
  specific / status / uninstall. Removed all qdisc/TCP-tuning/speedtest/
  smart-bandwidth/"madness"/clear-config features, the security (Dirty-Frag)
  mitigations, the profile (standard/max) selection, and the self-installing
  `b` quick command. Map dep command->package (sysctl->procps, awk->gawk) and
  abort clearly when a hard dependency is missing.
- Default network stack: on install write /etc/sysctl.d/99-bbrv3.conf with
  net.core.default_qdisc=cake, net.ipv4.tcp_congestion_control=bbr,
  net.ipv4.tcp_ecn=1 (CAKE has no compile-time default-qdisc option, so it is
  set via sysctl); uninstall removes the drop-in.
- prepare-kernel-config.sh: build sch_cake in (=y) so cake works at boot; drop
  the now-dead build-configs/ output.
- build.yml: matrix is just x86_64 + arm64 standard; tags are <arch>-<version>;
  removed the max profile/steps and the update-config-baseline auto-commit job;
  releases carry only the kernel .deb assets.
- Remove cve_2026_31431_detector.py and the two max-profile helper scripts.
- README rewritten to the 4-action, kernel-only scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-17 14:24:56 +08:00
parent c9c52c7e94
commit d888a9700e
7 changed files with 137 additions and 1770 deletions
+20 -118
View File
@@ -1,15 +1,10 @@
name: 构建带有BBRv3的内核
# Gitea Actions reads workflows from .github/workflows/ (and .gitea/workflows/).
# This workflow targets a self-hosted Gitea instance:
# * release existence checks, creation and asset uploads go through the Gitea
# REST API (curl), not the GitHub `gh` CLI;
# * config-baseline data is passed between jobs via Gitea release assets, NOT via
# actions/upload-artifact@v4 — the upstream artifact v4 actions detect Gitea as
# GHES and abort, so they are avoided entirely;
# * arm64 kernels are cross-compiled on the x86_64 runner
# (CROSS_COMPILE=aarch64-linux-gnu-), so only a single ubuntu-latest runner is
# required.
# This workflow targets a self-hosted Gitea instance: release existence checks,
# creation and asset uploads go through the Gitea REST API (curl), not the GitHub
# `gh` CLI. arm64 is cross-compiled on the x86_64 runner
# (CROSS_COMPILE=aarch64-linux-gnu-), so only a single ubuntu-latest runner is needed.
on:
workflow_dispatch:
@@ -74,15 +69,13 @@ jobs:
missing=0
for arch in x86_64 arm64; do
for suffix in "" "-max"; do
tag="$arch-$version$suffix"
if release_exists "$tag"; then
echo "$tag already exists."
else
echo "$tag is missing."
missing=1
fi
done
tag="$arch-$version"
if release_exists "$tag"; then
echo "$tag already exists."
else
echo "$tag is missing."
missing=1
fi
done
if [ "$missing" -eq 0 ]; then
@@ -100,35 +93,15 @@ jobs:
fail-fast: false
matrix:
include:
# All targets build on a single x86_64 runner; arm64 is cross-compiled.
# Both targets build on a single x86_64 runner; arm64 is cross-compiled.
- arch: x86_64
runs_on: ubuntu-latest
cross_compile: ""
profile: standard
profile_name: BBRv3
release_suffix: ""
localversion: -bbrv3
- arch: arm64
runs_on: ubuntu-latest
cross_compile: aarch64-linux-gnu-
profile: standard
profile_name: BBRv3
release_suffix: ""
localversion: -bbrv3
- arch: x86_64
runs_on: ubuntu-latest
cross_compile: ""
profile: max
profile_name: BBRv3 Max
release_suffix: -max
localversion: -bbrv3-max
- arch: arm64
runs_on: ubuntu-latest
cross_compile: aarch64-linux-gnu-
profile: max
profile_name: BBRv3 Max
release_suffix: -max
localversion: -bbrv3-max
runs-on: ${{ matrix.runs_on }}
env:
ARCH: ${{ matrix.arch }}
@@ -137,8 +110,7 @@ jobs:
- name: 检查是否已发布
id: check_release
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}${{ matrix.release_suffix }}
PROFILE_NAME: ${{ matrix.profile_name }}
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
@@ -148,7 +120,7 @@ jobs:
echo "$TAG already exists; skipping build."
else
echo "BUILD_NEEDED=true" >> "$GITHUB_ENV"
echo "$TAG does not exist; building latest kernel with $PROFILE_NAME."
echo "$TAG does not exist; building latest BBRv3 kernel."
fi
- name: 检出代码
@@ -190,27 +162,13 @@ jobs:
bash "$GITHUB_WORKSPACE/scripts/apply-bbrv3-port.sh"
grep -n "BBR_VERSION" net/ipv4/tcp_bbr.c
- name: 应用 BBRv3 Max 极限内核配置
if: env.BUILD_NEEDED == 'true' && matrix.profile == 'max'
working-directory: ./kernel/linux
run: |
bash "$GITHUB_WORKSPACE/scripts/apply-bbrv3-max-profile.sh"
- name: 编译声明
if: env.BUILD_NEEDED == 'true'
working-directory: ./kernel/linux
env:
PROFILE: ${{ matrix.profile }}
run: |
grep -v "MODULE_DESCRIPTION" net/ipv4/tcp_bbr.c > net/ipv4/tcp_bbr.c.tmp
mv net/ipv4/tcp_bbr.c.tmp net/ipv4/tcp_bbr.c
if [ "$PROFILE" = "max" ]; then
echo 'MODULE_DESCRIPTION("TCP BBR v3 Max - aggressive throughput profile by Joey");' >> net/ipv4/tcp_bbr.c
else
echo 'MODULE_DESCRIPTION("TCP BBR v3 (Bottleneck Bandwidth and RTT) - Compiled & Optimized by Joey");' >> net/ipv4/tcp_bbr.c
fi
echo 'MODULE_DESCRIPTION("TCP BBR v3 (Bottleneck Bandwidth and RTT) - Compiled & Optimized by Joey");' >> net/ipv4/tcp_bbr.c
tail -n 5 net/ipv4/tcp_bbr.c
- name: 更新 Makefile 中的版本号
@@ -264,7 +222,7 @@ jobs:
- name: 发布前复查是否已发布
if: env.BUILD_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}${{ matrix.release_suffix }}
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
@@ -280,13 +238,12 @@ jobs:
- name: 发布到 Gitea Release
if: env.BUILD_NEEDED == 'true' && env.PUBLISH_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}${{ matrix.release_suffix }}
PROFILE_NAME: ${{ matrix.profile_name }}
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
TARGET_ARCH: ${{ matrix.arch }}
TARGET_SHA: ${{ github.sha }}
run: |
set -euo pipefail
body="带有 $PROFILE_NAME 的最新内核,适用于 $TARGET_ARCH 架构。Compiled & Optimized by Joey."
body="带有 BBRv3 的最新内核,适用于 $TARGET_ARCH 架构。Compiled & Optimized by Joey."
auth=(-H "Authorization: token $GITEA_TOKEN")
@@ -309,14 +266,11 @@ jobs:
exit 1
fi
# Collect assets: kernel debs plus the versioned arch config.
# Upload the kernel .deb packages as release assets.
shopt -s nullglob
assets=( ./kernel/linux-*.deb )
cfg="./build-configs/$TARGET_ARCH-$KERNEL_VERSION.config"
[ -f "$cfg" ] && assets+=( "$cfg" )
if [ "${#assets[@]}" -eq 0 ]; then
echo "No assets found to upload for $TAG" >&2
echo "No .deb assets found to upload for $TAG" >&2
exit 1
fi
@@ -328,55 +282,3 @@ jobs:
-F "attachment=@$f" >/dev/null
done
echo "Published $TAG with ${#assets[@]} asset(s)."
update-config-baseline:
needs: [preflight, build]
if: ${{ needs.preflight.outputs.build_needed == 'true' && needs.build.result == 'success' }}
runs-on: ubuntu-latest
env:
KERNEL_VERSION: ${{ needs.preflight.outputs.kernel_version }}
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 回写配置基线
run: |
set -euxo pipefail
auth=(-H "Authorization: token $GITEA_TOKEN")
# Pull the generated .config for a freshly published standard release back
# into the repo baseline. Config travels as a Gitea release asset (named
# "<arch>-<version>.config"), so no actions/artifact is needed.
refresh_baseline() {
local arch="$1" baseline="$2"
local tag="$arch-$KERNEL_VERSION" # standard release (no -max)
local rel asset_name url
rel=$(curl -sS "${auth[@]}" "$GITEA_API/releases/tags/$tag")
if [ -z "$(echo "$rel" | jq -r '.id // empty')" ]; then
echo "Release $tag not found; skipping $baseline."
return 0
fi
asset_name="$arch-$KERNEL_VERSION.config"
url=$(echo "$rel" | jq -r --arg n "$asset_name" \
'.assets[]? | select(.name == $n) | .browser_download_url' | head -n1)
if [ -z "$url" ]; then
echo "Config asset $asset_name not found on $tag; skipping $baseline."
return 0
fi
curl -fsSL "${auth[@]}" -o "$baseline" "$url"
echo "Refreshed $baseline from $tag."
}
refresh_baseline x86_64 x86-64.config
refresh_baseline arm64 arm64.config
if git diff --quiet -- x86-64.config arm64.config; then
echo "Generated configs match current baselines."
exit 0
fi
git config user.name "gitea-actions[bot]"
git config user.email "gitea-actions[bot]@noreply.git.chilldove.com"
git add x86-64.config arm64.config
git commit -m "Refresh generated kernel config baselines [skip ci]"
git push
+30 -280
View File
@@ -1,6 +1,6 @@
# BBRv3 管理脚本
# BBRv3 内核安装脚本
一个用于 Debian/Ubuntu VPS 的 BBRv3 内核安装与网络加速管理脚本。
一个用于 Debian/Ubuntu VPS 的 BBRv3 内核安装脚本。脚本会自动识别系统架构,从本仓库的 Gitea Releases 下载匹配的 BBRv3 内核 `.deb` 包并安装。内核默认启用 BBR 拥塞控制并内置 `sch_cake`;安装脚本会写入 `/etc/sysctl.d/99-bbrv3.conf`,把默认队列算法设为 `cake` 并开启 ECN`net.ipv4.tcp_ecn=1`),安装并重启后 BBR + CAKE + ECN 自动生效
脚本入口:
@@ -8,22 +8,11 @@
bash <(curl -fsSL https://git.chilldove.com/icePigeon/linux-kernel-bbrv3/raw/branch/main/install.sh)
```
首次运行后脚本会自动安装联网快捷命令,后续可直接运行:
```bash
b
```
快捷命令每次都会从 Gitea 拉取最新版脚本执行,不使用本地缓存脚本。
脚本会自动识别当前系统架构,从本仓库 Gitea Releases 下载匹配的 BBRv3 内核 `.deb` 包,并提供安装、指定版本安装、状态检查、加速模式切换和卸载功能。安装内核时可选择标准 BBRv3 或 BBRv3 Max 激进吞吐内核。
## 支持环境
| 项目 | 要求 |
| --- | --- |
| 最低支持系统 | Ubuntu 24.04+ / Debian 12+ |
| 推荐系统 | Ubuntu 24.04+ / Debian 12+ |
| 包管理器 | `apt-get` |
| 架构 | `x86_64` / `aarch64` |
| 引导方式 | 建议使用 GRUB |
@@ -31,40 +20,21 @@ b
不建议在树莓派、NanoPi 等依赖 U-Boot 或厂商定制内核链路的设备上使用。此类设备的内核安装和启动流程通常与通用 Debian/Ubuntu VPS 不一致。
Debian testing/unstable 如缺少 `VERSION_ID`,脚本会按 `VERSION_CODENAME` 识别 `bookworm``trixie``forky``sid`。Alpine Linux 暂不支持安装本项目内核包,因为当前 release 产物是 `.deb`安装和引导流程依赖 Debian/Ubuntu 的包管理与内核安装链路。
Debian testing/unstable 如缺少 `VERSION_ID`,脚本会按 `VERSION_CODENAME` 识别 `bookworm``trixie``forky``sid`。Alpine 等非 Debian 系统不支持安装本项目内核包(产物是 `.deb`,依赖 Debian/Ubuntu 的包管理与内核安装链路
本项目当前内核主线为 Linux 7.x。安装内核时脚本会按最低支持系统拦截过旧环境,避免因用户态、initramfs 或引导链路过旧导致启动失败或 kernel panic。推荐系统是更稳妥的部署选择;旧系统仍可使用状态检查、网络调优、清空优化和卸载功能。
本项目内核主线为 Linux 7.x。安装内核时脚本会按最低支持系统拦截过旧环境,避免因用户态、initramfs 或引导链路过旧导致启动失败或 kernel panic。
## 菜单功能
运行脚本后进入交互菜单:
运行脚本后进入交互菜单:
```text
1. 安装或更新 BBR v3 最新版
2. 指定版本安装
1. 安装或更新 BBR v3 内核(最新版
2. 安装指定版本
3. 检查 BBR v3 状态
4. 启用 BBR + FQ
5. 启用 BBR + FQ_CODEL
6. 启用 BBR + FQ_PIE
7. 启用 BBR + CAKE
8. 亚太机器 TCP 调优
9. 卸载 BBR 内核
10. BBR v3 智能带宽优化
11. 清空网络优化配置
12. BBR v3 疯批模式(极限测速挑战)
4. 卸载 BBR v3 内核
```
常用流程:
1. 选择 `1` 安装或更新 BBRv3 内核,并按提示选择标准版或 Max 极限版。
2. 按提示重启系统。
3. 重新运行脚本,选择 `3` 检查 BBRv3 状态。
4. 按需选择 `4``7` 设置队列算法。
5. 亚太线路机器可选择 `8` 写入 TCP 收发窗口与空闲慢启动调优。
6. 不确定线路参数时可选择 `10` 自动测速并按带宽档位计算 TCP 缓冲区。
7. 做自有链路极限测速挑战时可选择 `12` 写入激进冲速率参数。
8. 需要撤回调优时可选择 `11` 清空脚本写入的网络优化配置。
## 内核与 BBR 策略
本项目的构建目标是:
@@ -82,36 +52,21 @@ linux-7.0.y -> patches/bbrv3-linux-7.0.patch
linux-7.1.y -> patches/bbrv3-linux-7.1.patch
```
同一主线系列内的小版本更新会自动复用同一个 patch,例如 `7.0.11 -> 7.0.12`。如果内核跳到新的主线系列但仓库内还没有对应 patch,构建会直接失败,避免产出不可验证的内核包。
同一主线系列内的小版本更新会自动复用同一个 patch,例如 `7.0.11 -> 7.0.12`。如果内核跳到新的主线系列但仓库内还没有对应 patch,构建会直接失败,避免产出不可验证的内核包。
## 安装最新版
```bash
bash <(curl -fsSL https://git.chilldove.com/icePigeon/linux-kernel-bbrv3/raw/branch/main/install.sh)
```
首次运行后也可以直接输入:
```bash
b
```
该命令会联网拉取最新版脚本后运行。
选择:
运行脚本后选择:
```text
1. 安装或更新 BBR v3 最新版
1. 安装或更新 BBR v3 内核(最新版
```
脚本会:
- 检查系统是否为 Debian/Ubuntu。
- 检查架构是否为 `x86_64``aarch64`
- 让用户选择标准 BBRv3 或 BBRv3 Max 激进吞吐内核
- 从 Gitea Releases 获取当前架构和内核类型匹配的最新版本。
- 下载非 debug 的内核 `.deb` 包。
- 安装新内核并更新引导配置。
- 检查系统是否为 Debian/Ubuntu,架构是否为 `x86_64``aarch64`
- 从 Gitea Releases 获取当前架构匹配的最新版本
- 下载内核 `.deb` 包,安装并更新引导配置
- 提示是否重启。
如果访问私有仓库或遇到 Gitea API 限流,可先设置 token
@@ -121,27 +76,23 @@ export GITEA_TOKEN=你的 Gitea Token
bash <(curl -fsSL https://git.chilldove.com/icePigeon/linux-kernel-bbrv3/raw/branch/main/install.sh)
```
## 指定版本安装
## 安装指定版本
运行脚本后选择:
```text
2. 指定版本安装
2. 安装指定版本
```
脚本会先让用户选择标准 BBRv3 或 BBRv3 Max,再列出当前架构可用的 release tag,并按编号安装指定版本。
脚本会列出当前架构可用的 release tag,并按编号安装指定版本。
release tag 格式:
```text
x86_64-7.0.11
arm64-7.0.11
x86_64-7.0.11-max
arm64-7.0.11-max
```
其中不带 `-max` 的 tag 是标准 BBRv3 内核,带 `-max` 的 tag 是 BBRv3 Max 激进吞吐内核。Max 版会提高 Startup、ProbeBW 和 cwnd 策略的进攻性,但保留 BBRv3 的 loss、ECN、inflight 和 ProbeBW 反馈闭环,只适合自有链路吞吐测试,不建议日常生产使用。
## 检查 BBRv3 状态
运行脚本后选择:
@@ -154,7 +105,7 @@ arm64-7.0.11-max
- `tcp_bbr` 模块版本是否为 `3`
- 当前 TCP 拥塞控制算法是否为 `bbr`
- Dirty Frag 相关模块黑名单是否写入
- 当前默认队列算法是否为 `cake`
也可以手动检查:
@@ -162,234 +113,33 @@ arm64-7.0.11-max
uname -r
sysctl net.ipv4.tcp_congestion_control
sysctl net.core.default_qdisc
sysctl net.ipv4.tcp_ecn
modinfo tcp_bbr 2>/dev/null | grep '^version:'
```
## 加速模式
脚本支持以下组合:
| 菜单 | 拥塞控制 | 队列算法 |
| --- | --- | --- |
| 4 | `bbr` | `fq` |
| 5 | `bbr` | `fq_codel` |
| 6 | `bbr` | `fq_pie` |
| 7 | `bbr` | `cake` |
选择后脚本会立即尝试应用配置,并询问是否永久写入:
```text
/etc/sysctl.d/99-joeyblog.conf
```
脚本不仅会写入 `net.core.default_qdisc`,还会尝试把当前默认路由出口网卡的 root qdisc 立即替换为所选算法,避免只对新建队列生效、当前网卡实际仍保持旧队列。
对于需要模块加载的队列算法,脚本会尝试加载对应 `sch_*` 模块,并在需要时写入:
```text
/etc/modules-load.d/joeyblog-qdisc.conf
```
## 亚太机器 TCP 调优
运行脚本后选择:
```text
8. 亚太机器 TCP 调优
```
脚本会立即应用并永久写入以下配置:
```text
net.ipv4.tcp_wmem = 4096 16384 12582912
net.ipv4.tcp_rmem = 4096 131072 33554432
net.ipv4.tcp_limit_output_bytes = 4194304
net.ipv4.tcp_slow_start_after_idle = 0
```
配置文件路径:
```text
/etc/sysctl.d/99-joeyblog.conf
```
## BBR v3 智能带宽优化
运行脚本后选择:
```text
10. BBR v3 智能带宽优化
```
脚本会优先安装并运行 Ookla 官方 `speedtest 1.2.0`,自动尝试附近测速服务器并获取上传/下载带宽;如果检测到 Python 版 `speedtest-cli`,会先自动移除并安装需要的 Ookla 官方版本。测速失败时会提示手动输入上传带宽。Speedtest 的测速节点延迟会被隐藏,不展示也不参与 RTT 计算,避免把测速节点延迟误当作真实业务线路延迟。
优化逻辑:
- 自动启用 `bbr` 拥塞控制和 `fq` 队列算法。
- 根据上传带宽和地区模式映射推荐 TCP buffer 档位。
- RTT 必须由用户手动输入,应填写真实链接延迟,使用 v2rayN 测出来的结果即可;不使用 Speedtest 测出来的 Ping。
- 用户手动选择亚太、美欧或手动 RTT + buffer 档位,不再按测速 RTT 自动判断。
- 亚太线路使用较保守的 buffer,美欧高延迟线路使用更大 buffer。
- 按机器内存设置 TCP buffer 上限,避免小内存 VPS 过度放大缓冲区。
- 同步写入 `net.core.rmem_max` / `net.core.wmem_max` / `tcp_rmem` / `tcp_wmem`
- 保留 `tcp_limit_output_bytes = 4194304``tcp_slow_start_after_idle = 0`
地区模式参考:
| 模式 | RTT 参考 |
| --- | --- |
| 亚太线路 | 通常小于 `100ms` |
| 美欧线路 | 通常 `150-300ms` |
| 手动 RTT | 按用户输入 RTT,并手动选择亚太或美欧 buffer 档位 |
配置同样写入:
```text
/etc/sysctl.d/99-joeyblog.conf
```
## BBR v3 疯批模式
运行脚本后选择:
```text
12. BBR v3 疯批模式(极限测速挑战)
```
该模式只面向自有链路的极限测速挑战,不建议日常使用。目标是尽量压榨单向吞吐和跑满带宽上限,会主动牺牲重传率、延迟抖动、排队延迟、连接稳定性、交互体验和流量公平性。
脚本会强制启用 `bbr` 拥塞控制和 `fq` 队列算法,并立即尝试替换当前默认路由出口网卡的 root qdisc。
写入参数:
```text
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
net.core.rmem_max = 1073741824
net.core.wmem_max = 1073741824
net.core.optmem_max = 1073741824
net.core.netdev_max_backlog = 1000000
net.core.somaxconn = 65535
net.ipv4.tcp_wmem = 4096 1048576 1073741824
net.ipv4.tcp_rmem = 4096 1048576 1073741824
net.ipv4.tcp_limit_output_bytes = 268435456
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_notsent_lowat = 4294967295
net.ipv4.tcp_autocorking = 0
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_ecn = 0
```
脚本还会把当前默认出口网卡的运行态 `txqueuelen` 拉高到 `100000`,让测速时本机发送队列更激进。该项不是 sysctl 参数,不会写入 `/etc/sysctl.d/99-joeyblog.conf`
其中核心参数应用失败会中止;不同内核可能不支持部分附加参数,脚本会尽量写入,失败的附加项不会阻断整个模式。
## 清空网络优化配置
运行脚本后选择:
```text
11. 清空网络优化配置
```
脚本会清理本项目写入的网络优化持久配置:
- `net.core.default_qdisc`
- `net.ipv4.tcp_congestion_control`
- `net.core.rmem_max` / `net.core.wmem_max` / `net.core.optmem_max`
- `net.core.netdev_max_backlog` / `net.core.somaxconn`
- `net.ipv4.tcp_rmem` / `net.ipv4.tcp_wmem`
- `net.ipv4.tcp_limit_output_bytes`
- `net.ipv4.tcp_slow_start_after_idle`
- `net.ipv4.tcp_notsent_lowat`
- `net.ipv4.tcp_autocorking`
- `net.ipv4.tcp_no_metrics_save`
- `net.ipv4.tcp_mtu_probing`
- `net.ipv4.tcp_fastopen`
- `net.ipv4.tcp_window_scaling`
- `net.ipv4.tcp_moderate_rcvbuf`
- `net.ipv4.tcp_ecn`
同时删除:
```text
/etc/modules-load.d/joeyblog-qdisc.conf
```
该功能只清空网络优化配置,不卸载 BBR 内核,也不移除 Dirty Frag 安全缓解规则。当前运行态参数可能需要重启后完全恢复为系统默认值。
## 安全缓解
脚本启动时会写入 Dirty Frag 风险面收敛规则:
```text
/etc/modprobe.d/99-joeyblog-security.conf
```
包含:
- `esp4` / `esp6` / `rxrpc` 黑名单,用于收敛 Dirty Frag 相关风险面。
如果模块当前已加载,脚本会尝试卸载;如果模块被占用,则黑名单会在重启后生效。
CVE-2026-31431 对应的 AEAD userspace 接口在新构建内核中由内核配置侧收敛:
```text
# CONFIG_CRYPTO_USER_API_AEAD is not set
```
因此安装脚本不再额外写入 `algif_aead` 黑名单。
如果旧版本脚本已经写入过该黑名单,新脚本只会在当前运行内核确认关闭 `CONFIG_CRYPTO_USER_API_AEAD` 后移除它。
## CVE-2026-31431 检测
仅检测,不利用:
```bash
command -v python3 >/dev/null 2>&1 || (sudo apt update && sudo apt install -y python3)
curl -fsSL -o cve_2026_31431_detector.py https://git.chilldove.com/icePigeon/linux-kernel-bbrv3/raw/branch/main/cve_2026_31431_detector.py
chmod +x cve_2026_31431_detector.py
sudo python3 cve_2026_31431_detector.py
```
## 内核包来源
`.deb` 内核包由 Gitea Actions 构建并发布到本仓库 Releases。
构建流程会:
- 读取 kernel.org 最新 stable 版本。
- 下载 `gregkh/linux` 对应 stable 分支。
- 应用仓库内固定 BBRv3 patch。
- 强制默认启用 BBR 和 fq。
- 关闭 debug info。
- 拒绝发布 `*-dbg*.deb` / `*-dbgsym*.deb`
构建不会自动更新 BBR patch 本身。
## 卸载
运行脚本后选择:
```text
9. 卸载 BBR 内核
4. 卸载 BBR v3 内核
```
脚本会卸载由本项目安装的 BBR v3 内核包(包名带 `-bbrv3` / `-bbrv3-max` 后缀),并更新引导配置。卸载后建议重启。
脚本会卸载由本项目安装的 BBR v3 内核包(包名带 `-bbrv3` 后缀),删除 `/etc/sysctl.d/99-bbrv3.conf`,并更新引导配置。卸载后建议重启。
## 反馈
## 内核包来源
博客:
`.deb` 内核包由 Gitea Actions 构建并发布到本仓库 Releases,提供 `x86_64``arm64` 两种标准 BBRv3 内核(arm64 在同一台 x86_64 runner 上交叉编译)。
[JoeyBlog](https://joeyblog.net)
构建流程会:
反馈群组:
- 读取 kernel.org 最新 stable 版本。
- 下载 `gregkh/linux` 对应 stable 分支。
- 应用仓库内固定 BBRv3 patch。
- 默认启用 BBR,并把 `sch_cake` 编入内核(=y),安装脚本据此把默认队列设为 cake。
- 关闭 debug info,拒绝发布 `*-dbg*.deb` / `*-dbgsym*.deb`
[Telegram Feedback Group](https://t.me/+ft-zI76oovgwNmRh)
构建不会自动更新 BBR patch 本身。
## 免责声明
-186
View File
@@ -1,186 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CVE-2026-31431 风险面检测脚本(仅检测,不利用)
检测项:
1) CVE-2026-31431 风险面(AEAD userspace 接口)
2) Dirty Frag 风险面(ESP/RXRPC 相关模块与配置)
"""
import gzip
import os
import socket
import subprocess
from typing import Optional, Tuple
def get_kernel_release() -> str:
return subprocess.check_output(["uname", "-r"], text=True).strip()
def read_kernel_config(kernel_release: str) -> Optional[str]:
boot_cfg = f"/boot/config-{kernel_release}"
if os.path.exists(boot_cfg):
with open(boot_cfg, "r", encoding="utf-8", errors="ignore") as f:
return f.read()
proc_cfg = "/proc/config.gz"
if os.path.exists(proc_cfg):
with gzip.open(proc_cfg, "rt", encoding="utf-8", errors="ignore") as f:
return f.read()
return None
def parse_aead_config(config_text: Optional[str]) -> str:
if not config_text:
return "未知(未找到内核配置)"
for line in config_text.splitlines():
if line.startswith("CONFIG_CRYPTO_USER_API_AEAD="):
return line.split("=", 1)[1].strip()
if line.strip() == "# CONFIG_CRYPTO_USER_API_AEAD is not set":
return "n"
return "未知(配置项不存在)"
def parse_tristate_symbol(config_text: Optional[str], symbol: str) -> str:
if not config_text:
return "未知(未找到内核配置)"
key = f"CONFIG_{symbol}="
disabled = f"# CONFIG_{symbol} is not set"
for line in config_text.splitlines():
if line.startswith(key):
return line.split("=", 1)[1].strip()
if line.strip() == disabled:
return "n"
return "未知(配置项不存在)"
def is_module_loaded(module_name: str) -> bool:
try:
with open("/proc/modules", "r", encoding="utf-8", errors="ignore") as f:
for line in f:
if line.startswith(module_name + " "):
return True
except OSError:
return False
return False
def check_af_alg_aead_bind() -> Tuple[bool, str]:
af_alg = getattr(socket, "AF_ALG", 38)
sock_type = getattr(socket, "SOCK_SEQPACKET", 5)
try:
sock = socket.socket(af_alg, sock_type, 0)
except OSError as e:
return False, f"创建 socket 失败: {e}"
try:
sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
return True, "bind 成功"
except OSError as e:
return False, f"bind 失败: {e}"
finally:
try:
sock.close()
except OSError:
pass
def read_security_conf(path: str) -> str:
if not os.path.exists(path):
return ""
try:
with open(path, "r", encoding="utf-8", errors="ignore") as f:
return f.read()
except OSError:
return ""
def has_rule(text: str, rule: str) -> bool:
return any(line.strip() == rule for line in text.splitlines())
def main() -> None:
kernel = get_kernel_release()
cfg = read_kernel_config(kernel)
aead_cfg = parse_aead_config(cfg)
mod_loaded = is_module_loaded("algif_aead")
bind_ok, bind_msg = check_af_alg_aead_bind()
xfrm_esp = parse_tristate_symbol(cfg, "XFRM_ESP")
inet_esp = parse_tristate_symbol(cfg, "INET_ESP")
inet6_esp = parse_tristate_symbol(cfg, "INET6_ESP")
af_rxrpc = parse_tristate_symbol(cfg, "AF_RXRPC")
esp4_loaded = is_module_loaded("esp4")
esp6_loaded = is_module_loaded("esp6")
rxrpc_loaded = is_module_loaded("rxrpc")
security_conf_path = "/etc/modprobe.d/99-joeyblog-security.conf"
security_conf = read_security_conf(security_conf_path)
dirtyfrag_rules_ok = all(
has_rule(security_conf, rule)
for rule in (
"blacklist esp4",
"install esp4 /bin/false",
"blacklist esp6",
"install esp6 /bin/false",
"blacklist rxrpc",
"install rxrpc /bin/false",
)
)
print(f"[*] 当前内核: {kernel}")
print("")
print("[CVE-2026-31431 检测]")
print(f"[*] CONFIG_CRYPTO_USER_API_AEAD: {aead_cfg}")
print(f"[*] algif_aead 已加载: {mod_loaded}")
print(f"[*] AF_ALG AEAD bind 可用: {bind_ok} ({bind_msg})")
print("")
print("[Dirty Frag 检测]")
print(f"[*] CONFIG_XFRM_ESP: {xfrm_esp}")
print(f"[*] CONFIG_INET_ESP: {inet_esp}")
print(f"[*] CONFIG_INET6_ESP: {inet6_esp}")
print(f"[*] CONFIG_AF_RXRPC: {af_rxrpc}")
print(f"[*] esp4 已加载: {esp4_loaded}")
print(f"[*] esp6 已加载: {esp6_loaded}")
print(f"[*] rxrpc 已加载: {rxrpc_loaded}")
print(f"[*] Dirty Frag 黑名单规则完整: {dirtyfrag_rules_ok} ({security_conf_path})")
print("")
print("[检测结论]")
high_risk_surface = (aead_cfg in {"y", "m"}) and bind_ok
reduced_surface = (aead_cfg == "n") or (not bind_ok)
dirtyfrag_cfg_exposed = any(v in {"y", "m"} for v in (xfrm_esp, inet_esp, inet6_esp, af_rxrpc))
dirtyfrag_runtime_exposed = esp4_loaded or esp6_loaded or rxrpc_loaded
dirtyfrag_high_risk = dirtyfrag_cfg_exposed and (dirtyfrag_runtime_exposed or not dirtyfrag_rules_ok)
dirtyfrag_reduced = (not dirtyfrag_cfg_exposed) or (dirtyfrag_rules_ok and not dirtyfrag_runtime_exposed)
if high_risk_surface:
print("[!] 检测到高风险暴露面。")
print("[!] 若内核未包含上游修复补丁,系统可能受 CVE-2026-31431 影响。")
print("[!] 建议:升级到新构建内核,或禁用 CRYPTO_USER_API_AEAD;旧内核可临时屏蔽 algif_aead。")
elif reduced_surface:
print("[+] 风险面已收敛/已缓解。")
else:
print("[?] 结果不确定,请继续核对内核补丁级别。")
if dirtyfrag_high_risk:
print("[!] Dirty Frag 风险面暴露。")
print("[!] 建议:禁用 XFRM_ESP/INET_ESP/INET6_ESP/AF_RXRPC,并屏蔽 esp4/esp6/rxrpc。")
elif dirtyfrag_reduced:
print("[+] Dirty Frag 风险面已收敛/已缓解。")
else:
print("[?] Dirty Frag 结果不确定,请继续核对内核补丁级别。")
if __name__ == "__main__":
main()
+82 -1009
View File
File diff suppressed because it is too large Load Diff
-91
View File
@@ -1,91 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
target="${1:-net/ipv4/tcp_bbr.c}"
if [[ ! -f "$target" ]]; then
echo "BBRv3 source file not found: $target" >&2
exit 1
fi
if ! grep -q '^#define BBR_VERSION[[:space:]]*3' "$target"; then
echo "BBRv3 max profile requires BBR_VERSION=3 in $target." >&2
exit 1
fi
python3 - "$target" <<'PY'
import re
import sys
from pathlib import Path
path = Path(sys.argv[1])
text = path.read_text()
replacements = {
r"static const u32 bbr_probe_rtt_win_ms = .*?;": "static const u32 bbr_probe_rtt_win_ms = 10000;",
r"static const u32 bbr_probe_rtt_cwnd_gain = .*?;": "static const u32 bbr_probe_rtt_cwnd_gain = BBR_UNIT;",
r"static const u32 bbr_probe_rtt_mode_ms = .*?;": "static const u32 bbr_probe_rtt_mode_ms = 10;",
r"static const u32 bbr_tso_rtt_shift = .*?;": "static const u32 bbr_tso_rtt_shift = 2;",
r"static const int bbr_pacing_margin_percent = .*?;": "static const int bbr_pacing_margin_percent = 0;",
r"static const int bbr_startup_pacing_gain = .*?;": "static const int bbr_startup_pacing_gain = BBR_UNIT * 3;",
r"static const int bbr_startup_cwnd_gain = .*?;": "static const int bbr_startup_cwnd_gain = BBR_UNIT * 5 / 2;",
r"static const int bbr_drain_gain = .*?;": "static const int bbr_drain_gain = BBR_UNIT / 2;",
r"static const int bbr_cwnd_gain = .*?;": "static const int bbr_cwnd_gain = BBR_UNIT * 5 / 2;",
r"static const u32 bbr_cwnd_min_target = .*?;": "static const u32 bbr_cwnd_min_target = 64;",
r"static const u32 bbr_full_bw_thresh = .*?;": "static const u32 bbr_full_bw_thresh = BBR_UNIT * 105 / 100;",
r"static const u32 bbr_full_bw_cnt = .*?;": "static const u32 bbr_full_bw_cnt = 8;",
r"static const int bbr_extra_acked_gain = .*?;": "static const int bbr_extra_acked_gain = BBR_UNIT * 2;",
r"static const u32 bbr_extra_acked_max_us = .*?;": "static const u32 bbr_extra_acked_max_us = 750 * 1000;",
r"static const bool bbr_precise_ece_ack = .*?;": "static const bool bbr_precise_ece_ack = true;",
r"static const u32 bbr_ecn_max_rtt_us = .*?;": "static const u32 bbr_ecn_max_rtt_us = 0;",
r"static const u32 bbr_beta = .*?;": "static const u32 bbr_beta = BBR_UNIT * 20 / 100;",
r"static const u32 bbr_ecn_alpha_gain = .*?;": "static const u32 bbr_ecn_alpha_gain = BBR_UNIT * 1 / 32;",
r"static const u32 bbr_ecn_alpha_init = .*?;": "static const u32 bbr_ecn_alpha_init = BBR_UNIT * 1 / 2;",
r"static const u32 bbr_ecn_factor = .*?;": "static const u32 bbr_ecn_factor = BBR_UNIT * 20 / 100;",
r"static const u32 bbr_ecn_thresh = .*?;": "static const u32 bbr_ecn_thresh = BBR_UNIT * 7 / 10;",
r"static const u32 bbr_ecn_reprobe_gain = .*?;": "static const u32 bbr_ecn_reprobe_gain = BBR_UNIT * 3 / 4;",
r"static const u32 bbr_loss_thresh = [^\n]*": "static const u32 bbr_loss_thresh = BBR_UNIT * 3 / 100; /* max: tolerate 3% loss before backing off */",
r"static const bool bbr_loss_probe_recovery = .*?;": "static const bool bbr_loss_probe_recovery = true;",
r"static const u32 bbr_full_loss_cnt = .*?;": "static const u32 bbr_full_loss_cnt = 8;",
r"static const u32 bbr_full_ecn_cnt = .*?;": "static const u32 bbr_full_ecn_cnt = 4;",
r"static const u32 bbr_inflight_headroom = .*?;": "static const u32 bbr_inflight_headroom = BBR_UNIT * 10 / 100;",
r"static const u32 bbr_bw_probe_cwnd_gain = .*?;": "static const u32 bbr_bw_probe_cwnd_gain = 2;",
r"static const u32 bbr_bw_probe_max_rounds = .*?;": "static const u32 bbr_bw_probe_max_rounds = 16;",
r"static const u32 bbr_bw_probe_rand_rounds = .*?;": "static const u32 bbr_bw_probe_rand_rounds = 2;",
r"static const u32 bbr_bw_probe_base_us = .*?;": "static const u32 bbr_bw_probe_base_us = 750 * 1000;",
r"static const u32 bbr_bw_probe_rand_us = .*?;": "static const u32 bbr_bw_probe_rand_us = 250 * 1000;",
}
missing = []
for pattern, replacement in replacements.items():
text, count = re.subn(pattern, replacement, text, count=1)
if count != 1:
missing.append(pattern)
pacing_pattern = re.compile(
r"static const int bbr_pacing_gain\[\] = \{\n"
r".*?\n"
r"\};",
re.S,
)
pacing_replacement = """static const int bbr_pacing_gain[] = {
\tBBR_UNIT * 3 / 2,\t/* UP: aggressive but keep BBR's feedback usable */
\tBBR_UNIT * 3 / 4,\t/* DOWN: drain the queue after probing */
\tBBR_UNIT,\t\t/* CRUISE: hold the measured pipe */
\tBBR_UNIT * 5 / 4,\t/* REFILL: refill faster than standard BBRv3 */
};"""
text, pacing_count = pacing_pattern.subn(pacing_replacement, text, count=1)
if pacing_count != 1:
missing.append("static const int bbr_pacing_gain[]")
if missing:
print("Failed to apply BBRv3 max profile; missing patterns:", file=sys.stderr)
for item in missing:
print(f" {item}", file=sys.stderr)
sys.exit(1)
path.write_text(text)
PY
grep -nE 'bbr_(startup_pacing_gain|startup_cwnd_gain|cwnd_gain|pacing_gain|beta|loss_thresh|full_loss_cnt|full_ecn_cnt|inflight_headroom|bw_probe_cwnd_gain|probe_rtt_mode_ms|pacing_margin_percent)' "$target"
echo "Applied BBRv3 max profile to $target"
-80
View File
@@ -1,80 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
kernel_version="${1:-}"
arch="${2:-$(uname -m)}"
repo_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
workdir="${BBRV3_MAX_WORKDIR:-$repo_root/kernel-max}"
if [[ -z "$kernel_version" ]]; then
raw_version=$(curl -fsSL https://www.kernel.org/finger_banner |
awk -F: '/latest stable version/ {gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2; exit}')
if [[ "$raw_version" =~ ^[0-9]+\.[0-9]+$ ]]; then
kernel_version="${raw_version}.0"
else
kernel_version="$raw_version"
fi
fi
case "$arch" in
aarch64|arm64)
build_arch="arm64"
config_arch="arm64"
;;
x86_64)
build_arch="x86_64"
config_arch="x86_64"
;;
*)
echo "Unsupported arch: $arch" >&2
exit 1
;;
esac
if ! [[ "$kernel_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Unexpected kernel version: $kernel_version" >&2
exit 1
fi
branch=$(echo "$kernel_version" | grep -oE '^[0-9]+\.[0-9]+')
mkdir -p "$workdir"
if [[ ! -d "$workdir/linux/.git" ]]; then
git clone --depth=1 --branch "linux-$branch.y" \
https://github.com/gregkh/linux.git "$workdir/linux"
fi
cd "$workdir/linux"
git fetch --depth=1 origin "linux-$branch.y"
git reset --hard FETCH_HEAD
git clean -fdx
bash "$repo_root/scripts/apply-bbrv3-port.sh"
bash "$repo_root/scripts/apply-bbrv3-max-profile.sh"
grep -v "MODULE_DESCRIPTION" net/ipv4/tcp_bbr.c > net/ipv4/tcp_bbr.c.tmp
mv net/ipv4/tcp_bbr.c.tmp net/ipv4/tcp_bbr.c
echo 'MODULE_DESCRIPTION("TCP BBR v3 Max - aggressive throughput profile by Joey");' >> net/ipv4/tcp_bbr.c
IFS='.' read -r v p s <<< "$kernel_version"
sed -i "s/^VERSION *=.*/VERSION = $v/" Makefile
sed -i "s/^PATCHLEVEL *=.*/PATCHLEVEL = $p/" Makefile
sed -i "s/^SUBLEVEL *=.*/SUBLEVEL = $s/" Makefile
export GITHUB_WORKSPACE="$repo_root"
export KERNEL_VERSION="$kernel_version"
bash "$repo_root/scripts/prepare-kernel-config.sh" "$config_arch"
if [[ "$build_arch" == "arm64" ]]; then
make ARCH=arm64 bindeb-pkg -j"$(nproc)" LOCALVERSION=-bbrv3-max KDEB_COMPRESS=gzip skipdbg=true
else
make bindeb-pkg -j"$(nproc)" LOCALVERSION=-bbrv3-max KDEB_COMPRESS=gzip skipdbg=true
fi
if find "$workdir" -maxdepth 1 \( -name '*-dbg*.deb' -o -name '*-dbgsym*.deb' \) | grep -q .; then
echo "ERROR: debug deb package was generated." >&2
find "$workdir" -maxdepth 1 \( -name '*-dbg*.deb' -o -name '*-dbgsym*.deb' \) -print >&2
exit 1
fi
find "$workdir" -maxdepth 1 -name 'linux-*.deb' -print | sort
+5 -6
View File
@@ -27,7 +27,10 @@ apply_policy_config() {
scripts/config --module NET_SCH_FQ_CODEL
scripts/config --module NET_SCH_PIE
scripts/config --module NET_SCH_FQ_PIE
scripts/config --module NET_SCH_CAKE
# CAKE built in (=y) so net.core.default_qdisc=cake works at boot without
# depending on module load timing. The kernel's compile-time default qdisc
# choice has no "cake" option, so the installer sets it via a sysctl drop-in.
scripts/config --enable NET_SCH_CAKE
scripts/config --disable DEFAULT_FQ_CODEL
scripts/config --disable DEFAULT_PFIFO_FAST
scripts/config --enable DEFAULT_FQ
@@ -98,7 +101,7 @@ validate_config() {
require_config_line 'CONFIG_NET_SCH_FQ_CODEL=m' 'CONFIG_NET_SCH_FQ_CODEL is not module-enabled.'
require_config_line 'CONFIG_NET_SCH_PIE=m' 'CONFIG_NET_SCH_PIE is not module-enabled.'
require_config_line 'CONFIG_NET_SCH_FQ_PIE=m' 'CONFIG_NET_SCH_FQ_PIE is not module-enabled.'
require_config_line 'CONFIG_NET_SCH_CAKE=m' 'CONFIG_NET_SCH_CAKE is not module-enabled.'
require_config_line 'CONFIG_NET_SCH_CAKE=y' 'CONFIG_NET_SCH_CAKE is not built in.'
require_config_line 'CONFIG_NET_SCH_DEFAULT=y' 'CONFIG_NET_SCH_DEFAULT is not enabled.'
require_config_line 'CONFIG_DEFAULT_FQ=y' 'CONFIG_DEFAULT_FQ is not enabled.'
require_config_line 'CONFIG_DEFAULT_NET_SCH="fq"' 'CONFIG_DEFAULT_NET_SCH is not fq.'
@@ -129,7 +132,3 @@ run_olddefconfig
apply_policy_config
run_olddefconfig
validate_config
mkdir -p "$GITHUB_WORKSPACE/build-configs"
cp .config "$GITHUB_WORKSPACE/build-configs/${arch}.config"
cp .config "$GITHUB_WORKSPACE/build-configs/${arch}-${KERNEL_VERSION}.config"