A DKMS source package for the lxin/quic
in-kernel QUIC implementation, packaged as a Debian .deb.
The package builds and installs only the production quic.ko module; it
does not install any user-space headers, the libquic user-space
library, or the upstream test modules.
Initial target: Debian Trixie / arm64 (the package itself is
Architecture: all; DKMS rebuilds the module on the user's system).
quic-dkms/
├── upstream/ git submodule -> https://github.com/lxin/quic
│ pinned to a specific upstream commit
├── debian/
│ ├── patches/ local patches applied on top of upstream/
│ │ ├── series patches applied in order, '#' = comment
│ │ └── *.patch paths relative to the package root
│ │ (e.g. upstream/modules/net/quic/socket.c)
│ ├── source/{format,options}
│ ├── rules debhelper sequence + DKMS install
│ └── ... (control, copyright, changelog, quic-dkms.dkms)
├── dkms/Makefile Top-level kbuild wrapper installed alongside
│ the module sources at /usr/src/quic-<ver>/
├── scripts/
│ ├── update-version.sh Compute / apply a new package version from
│ │ the upstream submodule's HEAD commit
│ └── make-orig.sh Produce the .orig.tar.xz from the working tree
├── .github/workflows/ CI: build amd64 + arm64 .debs and ship them
│ to a GitHub Release on every push to main
└── README.md
The upstream submodule is treated as read-only at rest -- any patches
we carry on top of the pinned commit live in debian/patches/, listed
in debian/patches/series (one filename per line, # and blank lines
ignored). Paths inside each patch are relative to the package root
(a/upstream/modules/..., b/upstream/modules/...), and they apply
with patch -p1.
Currently carried:
0001-path-detect-udp-tunnel-sock-api.patch— upstream chooses between the old (struct socket *) and new (struct sock *)udp_tunnelhelper prototypes with#ifdef RTEXT_FILTER_NAME_ONLY, an unrelated rtnetlink uapi macro used as a proxy for the mainline release that carried the conversion. Stable kernels that backport theudp_tunnelchange on its own (Debian's7.1.8+deb13) have the new prototypes but not that macro, so the old form is selected andpath.cfails to compile. The patch detects the declared prototype directly with__builtin_types_compatible_p()instead.
This is the standard 3.0 (quilt) layout, so:
dpkg-source --before-build(run automatically bydpkg-buildpackage) applies every patch inseriesto the working tree beforedebian/rulesruns.debian/rulesthen just copies the already-patchedupstream/modules/...into the DKMS source tree at/usr/src/quic-<upstream-version>/.dpkg-source --after-buildun-applies the patches (we setunapply-patchesindebian/source/options), so theupstream/submodule is left clean after every build.
To add a new patch:
# Bring upstream/ up to date.
git submodule update --init upstream
# Apply existing patches and start a quilt-managed new patch on top.
QUILT_PATCHES=debian/patches quilt push -a
QUILT_PATCHES=debian/patches quilt new 0002-my-fix.patch
QUILT_PATCHES=debian/patches quilt add upstream/modules/net/quic/<file>
# edit upstream/modules/net/quic/<file>
QUILT_PATCHES=debian/patches quilt refresh
QUILT_PATCHES=debian/patches quilt pop -a # leave upstream/ clean again(apt install quilt if needed.)
Package versions follow:
0~YYYYmmdd.NNNN.git+<short-hash>-<revision>
0~— fixed leading marker. The~makes the whole version sort before any future "real" upstream 0.x release in dpkg's ordering, so0~20260507....<0<0.1etc.YYYYmmdd— committer date (UTC) of the pinned upstream commitNNNN— 4-digit zero-padded snapshot counter (0000–9999), bumped by the maintainer when shipping a different snapshot of the same calendar day<short-hash>—git log -1 --format=%hof the pinned commit<revision>— Debian package revision counter, starting at1, bumped for packaging-only changes against the same upstream commit
Example: 0~20260507.0000.git+70ceda0-1. The everything-before-the-last
hyphen part (here 0~20260507.0000.git+70ceda0) is the upstream version,
and is what ends up in /usr/src/quic-<upstream-version>/. The trailing
-<revision> is the Debian revision and is not included in the DKMS
source dir name, so bumping it does not duplicate the on-disk source
tree.
This is a Debian quilt package (debian/source/format = 3.0 (quilt)),
so building requires both the Debian tree and a separately-generated
.orig.tar.xz (see "Building the .deb" below).
To bump to a new upstream commit:
git -C upstream fetch origin
git -C upstream checkout <new-commit-or-tag>
git add upstream
# default counter=0, revision=1; pass --counter / --revision to override
scripts/update-version.sh --update --message "..."
git commit -am "Bump upstream to <short-hash>"From the repo root, on Debian Trixie:
sudo apt install -y devscripts debhelper dh-dkms quilt rsync xz-utils
git submodule update --init --recursive
# Produce ../quic-dkms_<upstream-version>.orig.tar.xz from the working
# tree. This is required for 3.0 (quilt) builds; rerun after every
# changelog/version bump.
scripts/make-orig.sh
# Binary only:
dpkg-buildpackage -b -us -uc
# Or full set (binary + .dsc / .debian.tar.xz / *_source.changes):
dpkg-buildpackage -us -ucThe result, ../quic-dkms_<version>_all.deb, can be installed on any
Trixie system that has the matching linux-headers-* package.
A GitHub Actions workflow at .github/workflows/build-and-release.yml
performs this build on both amd64 and arm64 GitHub-hosted runners on
every push to main. In parallel, it also runs the upstream test
suite (upstream/tests/runtest.sh) on each architecture: the test
modules (quic_sample_test.ko) and user-space test binaries
(func_test, perf_test, alpn_test, ticket_test, sample_test)
are built from the patched upstream tree on the bare runner and the
full suite is exercised against the runner's live kernel. The HTTP/3
sub-suite is auto-skipped (no libnghttp3-dev installed in CI; it
otherwise reaches out to ~14 public websites and is too flaky for
CI), and the tlshd sub-suite is auto-skipped on runners without an
active tlshd daemon. Releases only publish if both the build and
the test jobs succeed on both architectures. None of these test
modules end up in the published .deb -- the DKMS source tree
installed by the package builds with CONFIG_IP_QUIC=m only, so
users only ever get quic.ko.
sudo apt install -y dkms linux-headers-arm64
sudo dpkg -i ../quic-dkms_<version>_all.deb
sudo modprobe quicDKMS will automatically rebuild quic.ko for every kernel that has
matching headers installed. The module is placed in
/lib/modules/<kver>/updates/quic.ko.
DKMS invokes the wrapper at /usr/src/quic-<ver>/Makefile, which calls
the upstream kbuild Makefile in net/quic/ with CONFIG_IP_QUIC=m.
Because CONFIG_IP_QUIC_TEST is intentionally left undefined, the
upstream test modules (quic_unit_test.ko, quic_sample_test.ko) are
not built.
The upstream module sources are GPL-2.0-or-later (see
upstream/COPYING); the Debian packaging in this repo is also
GPL-2.0-or-later. See debian/copyright for the full picture.