Skip to content

Commit bcf976c

Browse files
committed
feat(kernel): publish kmod-nvidia-open and add packaging strategy doc
1 parent e71f493 commit bcf976c

1 file changed

Lines changed: 202 additions & 0 deletions

File tree

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Open Source Out-of-Tree Kernel Module Packaging Strategy — Azure Linux 4.0
2+
3+
## Overview
4+
5+
Azure Linux 4.0 builds out-of-tree kernel modules (kmods) as **subpackages of the kernel RPM** rather than as standalone packages. This ensures tight coupling between the kernel binary and its companion modules — eliminating version skew, simplifying dependency resolution, and guaranteeing that modules are always compiled against the exact kernel headers they will run on.
6+
7+
## Architecture
8+
consider kmod-nvidia-open as an example:
9+
```
10+
kernel.comp.toml
11+
├── build.defines.nvidia_open_version = "595.58.03"
12+
├── build.defines.nvidia_open_branch = "595"
13+
├── source-files[] → kernel tarball, NVIDIA tarball
14+
├── overlays
15+
│ ├── [nvidia-open sources] .inc, modprobe.conf (Source6000-6002)
16+
│ └── [nvidia-open phases] spec-append-lines × 5 phases
17+
18+
└── Resulting kernel.spec (after overlays)
19+
├── %description → %include kmod-nvidia-open.inc (phase=package)
20+
├── %prep → %include kmod-nvidia-open.inc (phase=prep)
21+
├── %build → %include kmod-nvidia-open.inc (phase=build)
22+
├── %install → %include kmod-nvidia-open.inc (phase=install)
23+
└── %files → %include kmod-nvidia-open.inc (phase=files)
24+
```
25+
26+
### Key Files
27+
28+
| File | Purpose |
29+
|------|---------|
30+
| `kmod-<name>.inc` | Self-contained subpackage definition with phase-gated `%if` blocks |
31+
| `kmod-<name>-modprobe.conf` | Module loading configuration (blacklists, options) |
32+
| `kernel.comp.toml` | Overlay definitions that wire everything together |
33+
34+
## Phase-Gated Include Pattern
35+
36+
RPM's `%include` directive is a preprocessor operation — it injects file contents literally into the spec at parse time. Since `%include` cannot appear inside macro bodies, we use a **phase-gating** pattern:
37+
38+
```spec
39+
# At each build phase, set the phase variable then include the kmod file:
40+
%global _kmod_phase build
41+
%global _kmod_name nvidia-open
42+
%include %{_sourcedir}/kmod-nvidia-open.inc
43+
```
44+
45+
Inside the `.inc` file, each section is guarded:
46+
47+
```spec
48+
%if "%{_kmod_phase}" == "build"
49+
# ... build commands ...
50+
%endif
51+
```
52+
53+
This allows a single `.inc` file to contain all phases of a kmod's lifecycle while only activating the relevant section at each point in the spec.
54+
55+
### Phase Execution Order
56+
57+
| Phase | Injection Point | Purpose |
58+
|-------|----------------|---------|
59+
| `package` | After `%description` | Declare `%package -n kmod-<name>-<branch>`, Provides, Requires |
60+
| `prep` | End of `%prep` | Extract kmod source tarball |
61+
| `build` | End of `%build` | Compile modules against kernel build tree |
62+
| `install` | End of `%install` | Install `.ko` files, configs, licenses |
63+
| `files` | After `%files modules-extra-matched` | `%post`/`%postun` scriptlets and file list |
64+
65+
## Naming and Versioning Strategy
66+
67+
Kmod subpackages include a **branch** suffix derived from the driver's major version: `kmod-<name>-<branch>`. For example, NVIDIA driver `595.58.03` with `nvidia_open_branch = "595"` produces `kmod-nvidia-open-595`.
68+
69+
This allows **multiple driver branches to coexist** — e.g., `kmod-nvidia-open-595` and a future `kmod-nvidia-open-600` can be installed side by side for different kernel versions or workloads.
70+
71+
The RPM Version/Release is inherited from the **kernel** (e.g., `kmod-nvidia-open-595-6.18.5-1.8.azl4.x86_64.rpm`). The actual driver version is tracked via virtual Provides:
72+
73+
```spec
74+
Provides: nvidia-open-kmod-version = %{nvidia_open_version}
75+
Provides: kmod-nvidia-open = %{version}-%{release}
76+
```
77+
78+
This means:
79+
- `Requires: kmod-nvidia-open` → gets any branch that matches the installed kernel
80+
- `Requires: kmod-nvidia-open-595` → pins to the 595 branch
81+
- `Requires: nvidia-open-kmod-version = 595.58.03` → pins to a specific driver version
82+
83+
Consumer packages (e.g., `nvidia-cuda-driver`) should use the virtual Provides, not the RPM version directly.
84+
85+
## Adding a New kmod
86+
87+
### 1. Create the `.inc` file
88+
89+
```
90+
base/comps/kernel/kmod-<name>.inc
91+
```
92+
93+
Use `kmod-nvidia-open.inc` as a template. Implement all 5 phases with `%if "%{_kmod_phase}" == "<phase>"` guards.
94+
95+
### 2. Create supporting files
96+
97+
- `kmod-<name>-modprobe.conf` — module loading config (blacklists, options)
98+
- Any patches specific to the kmod
99+
100+
### 3. Add build defines for version and branch
101+
102+
In `kernel.comp.toml`, add the driver version and branch defines:
103+
104+
```toml
105+
[components.kernel.build.defines]
106+
<name>_version = "1.0.0"
107+
<name>_branch = "1" # major version — becomes part of the RPM name
108+
```
109+
110+
The branch suffix enables multiple driver branches to coexist (e.g., `kmod-foo-1` and `kmod-foo-2`).
111+
112+
### 4. Add source-files entry (if external tarball needed)
113+
114+
```toml
115+
[[components.kernel.source-files]]
116+
filename = "my-module-1.0.tar.gz"
117+
hash = "..."
118+
hash-type = "SHA256"
119+
origin = { type = "download", uri = "https://..." }
120+
```
121+
122+
### 5. Add overlays to `kernel.comp.toml`
123+
124+
```toml
125+
# Source registration (use Source6100+ range for the new kmod)
126+
[[components.kernel.overlays]]
127+
description = "Add kmod-<name>.inc to sources"
128+
type = "file-add"
129+
file = "kmod-<name>.inc"
130+
source = "kmod-<name>.inc"
131+
132+
[[components.kernel.overlays]]
133+
description = "Register kmod-<name> tarball as Sourcexxxx"
134+
type = "spec-insert-tag"
135+
tag = "Sourcexxxx"
136+
value = "my-module-1.0.tar.gz"
137+
138+
[[components.kernel.overlays]]
139+
description = "Register kmod-<name>.inc as Sourcexxxx++"
140+
type = "spec-insert-tag"
141+
tag = "Sourcexxx++"
142+
value = "kmod-<name>.inc"
143+
144+
# Phase injection (repeat for each phase)
145+
[[components.kernel.overlays]]
146+
description = "Run kmod-<name> 'package' phase"
147+
type = "spec-append-lines"
148+
section = "%description"
149+
lines = [
150+
"",
151+
"%global _kmod_phase package",
152+
"%global _kmod_name <name>",
153+
"%include %{_sourcedir}/kmod-<name>.inc",
154+
]
155+
156+
# ... repeat for prep, build, install, files ...
157+
```
158+
159+
### 6. Validate
160+
161+
```bash
162+
azldev comp render -p kernel # Check overlays apply cleanly
163+
azldev comp build -p kernel # Full build + kmod compilation
164+
```
165+
166+
## Source Number Allocation
167+
168+
| Range | Reserved For |
169+
|-------|-------------|
170+
| 5000–5099 | AZL kernel configs and certificates |
171+
| 6000–6099 | kmod-nvidia-open |
172+
| 6100–6199 | (next kmod) |
173+
| 6200–6299 | (next kmod) |
174+
175+
## RPM Output
176+
177+
A successful kernel build produces (among others) the following RPMs, consider kmod-nvidia-open as an example:
178+
179+
```
180+
kernel-6.18.5-1.8.azl4.x86_64.rpm
181+
kernel-core-6.18.5-1.8.azl4.x86_64.rpm
182+
kernel-modules-6.18.5-1.8.azl4.x86_64.rpm
183+
kmod-nvidia-open-595-6.18.5-1.8.azl4.x86_64.rpm ← kmod subpackage (branch 595)
184+
```
185+
186+
The kmod RPM contains:
187+
- `/lib/modules/%{KVERREL}/extra/nvidia/*.ko.xz` — compressed kernel modules
188+
- `/etc/modprobe.d/kmod-nvidia-open-595.conf` — blacklist conflicting modules
189+
- `/etc/depmod.d/kmod-nvidia-open-595.conf` — depmod override configuration
190+
- `/usr/share/licenses/kmod-nvidia-open-595/COPYING` — license file
191+
192+
## Constraints and Limitations
193+
194+
1. **RPM `%include` is a preprocessor directive** — it cannot be used inside `%define`/`%global` macro bodies, generated from Lua, or made conditional at the `%include` line itself (the `%if` must be inside the included file).
195+
196+
2. **No parametric dispatch** — each kmod requires explicit `%global` + `%include` lines per phase. You cannot loop over kmod names with a single macro call due to the `%include` limitation above.
197+
198+
3. **Build time** — each additional kmod adds compilation time to the kernel build. The NVIDIA open modules add ~5-10 minutes to a ~25 minute kernel build.
199+
200+
4. **Module compression** — the kernel spec's `%post` processing compresses `.ko` files to `.ko.xz`. The `%files` section must reference the compressed names.
201+
202+
5. **Architecture restrictions** — use `%ifarch x86_64 aarch64` guards in prep/build/install phases to skip kmod work on architectures where the module is not supported.

0 commit comments

Comments
 (0)