Archived
Public Access
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:
+119
-116
@@ -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)."
|
||||
|
||||
@@ -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 registry(apt 源)**。安装脚本会自动识别架构、配置 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` secret;Gitea 实例需启用 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 key(Gitea 全包)。
|
||||
- 不做过渡期双发布。
|
||||
- 不按发行版分多 distribution。
|
||||
+130
-268
@@ -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 registry:apt 源 + 自动 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-package;sysctl 配置由 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"
|
||||
# 不加 -f:HTTP >= 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 把默认队列设为 cake;sch_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)也包含 meta(linux-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.conf(conffile)
|
||||
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"
|
||||
|
||||
Executable
+54
@@ -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"
|
||||
Executable
+38
@@ -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"
|
||||
Executable
+60
@@ -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"
|
||||
Reference in New Issue
Block a user