Distribute kernel via Gitea Debian apt repo; track stable not mainline

- Publish .deb packages to Gitea's built-in Debian registry (apt source)
  instead of Releases; CI uploads to pool/stable/main and stops creating
  Releases. One apt source line serves amd64 and arm64.
- Add linux-image-bbrv3 meta-package so `apt upgrade` tracks the latest
  stable kernel while older kernels stay installed for fallback. Its
  dependency is the actual built image package name (immune to localversion
  drift).
- Add bbrv3-config package shipping the BBR+CAKE+ECN sysctl drop-in as a
  conffile (applied via postinst), replacing the installer's sysctl write.
- Rewrite install.sh to add the apt source + signing key and install the
  meta package; keep the OS-version gate, status check and uninstall menu,
  plus an apt-mark hold escape hatch.
- select-stable-kernel.sh: pick the highest stable point release whose
  series is below mainline and has a matching BBRv3 patch, so a freshly-cut
  series (latest stable == mainline, e.g. 7.1) is not built. Currently 7.0.12.
- Exclude linux-libc-dev (clashes with the distro's headers) and drop the
  "by Joey" MODULE_DESCRIPTION step and release branding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-17 18:26:05 +08:00
parent d888a9700e
commit b8ccd431ea
7 changed files with 521 additions and 407 deletions
+119 -116
View File
@@ -1,9 +1,9 @@
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. arm64 is cross-compiled on the x86_64 runner
# This workflow targets a self-hosted Gitea instance. Kernel .deb packages are
# published to Gitea's built-in Debian package registry (an apt source), not to
# Releases. arm64 is cross-compiled on the x86_64 runner
# (CROSS_COMPILE=aarch64-linux-gnu-), so only a single ubuntu-latest runner is needed.
on:
@@ -13,14 +13,18 @@ on:
- cron: "17 3 * * *"
env:
# Gitea auto-injects GITHUB_TOKEN / GITEA_TOKEN into Actions jobs.
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gitea REST API base for this repo, e.g.
# https://git.chilldove.com/api/v1/repos/icePigeon/linux-kernel-bbrv3
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
# Gitea Debian package registry for this owner, e.g.
# https://git.chilldove.com/api/packages/icePigeon/debian
PKG_REGISTRY: ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/debian
PKG_USER: ${{ github.repository_owner }}
# Dedicated token with write:package scope. The auto-injected GITHUB_TOKEN is
# not guaranteed to carry package-write permission, so this is a repo secret.
PKG_TOKEN: ${{ secrets.PKG_TOKEN }}
permissions:
contents: write
# Uploads authenticate via the PKG_TOKEN secret, not the auto-injected token,
# so no write permission is requested here.
contents: read
concurrency:
group: bbrv3-kernel-build
@@ -31,59 +35,46 @@ jobs:
runs-on: ubuntu-latest
outputs:
kernel_version: ${{ steps.plan.outputs.kernel_version }}
raw_kernel_version: ${{ steps.plan.outputs.raw_kernel_version }}
build_needed: ${{ steps.plan.outputs.build_needed }}
steps:
- name: 查最新内核和已发布版本
- name: 出代码
uses: actions/checkout@v4
- name: 选择 stable 内核并检查 registry
id: plan
run: |
set -euo pipefail
raw_version=$(curl -fsSL https://www.kernel.org/finger_banner \
| awk -F: '/latest stable version/ {gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2; exit}')
if [ -z "$raw_version" ]; then
echo "Failed to read latest stable kernel version from kernel.org." >&2
exit 1
fi
version="$raw_version"
if [[ "$version" =~ ^[0-9]+\.[0-9]+$ ]]; then
version="${version}.0"
fi
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Unexpected stable kernel version: $raw_version" >&2
exit 1
fi
echo "raw_kernel_version=$raw_version" >> "$GITHUB_OUTPUT"
# Track an established stable series, never the freshly-cut top series
# that still equals mainline. See scripts/select-stable-kernel.sh.
version=$(bash scripts/select-stable-kernel.sh)
echo "Selected stable kernel: $version"
echo "kernel_version=$version" >> "$GITHUB_OUTPUT"
# Returns 0 when a release with the given tag already exists on Gitea.
release_exists() {
local tag="$1" code
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$tag" || echo 000)
[ "$code" = "200" ]
# Already-published check against the registry's apt index (per arch).
pkg_present() {
local debarch="$1"
curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$debarch/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$version-bbrv3$"
}
missing=0
for arch in x86_64 arm64; do
tag="$arch-$version"
if release_exists "$tag"; then
echo "$tag already exists."
for da in amd64 arm64; do
if pkg_present "$da"; then
echo "linux-image-$version-bbrv3 ($da) already in registry."
else
echo "$tag is missing."
echo "linux-image-$version-bbrv3 ($da) missing."
missing=1
fi
done
if [ "$missing" -eq 0 ]; then
echo "build_needed=false" >> "$GITHUB_OUTPUT"
echo "All releases for $version already exist; ending workflow before build."
else
if [ "$missing" -eq 1 ]; then
echo "build_needed=true" >> "$GITHUB_OUTPUT"
echo "At least one release for $version is missing; build will continue."
echo "At least one arch for $version is missing; build will continue."
else
echo "build_needed=false" >> "$GITHUB_OUTPUT"
echo "All arches for $version already published; ending before build."
fi
build:
@@ -94,39 +85,42 @@ jobs:
matrix:
include:
# Both targets build on a single x86_64 runner; arm64 is cross-compiled.
# is_primary builds the Architecture:all bbrv3-config package exactly once.
- arch: x86_64
deb_arch: amd64
runs_on: ubuntu-latest
cross_compile: ""
localversion: -bbrv3
is_primary: "true"
- arch: arm64
deb_arch: arm64
runs_on: ubuntu-latest
cross_compile: aarch64-linux-gnu-
localversion: -bbrv3
is_primary: "false"
runs-on: ${{ matrix.runs_on }}
env:
ARCH: ${{ matrix.arch }}
DEB_ARCH: ${{ matrix.deb_arch }}
KERNEL_VERSION: ${{ needs.preflight.outputs.kernel_version }}
steps:
- name: 查是否已发布
id: check_release
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
- name: 出代码
uses: actions/checkout@v4
- name: 检查 registry 是否已发布
id: check_present
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$TAG" || echo 000)
if [ "$code" = "200" ]; then
set -euo pipefail
if curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$DEB_ARCH/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$KERNEL_VERSION-bbrv3$"; then
echo "BUILD_NEEDED=false" >> "$GITHUB_ENV"
echo "$TAG already exists; skipping build."
echo "linux-image-$KERNEL_VERSION-bbrv3 ($DEB_ARCH) already published; skipping."
else
echo "BUILD_NEEDED=true" >> "$GITHUB_ENV"
echo "$TAG does not exist; building latest BBRv3 kernel."
echo "linux-image-$KERNEL_VERSION-bbrv3 ($DEB_ARCH) missing; building."
fi
- name: 检出代码
if: env.BUILD_NEEDED == 'true'
uses: actions/checkout@v4
- name: 安装依赖项
if: env.BUILD_NEEDED == 'true'
run: |
@@ -162,15 +156,6 @@ jobs:
bash "$GITHUB_WORKSPACE/scripts/apply-bbrv3-port.sh"
grep -n "BBR_VERSION" net/ipv4/tcp_bbr.c
- name: 编译声明
if: env.BUILD_NEEDED == 'true'
working-directory: ./kernel/linux
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
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 中的版本号
if: env.BUILD_NEEDED == 'true'
working-directory: ./kernel/linux
@@ -219,66 +204,84 @@ jobs:
fi
find ./kernel -maxdepth 1 -name 'linux-*.deb' -print | sort
- name: 发布前复查是否已发布
- name: 构建 meta 与 config 包
if: env.BUILD_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_API/releases/tags/$TAG" || echo 000)
if [ "$code" = "200" ]; then
echo "PUBLISH_NEEDED=false" >> "$GITHUB_ENV"
echo "$TAG was published while this job was running; skipping upload and release."
else
echo "PUBLISH_NEEDED=true" >> "$GITHUB_ENV"
echo "$TAG still missing; publishing this build."
fi
- name: 发布到 Gitea Release
if: env.BUILD_NEEDED == 'true' && env.PUBLISH_NEEDED == 'true'
env:
TAG: ${{ matrix.arch }}-${{ needs.preflight.outputs.kernel_version }}
TARGET_ARCH: ${{ matrix.arch }}
TARGET_SHA: ${{ github.sha }}
IS_PRIMARY: ${{ matrix.is_primary }}
run: |
set -euo pipefail
body="带有 BBRv3 的最新内核,适用于 $TARGET_ARCH 架构。Compiled & Optimized by Joey."
mkdir -p ./out
auth=(-H "Authorization: token $GITEA_TOKEN")
# Reuse an existing release for this tag, otherwise create it.
release_id=$(curl -sS "${auth[@]}" "$GITEA_API/releases/tags/$TAG" | jq -r '.id // empty')
if [ -z "$release_id" ]; then
release_id=$(curl -sS "${auth[@]}" \
-H "Content-Type: application/json" \
-X POST "$GITEA_API/releases" \
-d "$(jq -n \
--arg tag "$TAG" \
--arg target "$TARGET_SHA" \
--arg name "$TAG" \
--arg body "$body" \
'{tag_name:$tag, target_commitish:$target, name:$name, body:$body, draft:false, prerelease:false}')" \
| jq -r '.id // empty')
# Depend on the *actual* image package name, immune to localversion drift.
img_deb=$(find ./kernel -maxdepth 1 -name 'linux-image-*.deb' ! -name '*-dbg*' | sort | head -n1)
if [ -z "$img_deb" ]; then
echo "No linux-image .deb found to base the meta-package on." >&2
exit 1
fi
if [ -z "$release_id" ] || [ "$release_id" = "null" ]; then
echo "Failed to resolve or create Gitea release for $TAG" >&2
img_pkg=$(dpkg-deb -f "$img_deb" Package)
echo "Kernel image package: $img_pkg"
bash scripts/build-meta-package.sh "$KERNEL_VERSION" "$DEB_ARCH" "$img_pkg" ./out
# bbrv3-config is Architecture:all; build it once (on the primary arch).
if [ "$IS_PRIMARY" = "true" ]; then
bash scripts/build-config-package.sh ./out
fi
- name: 发布前复查是否已发布
if: env.BUILD_NEEDED == 'true'
run: |
set -euo pipefail
if curl -fsSL ${PKG_TOKEN:+--user "$PKG_USER:$PKG_TOKEN"} \
"$PKG_REGISTRY/dists/stable/main/binary-$DEB_ARCH/Packages" 2>/dev/null \
| grep -q "^Package: linux-image-$KERNEL_VERSION-bbrv3$"; then
echo "PUBLISH_NEEDED=false" >> "$GITHUB_ENV"
echo "Published while this job was running; skipping upload."
else
echo "PUBLISH_NEEDED=true" >> "$GITHUB_ENV"
echo "Still missing; publishing this build."
fi
- name: 发布到 Gitea Debian registry
if: env.BUILD_NEEDED == 'true' && env.PUBLISH_NEEDED == 'true'
run: |
set -euo pipefail
if [ -z "${PKG_TOKEN:-}" ]; then
echo "PKG_TOKEN secret is required to publish (needs write:package scope)." >&2
exit 1
fi
# Upload the kernel .deb packages as release assets.
# Gitea returns 201/202 on upload, 409 when the file already exists.
upload() {
local f="$1" code
code=$(curl -sS -o /dev/null -w '%{http_code}' \
--user "$PKG_USER:$PKG_TOKEN" --upload-file "$f" \
"$PKG_REGISTRY/pool/stable/main/upload" || echo 000)
case "$code" in
201|202) echo "Uploaded $(basename "$f") ($code)";;
409) echo "Already present $(basename "$f") (409)";;
*) echo "Upload failed: $(basename "$f") (HTTP $code)" >&2; return 1;;
esac
}
shopt -s nullglob
assets=( ./kernel/linux-*.deb )
if [ "${#assets[@]}" -eq 0 ]; then
echo "No .deb assets found to upload for $TAG" >&2
# Publish the kernel image and (x86_64) headers, plus the meta/config
# packages. Never linux-libc-dev (clashes with the distro's userspace
# headers) and never *-dbg* packages.
assets=()
for f in ./kernel/linux-image-*.deb ./kernel/linux-headers-*.deb; do
case "$f" in *-dbg*) continue;; esac
assets+=("$f")
done
assets+=( ./out/*.deb )
if [ ${#assets[@]} -eq 0 ]; then
echo "No .deb assets found to upload." >&2
exit 1
fi
for f in "${assets[@]}"; do
name=$(basename "$f")
echo "Uploading $name to release $TAG (id=$release_id)"
curl -fsS "${auth[@]}" \
-X POST "$GITEA_API/releases/$release_id/assets?name=$name" \
-F "attachment=@$f" >/dev/null
echo "Publishing $(basename "$f")"
upload "$f"
done
echo "Published $TAG with ${#assets[@]} asset(s)."
echo "Published ${#assets[@]} package(s) for $KERNEL_VERSION ($DEB_ARCH)."
+54 -23
View File
@@ -1,6 +1,6 @@
# 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 自动生效。
一个用于 Debian/Ubuntu VPS 的 BBRv3 内核分发方案。内核 `.deb` 包发布到本仓库自建 Gitea **Debian package registryapt 源)**。安装脚本会自动识别架构、配置 apt 源并安装 `linux-image-bbrv3` meta-package,之后 `sudo apt upgrade` 即可自动跟随最新 stable 内核(旧内核保留以便回退)。内核默认启用 BBR 拥塞控制并内置 `sch_cake`随包安装的 `bbrv3-config` 会写入 `/etc/sysctl.d/99-bbrv3.conf`,把默认队列算法设为 `cake` 并开启 ECN`net.ipv4.tcp_ecn=1`),安装并重启后 BBR + CAKE + ECN 自动生效。
脚本入口:
@@ -29,7 +29,7 @@ Debian testing/unstable 如缺少 `VERSION_ID`,脚本会按 `VERSION_CODENAME`
运行脚本后进入交互菜单:
```text
1. 安装或更新 BBR v3 内核(最新版)
1. 安装或更新 BBR v3 内核(最新版apt 源自动跟随
2. 安装指定版本
3. 检查 BBR v3 状态
4. 卸载 BBR v3 内核
@@ -40,19 +40,25 @@ Debian testing/unstable 如缺少 `VERSION_ID`,脚本会按 `VERSION_CODENAME`
本项目的构建目标是:
```text
BBRv3 补丁固定,内核自动跟随 kernel.org 最新 stable 更新。
BBRv3 补丁固定,内核自动跟随 kernel.org stable 的小版本更新。
```
也就是说,BBR 实现不会在自动构建时偷偷更新;自动更新的是 Linux stable 内核版本。构建流程会把仓库内固定的 BBRv3 patch 应用到最新 stable 内核上
BBR 实现不会在自动构建时偷偷更新;自动更新的是 Linux stable 内核的小版本。
当前 patch 选择规则
**追踪的是成熟 stable,而非 mainline。** 一个新系列(如 `7.1`)刚发布时,kernel.org 的 “latest stable” 会瞬间等于 “latest mainline”——那其实还是尖端,不是经过 `.z` 打磨的 stable。因此构建脚本(`scripts/select-stable-kernel.sh`)只在满足以下**全部**条件的版本里取最高
- 是带三段点号的点版本 `X.Y.Z`(排除刚发布、仅显示为 `X.Y` 的新系列);
- 系列 `X.Y` 严格低于当前 mainline(排除仍等于 mainline 的系列);
- 仓库存在对应的 `patches/bbrv3-linux-X.Y.patch`
当前 patch
```text
linux-7.0.y -> patches/bbrv3-linux-7.0.patch
linux-7.1.y -> patches/bbrv3-linux-7.1.patch
patches/bbrv3-linux-7.0.patch # linux-7.0.y
patches/bbrv3-linux-7.1.patch # linux-7.1.y
```
一主线系列内的小版本更新自动复用同一 patch,例`7.0.11 -> 7.0.12`。如果内核跳到新的主线系列但仓库内还没有对应 patch,构建会直接失败,避免产出不可验证的内核包
系列小版本更新自动复用同一 patch`7.0.11 -> 7.0.12`)。等新系列出了点版本、且 mainline 前移到再下一个系列,构建会自动接棒到新系列(前提是其 patch 已就位)
## 安装最新版
@@ -64,12 +70,19 @@ linux-7.1.y -> patches/bbrv3-linux-7.1.patch
脚本会:
- 检查系统是否为 Debian/Ubuntu,架构是否为 `x86_64``aarch64`
- 从 Gitea Releases 获取当前架构匹配的最新版本
- 下载内核 `.deb` 包,安装并更新引导配置
- 检查系统是否为 Debian/Ubuntu,架构是否为 `x86_64``aarch64`,并拦截过旧系统
- 配置 apt 源:导入 registry 签名公钥到 `/etc/apt/keyrings/`,写入 `/etc/apt/sources.list.d/bbrv3.list`
- `apt-get install linux-image-bbrv3` 安装/升级到最新 stable(旧内核保留以便回退)
- 提示是否重启。
如果访问私有仓库或遇到 Gitea API 限流,可先设置 token
之后无需再跑脚本,直接 `sudo apt update && sudo apt upgrade` 即可跟随最新内核。**不希望内核被 `apt upgrade` 自动更换**时
```bash
sudo apt-mark hold linux-image-bbrv3 # 钉死,停止自动跟随
sudo apt-mark unhold linux-image-bbrv3 # 解钉,恢复自动跟随
```
如果 registry 为私有或拉取签名公钥受限,可先设置 token 再运行:
```bash
export GITEA_TOKEN=你的 Gitea Token
@@ -84,15 +97,30 @@ bash <(curl -fsSL https://git.chilldove.com/icePigeon/linux-kernel-bbrv3/raw/bra
2. 安装指定版本
```
脚本会列出当前架构可用的 release tag,并按编号安装指定版本
脚本会列出 apt 源中可用的内核包并按编号安装;装完可选择 `apt-mark hold` 钉死,避免被 `apt upgrade` 自动更换
release tag 格式:
内核包名格式:
```text
x86_64-7.0.11
arm64-7.0.11
linux-image-7.0.12-bbrv3
```
也可手动安装:`sudo apt install linux-image-7.0.12-bbrv3`
## 手动配置 apt 源(不想用脚本)
```bash
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://git.chilldove.com/api/packages/icePigeon/debian/repository.key \
| sudo tee /etc/apt/keyrings/gitea-icePigeon.asc > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/gitea-icePigeon.asc] https://git.chilldove.com/api/packages/icePigeon/debian stable main" \
| sudo tee /etc/apt/sources.list.d/bbrv3.list > /dev/null
sudo apt update
sudo apt install linux-image-bbrv3
```
装完按需 `sudo reboot``bbrv3-config` 写入的 cake 默认队列需重启进新内核后才生效。
## 检查 BBRv3 状态
运行脚本后选择:
@@ -125,22 +153,25 @@ modinfo tcp_bbr 2>/dev/null | grep '^version:'
4. 卸载 BBR v3 内核
```
脚本会卸载由本项目安装的 BBR v3 内核包(包名带 `-bbrv3` 后缀),删除 `/etc/sysctl.d/99-bbrv3.conf`,并更新引导配置。卸载后建议重启。
脚本会卸载由本项目安装的内核包(`linux-image-*-bbrv3` 与 meta 包 `linux-image-bbrv3`)及 `bbrv3-config`purge 时带走 `/etc/sysctl.d/99-bbrv3.conf`,并移除 apt 源 `/etc/apt/sources.list.d/bbrv3.list` 与签名公钥;引导由内核包卸载钩子自动更新。卸载后建议重启。
## 内核包来源
`.deb` 内核包由 Gitea Actions 构建并发布到本仓库 Releases,提供 `x86_64``arm64` 两种标准 BBRv3 内核(arm64 在同一台 x86_64 runner 上交叉编译)。
`.deb` 内核包由 Gitea Actions 构建并发布到本仓库自建 Gitea 的 **Debian package registry**,提供 `amd64``arm64` 两种标准 BBRv3 内核(arm64 在同一台 x86_64 runner 上交叉编译)。一行 apt 源同时服务两种架构,apt 按本机架构自动取包。
构建流程会:
- 读取 kernel.org 最新 stable 版本
- 下载 `gregkh/linux` 对应 stable 分支。
- 应用仓库内固定 BBRv3 patch
- 默认启用 BBR,并把 `sch_cake` 编入内核(=y),安装脚本据此把默认队列设为 cake
- 关闭 debug info,拒绝发布 `*-dbg*.deb` / `*-dbgsym*.deb`
- `scripts/select-stable-kernel.sh` 选定要追踪的 stable 版本(见上文「内核与 BBR 策略」)
- 下载 `gregkh/linux` 对应 stable 分支,应用仓库内固定 BBRv3 patch
- 默认启用 BBR,并把 `sch_cake` 编入内核(=y);`bbrv3-config` 包据此把默认队列设为 cake
- 构建 `linux-image-bbrv3`meta,跟随最新)与 `bbrv3-config`sysctl 配置)两个辅助包
- 关闭 debug info,拒绝发布 `*-dbg*.deb` / `*-dbgsym*.deb`;不发布 `linux-libc-dev`(避免覆盖发行版头文件)
- 发布到 registry 的 `stable/main`,已存在的版本会跳过。
构建不会自动更新 BBR patch 本身。
发布所需:CI 配置一个有 `write:package` 权限的 `PKG_TOKEN` secretGitea 实例需启用 Packages → Debian registry。
## 免责声明
内核升级有风险。安装前建议确认 VPS 控制台、救援模式或旧内核启动项可用。使用本项目构建或安装的内核造成的系统启动失败、网络异常或数据损失,由使用者自行承担。
@@ -0,0 +1,66 @@
# BBRv3 内核分发改造:迁移到 Gitea Debian apt 源
日期:2026-06-17
状态:已确认,进入实现
## 背景与目标
当前分发链路是「Gitea Releases 存 `.deb` + `curl|bash` 安装脚本手动 `dpkg -i`」。
目标是改成 **apt 源**,让用户 `apt upgrade` 即可时刻跟随最新 stable 内核,并顺带提升
安全性(GPG 签名、保留旧内核可回退、apt 解依赖)。
构建层(CI 每天编译 `.deb`)保留不变;本次只替换**分发/更新层**。
## 关键决策
1. **分发层 = Gitea 自带 Debian package registry**(实例已自建 Gitea,自动 PGP 签名)。
- 上传:`PUT {server}/api/packages/{owner}/debian/pool/{dist}/{comp}/upload`
- 用户源:`deb [signed-by=…] {server}/api/packages/{owner}/debian stable main`
- 公钥:`{server}/api/packages/{owner}/debian/repository.key`
- 统一用 `stable/main` 一个桶;架构由 `.deb` 自带,apt 按 `amd64/arm64` 自动取。
2. **更新策略 = 自动跟最新**:构建 meta-package `linux-image-bbrv3``Depends` 当前最新
`linux-image-<ver>-bbrv3`,版本随内核版本走。`apt upgrade` 跟最新,**旧内核保留可回退**。
谨慎用户 `apt-mark hold linux-image-bbrv3` 钉死。
3. **sysctl 配置入包**:新增 `bbrv3-config``Architecture: all`),把
`/etc/sysctl.d/99-bbrv3.conf`BBR + CAKE + ECN)作为 conffile 随包安装,`postinst`
`sysctl --system`。装包即配置,不再依赖脚本。`meta` 依赖它。
4. **迁移 = 干净切换 + 保留入口**CI 只发 registry,停发 Releases`install.sh` 仍是同一
`curl|bash` 入口,菜单不变,动作改成 apt(加源 + 导 key + 装 meta)。
5. **只发 `linux-image` / `linux-headers`,排除 `linux-libc-dev`**(避免覆盖发行版 userspace
头文件)与 `*-dbg*`
## 本次新增需求(用户补充)
6. **追踪 stable 而非 mainline**。根因:7.1.0 刚发布时 kernel.org「latest stable」== mainline
== 7.1,旧 preflight 直接取它就抓到 7.1;成熟 stable 实为 7.0.12。
**修法**`scripts/select-stable-kernel.sh``finger_banner` 选「带三段点号 `X.Y.Z`
`X.Y` 严格 `<` mainline、且仓库存在 `patches/bbrv3-linux-X.Y.patch`」中的最高版本。
三段号排除刚发布的 `7.1`,patch 闸门排除无补丁的 6.x → 当前命中 `7.0.12`。系列自动接棒。
7. **删除 joey 标签**:移除 `build.yml` 的「编译声明」步骤(注入 `Compiled & Optimized by
Joey` 的 `MODULE_DESCRIPTION`),让上游 patch 自带描述生效;Release 发布块里的 joey 文案
随该块一并删除。
## 改动清单
- `scripts/select-stable-kernel.sh`(新)— 选 stable 目标版本。
- `scripts/build-config-package.sh`(新)— 构建 `bbrv3-config_*_all.deb`。
- `scripts/build-meta-package.sh`(新)— 构建 `linux-image-bbrv3_<ver>_<arch>.deb`,依赖项
取自实际产出的内核包名(`dpkg-deb -f`),避免 localversion 后缀漂移。
- `.github/workflows/build.yml`(改)— preflight 用选择脚本 + 查 registry index 判存在;删
joey 步骤;构建 meta/config;发布改 registry `--upload-file`;停发 Release。
- `install.sh`(改)— 菜单动作改 apt:加源/导 key/装 meta(1)、装指定版本(2)、状态检查
(3,不变)、卸载并删源(4)。保留 OS 版本闸门、依赖安装、sudo 兜底。
- `README.md`(改)— 改写「内核来源/BBR 策略/菜单」,新增 apt 用法与 `apt-mark hold`。
## 前提(落地前核对)
- `git.chilldove.com` 启用 Packages → Debian registry(新版 Gitea 默认开)。
- CI 需 `PKG_TOKEN` secret(有 `write:package` scope);自动注入的 `GITHUB_TOKEN` 不保证有
包写权限。
- registry 保留历史版本以支撑「装指定版本」;将来再议 retention。
## 不做(YAGNI
- 不搭 aptly/reprepro、不自管 GPG keyGitea 全包)。
- 不做过渡期双发布。
- 不按发行版分多 distribution。
+130 -268
View File
@@ -17,23 +17,29 @@ if ! command -v sudo &> /dev/null; then
fi
fi
# 检查并安装必要依赖(命令名与 apt 包名不一致时做映射
declare -A CMD_PKG=( [curl]=curl [wget]=wget [dpkg]=dpkg [awk]=gawk [jq]=jq [sysctl]=procps )
# 检查并安装必要依赖(apt 源方式只需 curl + ca-certificates
declare -A CMD_PKG=( [curl]=curl )
APT_UPDATED=0
ensure_pkg() {
local pkg="$1"
[[ "$APT_UPDATED" == "0" ]] && { sudo apt-get update > /dev/null 2>&1; APT_UPDATED=1; }
sudo apt-get install -y "$pkg" > /dev/null 2>&1
}
for cmd in "${!CMD_PKG[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
echo -e "\033[33m缺少依赖:$cmd,正在安装 ${CMD_PKG[$cmd]}...\033[0m"
[[ "$APT_UPDATED" == "0" ]] && { sudo apt-get update > /dev/null 2>&1; APT_UPDATED=1; }
sudo apt-get install -y "${CMD_PKG[$cmd]}" > /dev/null 2>&1
fi
done
# 关键依赖必须就绪,否则给出明确报错(而不是后续 jq/curl 的迷惑错误)
for cmd in curl wget jq; do
if ! command -v "$cmd" &> /dev/null; then
echo -e "\033[31m关键依赖 $cmd 安装失败,无法继续。请手动安装后重试。\033[0m"
exit 1
ensure_pkg "${CMD_PKG[$cmd]}"
fi
done
# HTTPS 根证书:apt update / 拉取签名公钥都需要
if ! dpkg -s ca-certificates &> /dev/null; then
echo -e "\033[33m缺少 ca-certificates,正在安装...\033[0m"
ensure_pkg ca-certificates
fi
if ! command -v curl &> /dev/null; then
echo -e "\033[31m关键依赖 curl 安装失败,无法继续。请手动安装后重试。\033[0m"
exit 1
fi
# 检测系统架构
ARCH=$(uname -m)
@@ -42,76 +48,27 @@ if [[ "$ARCH" != "aarch64" && "$ARCH" != "x86_64" ]]; then
exit 1
fi
# Gitea 仓库坐标(自建实例 git.chilldove.com
# Gitea 仓库 / Debian package registry 坐标(自建实例 git.chilldove.com
GITEA_HOST="https://git.chilldove.com"
GITEA_OWNER="icePigeon"
GITEA_REPO="linux-kernel-bbrv3"
# Gitea Releases API
RELEASES_API="$GITEA_HOST/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/releases"
# 可选:访问私有仓库或提升 Gitea API 限额(支持 GITEA_TOKEN / GITHUB_TOKEN / GH_TOKEN
GITEA_API_TOKEN="${GITEA_TOKEN:-${GITHUB_TOKEN:-${GH_TOKEN:-}}}"
# 安装后写入的默认网络栈配置(BBR 拥塞控制 + CAKE 队列)
# Gitea 自带 Debian registryapt 源 + 自动 PGP 签名
REG_BASE="$GITEA_HOST/api/packages/$GITEA_OWNER/debian"
REG_DIST="stable"
REG_COMP="main"
KEYRING="/etc/apt/keyrings/gitea-$GITEA_OWNER.asc"
SOURCE_LIST="/etc/apt/sources.list.d/bbrv3.list"
# 跟随最新 stable 的 meta-packagesysctl 配置由 bbrv3-config 包负责
META_PKG="linux-image-bbrv3"
SYSCTL_DROPIN="/etc/sysctl.d/99-bbrv3.conf"
# 可选:访问私有仓库时给拉取签名公钥用(支持 GITEA_TOKEN / GITHUB_TOKEN / GH_TOKEN
GITEA_API_TOKEN="${GITEA_TOKEN:-${GITHUB_TOKEN:-${GH_TOKEN:-}}}"
api_get() {
local url="$1"
# 不加 -fHTTP >= 400 时保留 JSON 错误体({"message":...}),交给
# check_release_api_response 解析并给出 token 提示;网络层失败仍会非零退出。
if [[ -n "$GITEA_API_TOKEN" ]]; then
curl -sSL \
-H "Authorization: token $GITEA_API_TOKEN" \
-H "Accept: application/json" \
"$url"
# 把 uname -m 映射成 Debian 架构名(apt 用 amd64/arm64
get_deb_arch() {
if [[ "$ARCH" == "aarch64" ]]; then
echo "arm64"
else
curl -sSL "$url"
fi
}
# 分页拉取全部 release(Gitea 单页上限为 50),合并成一个 JSON 数组返回
fetch_all_releases() {
local page=1 combined="[]" data count
while :; do
data=$(api_get "$RELEASES_API?limit=50&page=$page") || return 1
# 出错或非数组(例如 {"message":...})时原样返回,交给 check_release_api_response 处理
if ! echo "$data" | jq -e 'type=="array"' > /dev/null 2>&1; then
printf '%s' "$data"
return 0
fi
count=$(echo "$data" | jq 'length')
combined=$(jq -n --argjson a "$combined" --argjson b "$data" '$a + $b')
[ "$count" -lt 50 ] && break
page=$((page + 1))
[ "$page" -gt 20 ] && break
done
printf '%s' "$combined"
}
# 下载 release 资源;存在 token 时带上鉴权头以支持私有仓库
wget_asset() {
local url="$1"
if [[ -n "$GITEA_API_TOKEN" ]]; then
wget -q --show-progress --header="Authorization: token $GITEA_API_TOKEN" "$url" -P /tmp/
else
wget -q --show-progress "$url" -P /tmp/
fi
}
check_release_api_response() {
local response="$1"
local api_message=""
api_message=$(echo "$response" | jq -r 'if type=="object" then .message // "" else "" end')
if [[ -n "$api_message" ]]; then
echo -e "\033[31mGitea API 返回错误:$api_message\033[0m"
if echo "$api_message" | grep -qiE "rate limit|not found|permission|unauthor"; then
echo -e "\033[33m提示:私有仓库或受限访问可先执行 export GITEA_TOKEN=你的令牌,再重新运行脚本。\033[0m"
fi
return 1
fi
if ! echo "$response" | jq -e 'type=="array"' > /dev/null 2>&1; then
echo -e "\033[31mGitea API 返回数据格式异常,无法继续。\033[0m"
return 1
echo "amd64"
fi
}
@@ -180,222 +137,136 @@ assert_supported_kernel_install_system() {
fi
}
# 返回当前已安装的标准 BBRv3 内核版本(忽略遗留的 -max 包
get_installed_version() {
dpkg -l 2>/dev/null \
| awk '/^ii/ && $2 ~ /^linux-image-/ && $2 ~ /-bbrv3$/ {sub(/^linux-image-/, "", $2); print $2}' \
| sort -V | tail -n 1
}
# 函数:配置 apt 源(导入签名公钥 + 写 sources.list + apt update
setup_apt_source() {
echo -e "\033[36m正在配置 BBRv3 apt 源...\033[0m"
sudo install -d -m 0755 /etc/apt/keyrings
# 把 uname -m 映射成 release tag 的架构前缀
get_arch_filter() {
if [[ "$ARCH" == "aarch64" ]]; then
echo "arm64"
elif [[ "$ARCH" == "x86_64" ]]; then
echo "x86_64"
# 拉取 Gitea registry 的签名公钥(armored,可直接用作 signed-by
local key_args=()
[[ -n "$GITEA_API_TOKEN" ]] && key_args=(-H "Authorization: token $GITEA_API_TOKEN")
if ! curl -fsSL "${key_args[@]}" "$REG_BASE/repository.key" | sudo tee "$KEYRING" > /dev/null; then
echo -e "\033[31m下载仓库签名公钥失败:$REG_BASE/repository.key\033[0m"
echo -e "\033[33m提示:私有仓库可先 export GITEA_TOKEN=你的令牌 再重试。\033[0m"
return 1
fi
}
# 由 release tag(如 x86_64-7.0.12)推导已安装包应有的版本串
get_expected_installed_version() {
local tag="$1"
local version
version="${tag#x86_64-}"
version="${version#arm64-}"
echo "${version}-bbrv3"
}
# 函数:智能更新引导加载程序
update_bootloader() {
echo -e "\033[36m正在更新引导加载程序...\033[0m"
if command -v update-grub &> /dev/null; then
echo -e "\033[33m检测到 GRUB,正在执行 update-grub...\033[0m"
if sudo update-grub; then
echo -e "\033[1;32mGRUB 更新成功!\033[0m"
return 0
else
echo -e "\033[1;31mGRUB 更新失败!\033[0m"
return 1
fi
else
echo -e "\033[33m未找到 'update-grub'。您的系统可能使用 U-Boot 或其他引导程序。\033[0m"
echo -e "\033[33m在许多 ARM 系统上,内核安装包会自动处理引导更新,通常无需手动操作。\033[0m"
echo -e "\033[33m如果重启后新内核未生效,您可能需要手动更新引导配置,请参考您系统的文档。\033[0m"
return 0
fi
}
# 函数:安装后写入默认网络栈(BBR + CAKE + ECN)。内核编译期默认队列没有 cake 选项,
# 因此用 sysctl drop-in 把默认队列设为 cakesch_cake 已内置,重启进新内核后生效。
apply_default_network_stack() {
if sudo tee "$SYSCTL_DROPIN" > /dev/null <<'EOF'
# Managed by linux-kernel-bbrv3 installer
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_ecn = 1
EOF
then
echo -e "\033[1;32m✔ 已写入默认网络栈配置(BBR + CAKE + ECN):$SYSCTL_DROPIN\033[0m"
# 当前内核若已支持则立即生效;否则仅写入,重启进新内核后生效。
sudo sysctl -p "$SYSCTL_DROPIN" > /dev/null 2>&1 || true
else
echo -e "\033[33m提示:写入 $SYSCTL_DROPIN 失败,可手动设置 net.core.default_qdisc=cake。\033[0m"
fi
}
# 函数:安全地安装下载的包
install_packages() {
if ! ls /tmp/linux-*.deb &> /dev/null; then
echo -e "\033[31m错误:未在 /tmp 目录下找到内核文件,安装中止。\033[0m"
if [[ ! -s "$KEYRING" ]]; then
echo -e "\033[31m签名公钥为空,无法继续。\033[0m"
return 1
fi
for deb_file in /tmp/linux-*.deb; do
if ! dpkg-deb -I "$deb_file" > /dev/null 2>&1; then
echo -e "\033[31m当前系统无法读取安装包:$deb_file\033[0m"
echo -e "\033[33m可能原因:dpkg 版本过旧,不支持该压缩格式。建议升级 dpkg 后重试。\033[0m"
return 1
fi
done
echo "deb [signed-by=$KEYRING] $REG_BASE $REG_DIST $REG_COMP" | sudo tee "$SOURCE_LIST" > /dev/null
echo -e "\033[1;32m✔ 已写入 apt 源:$SOURCE_LIST\033[0m"
echo -e "\033[36m开始卸载旧版内核... \033[0m"
INSTALLED_PACKAGES=$(dpkg -l | grep -- '-bbrv3' | awk '{print $2}' | tr '\n' ' ')
if [[ -n "$INSTALLED_PACKAGES" ]]; then
sudo apt-get remove --purge $INSTALLED_PACKAGES -y > /dev/null 2>&1
fi
echo -e "\033[36m开始安装新内核... \033[0m"
if sudo dpkg -i /tmp/linux-*.deb && update_bootloader; then
echo -e "\033[1;32m内核安装并配置完成!\033[0m"
apply_default_network_stack
echo -n -e "\033[33m需要重启系统来加载新内核。是否立即重启? (y/n): \033[0m"
read -r REBOOT_NOW
if [[ "$REBOOT_NOW" == "y" || "$REBOOT_NOW" == "Y" ]]; then
echo -e "\033[36m系统即将重启...\033[0m"
sudo reboot
else
echo -e "\033[33m操作完成。请记得稍后手动重启 ('sudo reboot') 来应用新内核。\033[0m"
fi
else
echo -e "\033[1;31m内核安装或引导更新失败!系统可能处于不稳定状态。请不要重启并寻求手动修复!\033[0m"
if ! sudo apt-get update; then
echo -e "\033[31mapt-get update 失败,请检查网络或 registry 是否可访问。\033[0m"
return 1
fi
}
# 函数:检查并安装最新版本
# 函数:提示重启
prompt_reboot() {
echo -n -e "\033[33m需要重启系统来加载新内核。是否立即重启? (y/N): \033[0m"
read -r REBOOT_NOW
if [[ "$REBOOT_NOW" == "y" || "$REBOOT_NOW" == "Y" ]]; then
echo -e "\033[36m系统即将重启...\033[0m"
sudo reboot
else
echo -e "\033[33m操作完成。请记得稍后手动重启 ('sudo reboot') 来应用新内核。\033[0m"
fi
}
# 函数:安装或更新到最新版(meta-package 自动跟随最新 stable
install_latest_version() {
local arch_filter
local expected_version
assert_supported_kernel_install_system || return 1
setup_apt_source || return 1
echo -e "\033[36m正在从 Gitea 获取最新版本信息...\033[0m"
RELEASE_DATA=$(fetch_all_releases)
if [[ -z "$RELEASE_DATA" ]]; then
echo -e "\033[31m从 Gitea 获取版本信息失败。请检查网络连接或 API 状态。\033[0m"
echo -e "\033[36m正在安装/升级 $META_PKG(自动跟随最新 stable,旧内核会保留以便回退)...\033[0m"
# 内核包的 postinst 会自动更新引导(update-grub / kernel-install),无需手动处理;
# bbrv3-config 的 postinst 会写入并应用 BBR + CAKE + ECN 的 sysctl 配置。
if sudo apt-get install -y "$META_PKG"; then
echo -e "\033[1;32m内核安装并配置完成!默认网络栈:BBR + CAKE + ECN。\033[0m"
echo -e "\033[33m如不希望以后 apt upgrade 自动更换内核,可执行:sudo apt-mark hold $META_PKG\033[0m"
prompt_reboot
else
echo -e "\033[1;31m内核安装失败!系统未变更内核,可重试或检查上面的 apt 报错。\033[0m"
return 1
fi
check_release_api_response "$RELEASE_DATA" || return 1
arch_filter=$(get_arch_filter)
LATEST_TAG_NAME=$(echo "$RELEASE_DATA" | jq -r --arg filter "$arch_filter" '
map(
select(.tag_name | test("^" + $filter + "-[0-9]"; "i"))
| select(.tag_name | endswith("-max") | not)
)
| sort_by(.published_at)
| .[-1].tag_name
')
if [[ -z "$LATEST_TAG_NAME" || "$LATEST_TAG_NAME" == "null" ]]; then
echo -e "\033[31m未找到适合当前架构 ($ARCH) 的最新版本。\033[0m"
return 1
fi
echo -e "\033[36m检测到最新版本:\033[0m\033[1;32m$LATEST_TAG_NAME\033[0m"
INSTALLED_VERSION=$(get_installed_version)
echo -e "\033[36m当前已安装版本:\033[0m\033[1;32m${INSTALLED_VERSION:-"未安装"}\033[0m"
expected_version=$(get_expected_installed_version "$LATEST_TAG_NAME")
if [[ -n "$INSTALLED_VERSION" && "$INSTALLED_VERSION" == "$expected_version" ]]; then
echo -e "\033[1;32m(o'▽'o) 您已安装最新 BBR v3 内核,无需更新!\033[0m"
return 0
fi
echo -e "\033[33m发现新版本或未安装内核,准备下载...\033[0m"
ASSET_URLS=$(echo "$RELEASE_DATA" | jq -r --arg tag "$LATEST_TAG_NAME" '
.[] | select(.tag_name == $tag) | .assets[].browser_download_url
| select(test("(-dbg_|-dbgsym_)"; "i") | not)
')
rm -f /tmp/linux-*.deb
for URL in $ASSET_URLS; do
echo -e "\033[36m正在下载文件:$URL\033[0m"
wget_asset "$URL" || { echo -e "\033[31m下载失败:$URL\033[0m"; return 1; }
done
install_packages
}
# 函数:安装指定版本
# 函数:安装指定版本(从 apt 源里选一个具体的内核版本)
install_specific_version() {
local arch_filter
assert_supported_kernel_install_system || return 1
setup_apt_source || return 1
RELEASE_DATA=$(fetch_all_releases)
if [[ -z "$RELEASE_DATA" ]]; then
echo -e "\033[31m从 Gitea 获取版本信息失败。请检查网络连接或 API 状态。\033[0m"
return 1
fi
check_release_api_response "$RELEASE_DATA" || return 1
echo -e "\033[36m正在从 apt 源获取可用版本...\033[0m"
# 列出仓库中所有带版本号的 BBRv3 内核包(排除无版本号的 meta 包本身)
mapfile -t PKGS < <(apt-cache pkgnames 2>/dev/null \
| grep -E '^linux-image-[0-9].+-bbrv3$' | sort -V)
arch_filter=$(get_arch_filter)
MATCH_TAGS=$(echo "$RELEASE_DATA" | jq -r --arg filter "$arch_filter" '
.[]
| select(.tag_name | test("^" + $filter + "-[0-9]"; "i"))
| select(.tag_name | endswith("-max") | not)
| .tag_name
')
if [[ -z "$MATCH_TAGS" ]]; then
echo -e "\033[31m未找到适合当前架构的可用版本。\033[0m"
if [[ ${#PKGS[@]} -eq 0 ]]; then
echo -e "\033[31m仓库中未找到可用的 BBRv3 内核版本。\033[0m"
return 1
fi
echo -e "\033[36m以下为适用于当前架构的可用版本:\033[0m"
IFS=$'\n' read -rd '' -a TAG_ARRAY <<<"$MATCH_TAGS"
for i in "${!TAG_ARRAY[@]}"; do
echo -e "\033[33m $((i+1)). ${TAG_ARRAY[$i]}\033[0m"
echo -e "\033[36m以下为可用的内核版本:\033[0m"
for i in "${!PKGS[@]}"; do
echo -e "\033[33m $((i+1)). ${PKGS[$i]}\033[0m"
done
echo -n -e "\033[36m请输入要安装的版本编号(例如 1):\033[0m"
read -r CHOICE
if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || (( CHOICE < 1 || CHOICE > ${#TAG_ARRAY[@]} )); then
if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || (( CHOICE < 1 || CHOICE > ${#PKGS[@]} )); then
echo -e "\033[31m输入无效编号,取消操作。\033[0m"
return 1
fi
INDEX=$((CHOICE-1))
SELECTED_TAG="${TAG_ARRAY[$INDEX]}"
echo -e "\033[36m已选择版本:\033[0m\033[1;32m$SELECTED_TAG\033[0m"
local pkg="${PKGS[$((CHOICE-1))]}"
echo -e "\033[36m已选择:\033[0m\033[1;32m$pkg\033[0m"
ASSET_URLS=$(echo "$RELEASE_DATA" | jq -r --arg tag "$SELECTED_TAG" '
.[] | select(.tag_name == $tag) | .assets[].browser_download_url
| select(test("(-dbg_|-dbgsym_)"; "i") | not)
')
if sudo apt-get install -y "$pkg"; then
echo -e "\033[1;32m已安装 $pkg。\033[0m"
# 装指定版本通常是想钉死,提示如何阻止 apt 自动更换内核
if dpkg -s "$META_PKG" &> /dev/null; then
echo -n -e "\033[33m检测到已安装 $META_PKG,是否钉死当前内核、阻止 apt upgrade 自动更换? (y/N): \033[0m"
read -r HOLD_NOW
if [[ "$HOLD_NOW" == "y" || "$HOLD_NOW" == "Y" ]]; then
sudo apt-mark hold "$META_PKG" "$pkg"
echo -e "\033[1;32m已钉死:$META_PKG $pkg(解钉:sudo apt-mark unhold ...\033[0m"
fi
fi
prompt_reboot
else
echo -e "\033[1;31m安装 $pkg 失败!请检查上面的 apt 报错。\033[0m"
return 1
fi
}
rm -f /tmp/linux-*.deb
# 函数:卸载本项目安装的所有内容(内核包 + meta + config),并移除 apt 源
uninstall_bbrv3() {
# 带 -bbrv3 后缀的包既包含具体内核(linux-image-7.0.x-bbrv3)也包含 metalinux-image-bbrv3
local pkgs
pkgs=$(dpkg -l 2>/dev/null | awk '/^ii/ && $2 ~ /-bbrv3$/ {print $2}' | tr '\n' ' ')
pkgs+=" $(dpkg -s bbrv3-config &> /dev/null && echo bbrv3-config)"
pkgs=$(echo "$pkgs" | xargs) # 规整空白
for URL in $ASSET_URLS; do
echo -e "\033[36m下载中:$URL\033[0m"
wget_asset "$URL" || { echo -e "\033[31m下载失败:$URL\033[0m"; return 1; }
done
if [[ -n "$pkgs" ]]; then
echo -e "\033[36m将要卸载以下包:\033[33m$pkgs\033[0m"
# 内核包 postrm 钩子会自动更新引导;purge 会带走 99-bbrv3.confconffile
sudo apt-get remove --purge -y $pkgs
else
echo -e "\033[33m未找到由本项目安装的 BBRv3 内核包。\033[0m"
fi
install_packages
# 移除 apt 源与签名公钥
if [[ -f "$SOURCE_LIST" || -f "$KEYRING" ]]; then
sudo rm -f "$SOURCE_LIST" "$KEYRING"
echo -e "\033[36m已移除 apt 源与签名公钥。\033[0m"
sudo apt-get update > /dev/null 2>&1 || true
fi
# 兜底清理可能残留的 sysctl drop-in(旧版脚本写入、或非 conffile 情形)
sudo rm -f "$SYSCTL_DROPIN"
echo -e "\033[1;32m卸载完成。请记得重启系统。\033[0m"
}
# 美化输出的分隔线
@@ -411,7 +282,7 @@ echo -e "\033[1;35m(☆ω☆)✧*。 欢迎使用 BBR v3 内核安装脚本 ✧*
print_separator
echo -e "\033[1;33m╭( ・ㅂ・)و ✧ 你可以选择以下操作哦:\033[0m"
echo -e "\033[33m 1. 🚀 安装或更新 BBR v3 内核(最新版)\033[0m"
echo -e "\033[33m 1. 🚀 安装或更新 BBR v3 内核(最新版apt 源自动跟随\033[0m"
echo -e "\033[33m 2. 📚 安装指定版本\033[0m"
echo -e "\033[33m 3. 🔍 检查 BBR v3 状态\033[0m"
echo -e "\033[33m 4. 🗑️ 卸载 BBR v3 内核\033[0m"
@@ -469,16 +340,7 @@ case "$ACTION" in
;;
4)
echo -e "\033[1;32mヽ(・∀・) 您选择了卸载 BBR v3 内核!\033[0m"
PACKAGES_TO_REMOVE=$(dpkg -l | grep -- '-bbrv3' | awk '{print $2}' | tr '\n' ' ')
if [[ -n "$PACKAGES_TO_REMOVE" ]]; then
echo -e "\033[36m将要卸载以下内核包: \033[33m$PACKAGES_TO_REMOVE\033[0m"
sudo apt-get remove --purge $PACKAGES_TO_REMOVE -y
sudo rm -f "$SYSCTL_DROPIN"
update_bootloader
echo -e "\033[1;32m内核包已卸载。请记得重启系统。\033[0m"
else
echo -e "\033[33m未找到由本脚本安装的 BBR v3 内核包。\033[0m"
fi
uninstall_bbrv3
;;
*)
echo -e "\033[31m( ̄▽ ̄)ゞ 无效的选项,请输入 1-4 之间的数字哦~\033[0m"
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Build the bbrv3-config package (Architecture: all): ships the BBR + CAKE + ECN
# sysctl drop-in so installing the kernel configures the network stack with no
# installer script. The meta-package depends on it.
set -euo pipefail
out_dir=${1:?usage: build-config-package.sh <output_dir> [version]}
version=${2:-1.0}
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
pkgdir="$work/bbrv3-config"
mkdir -p "$pkgdir/DEBIAN" "$pkgdir/etc/sysctl.d"
cat > "$pkgdir/etc/sysctl.d/99-bbrv3.conf" <<'EOF'
# Managed by the bbrv3-config package (linux-kernel-bbrv3).
# BBR congestion control + CAKE default qdisc + ECN.
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_ecn = 1
EOF
# conffile: dpkg preserves local edits to the drop-in across upgrades.
echo "/etc/sysctl.d/99-bbrv3.conf" > "$pkgdir/DEBIAN/conffiles"
cat > "$pkgdir/DEBIAN/control" <<EOF
Package: bbrv3-config
Version: $version
Architecture: all
Maintainer: linux-kernel-bbrv3
Depends: procps
Section: net
Priority: optional
Description: Default network stack (BBR + CAKE + ECN) for BBRv3 kernels
Ships /etc/sysctl.d/99-bbrv3.conf so the BBRv3 kernel boots with BBR
congestion control, the CAKE default qdisc and ECN enabled.
EOF
cat > "$pkgdir/DEBIAN/postinst" <<'EOF'
#!/bin/sh
set -e
if [ "$1" = "configure" ]; then
# Applies now if the running kernel supports it; otherwise the settings take
# effect on the next boot into the BBRv3 kernel (sch_cake is built in there).
sysctl --system >/dev/null 2>&1 || true
fi
EOF
chmod 0755 "$pkgdir/DEBIAN/postinst"
mkdir -p "$out_dir"
dpkg-deb --build --root-owner-group "$pkgdir" \
"$out_dir/bbrv3-config_${version}_all.deb"
echo "Built $out_dir/bbrv3-config_${version}_all.deb"
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Build the linux-image-bbrv3 meta-package. It depends on a specific built kernel
# package plus bbrv3-config, so `apt upgrade` tracks the newest BBRv3 kernel while
# previously installed kernels stay around for fallback.
#
# The dependency is the *actual* produced package name (passed in), not a guessed
# one, so any localversion/suffix drift from the kernel build can't break it.
set -euo pipefail
meta_version=${1:?usage: build-meta-package.sh <meta_version> <deb_arch> <depends_pkg> <out_dir>}
arch=${2:?missing deb arch (amd64|arm64)}
depends_pkg=${3:?missing kernel image package name to depend on}
out_dir=${4:?missing output dir}
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
pkgdir="$work/meta"
mkdir -p "$pkgdir/DEBIAN"
cat > "$pkgdir/DEBIAN/control" <<EOF
Package: linux-image-bbrv3
Version: $meta_version
Architecture: $arch
Maintainer: linux-kernel-bbrv3
Depends: $depends_pkg, bbrv3-config
Section: kernel
Priority: optional
Description: BBRv3 kernel (tracks the latest stable build)
Meta-package pulling in the newest BBRv3 kernel built by this project
($depends_pkg) plus the bbrv3-config network defaults. Run
'apt-mark hold linux-image-bbrv3' to pin your kernel and stop auto-tracking.
EOF
mkdir -p "$out_dir"
dpkg-deb --build --root-owner-group "$pkgdir" \
"$out_dir/linux-image-bbrv3_${meta_version}_${arch}.deb"
echo "Built $out_dir/linux-image-bbrv3_${meta_version}_${arch}.deb"
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# Print the kernel version this project should build.
#
# We track an established *stable* series, never the bleeding edge. Right after a
# new series N.M is released, kernel.org's "latest stable version" flips to "N.M"
# and equals "latest mainline version" — that is mainline, not a baked stable.
# So we select the highest three-component point release (X.Y.Z) whose series X.Y
# is strictly below mainline AND has a matching BBRv3 patch in this repo:
# - three components exclude the freshly-cut top series (shown as "N.M");
# - the "< mainline" test excludes a series that still equals mainline;
# - the patch gate excludes series we cannot port BBRv3 onto (e.g. LTS 6.x).
# The series advances automatically once the next one matures and mainline moves on.
set -euo pipefail
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
repo_root=$(cd -- "$script_dir/.." && pwd)
FINGER_URL="${FINGER_URL:-https://www.kernel.org/finger_banner}"
banner=$(curl -fsSL "$FINGER_URL")
if [ -z "$banner" ]; then
echo "Failed to fetch $FINGER_URL" >&2
exit 1
fi
# Mainline major.minor, stripping any -rcN suffix: "7.1" or "7.2-rc1" -> "7.1"/"7.2".
mainline_mm=$(printf '%s\n' "$banner" \
| grep -i 'latest mainline version' \
| grep -oE '[0-9]+\.[0-9]+' | head -n1)
if [ -z "$mainline_mm" ]; then
echo "Could not parse mainline version from finger_banner." >&2
exit 1
fi
# Every three-component point release mentioned in the banner (stable + longterm),
# ascending and de-duplicated. Two-component entries like a just-released "7.1"
# are intentionally not matched here.
mapfile -t candidates < <(printf '%s\n' "$banner" \
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | sort -V -u)
# strictly_less A B -> true when A < B under version sort.
strictly_less() {
[ "$1" != "$2" ] && [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]
}
target=""
for v in "${candidates[@]}"; do
mm=${v%.*} # 7.0.12 -> 7.0
strictly_less "$mm" "$mainline_mm" || continue
[ -f "$repo_root/patches/bbrv3-linux-$mm.patch" ] || continue
target="$v" # candidates ascending: keep highest match
done
if [ -z "$target" ]; then
echo "No stable series below mainline $mainline_mm has a BBRv3 patch in patches/." >&2
echo "Point releases seen: ${candidates[*]:-none}" >&2
exit 1
fi
printf '%s\n' "$target"