Skip to content

Commit 1d68dfa

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

1 file changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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+
├── source-files[] → kernel tarball, NVIDIA tarball
13+
├── overlays
14+
│ ├── [nvidia-open sources] .inc, modprobe.conf (Source6000-6002)
15+
│ └── [nvidia-open phases] spec-append-lines × 5 phases
16+
17+
└── Resulting kernel.spec (after overlays)
18+
├── %description → %include kmod-nvidia-open.inc (phase=package)
19+
├── %prep → %include kmod-nvidia-open.inc (phase=prep)
20+
├── %build → %include kmod-nvidia-open.inc (phase=build)
21+
├── %install → %include kmod-nvidia-open.inc (phase=install)
22+
└── %files → %include kmod-nvidia-open.inc (phase=files)
23+
```
24+
25+
### Key Files
26+
27+
| File | Purpose |
28+
|------|---------|
29+
| `kmod-<name>.inc` | Self-contained subpackage definition with phase-gated `%if` blocks |
30+
| `kmod-<name>-modprobe.conf` | Module loading configuration (blacklists, options) |
31+
| `kernel.comp.toml` | Overlay definitions that wire everything together |
32+
33+
## Phase-Gated Include Pattern
34+
35+
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:
36+
37+
```spec
38+
# At each build phase, set the phase variable then include the kmod file:
39+
%global _kmod_phase build
40+
%global _kmod_name nvidia-open
41+
%include %{_sourcedir}/kmod-nvidia-open.inc
42+
```
43+
44+
Inside the `.inc` file, each section is guarded:
45+
46+
```spec
47+
%if "%{_kmod_phase}" == "build"
48+
# ... build commands ...
49+
%endif
50+
```
51+
52+
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.
53+
54+
### Phase Execution Order
55+
56+
| Phase | Injection Point | Purpose |
57+
|-------|----------------|---------|
58+
| `package` | After `%description` | Declare `%package -n kmod-<name>-<version>`, Provides, Requires |
59+
| `prep` | End of `%prep` | Extract kmod source tarball |
60+
| `build` | End of `%build` | Compile modules against kernel build tree |
61+
| `install` | End of `%install` | Install `.ko` files, configs, licenses |
62+
| `files` | After `%files modules-extra-matched` | `%post`/`%postun` scriptlets and file list |
63+
64+
## Naming and Versioning Strategy
65+
66+
The driver version is embedded directly in the kmod subpackage name (e.g., `kmod-nvidia-open-595.58.03`).
67+
68+
The subpackage is declared as:
69+
70+
```spec
71+
%package -n kmod-%{_kmod_name}-%{nvidia_open_version}
72+
```
73+
74+
The RPM Version/Release is inherited from the **kernel** (e.g., `kmod-nvidia-open-595.58.03-6.18.5-1.8.azl4.x86_64.rpm`). The driver version is also exposed via virtual Provides so that consumers can depend on it without pinning the kernel version:
75+
76+
```spec
77+
Provides: nvidia-open-kmod-version = %{nvidia_open_version}
78+
Provides: nvidia-kmod = %{nvidia_open_version}
79+
Provides: kmod-nvidia-open = %{version}-%{release}
80+
```
81+
82+
This means:
83+
- `Requires: kmod-nvidia-open` → gets any driver version that matches the installed kernel
84+
- `Requires: kmod-nvidia-open-595.58.03` → pins to that specific driver version's RPM name
85+
- `Requires: nvidia-open-kmod-version = 595.58.03` → pins to a specific driver version via virtual Provides
86+
87+
Consumer packages (e.g., `nvidia-cuda-driver`) should use the virtual Provides, not the RPM version directly.
88+
89+
## Adding a New kmod
90+
91+
### 1. Create the `.inc` file
92+
93+
```
94+
base/comps/kernel/kmod-<name>.inc
95+
```
96+
97+
Use `kmod-nvidia-open.inc` as a template. Implement all 5 phases with `%if "%{_kmod_phase}" == "<phase>"` guards.
98+
99+
### 2. Create supporting files
100+
101+
- `kmod-<name>-modprobe.conf` — module loading config (blacklists, options)
102+
- Any patches specific to the kmod
103+
104+
### 3. Add build defines for version
105+
106+
In `kernel.comp.toml`, add the driver version define:
107+
108+
```toml
109+
[components.kernel.build.defines]
110+
<name>_version = "1.0.0" # driver version — becomes part of the RPM name
111+
```
112+
113+
The driver version is embedded directly in the subpackage name (e.g., `kmod-foo-1.0.0`), enabling multiple driver versions to coexist (e.g., `kmod-foo-1.0.0` and `kmod-foo-2.0.0`).
114+
115+
### 4. Add source-files entry (if external tarball needed)
116+
117+
```toml
118+
[[components.kernel.source-files]]
119+
filename = "my-module-1.0.tar.gz"
120+
hash = "..."
121+
hash-type = "SHA256"
122+
origin = { type = "download", uri = "https://..." }
123+
```
124+
125+
### 5. Add overlays to `kernel.comp.toml`
126+
127+
```toml
128+
# Source registration (use Source6100+ range for the new kmod)
129+
[[components.kernel.overlays]]
130+
description = "Add kmod-<name>.inc to sources"
131+
type = "file-add"
132+
file = "kmod-<name>.inc"
133+
source = "kmod-<name>.inc"
134+
135+
[[components.kernel.overlays]]
136+
description = "Register kmod-<name> tarball as Sourcexxxx"
137+
type = "spec-insert-tag"
138+
tag = "Sourcexxxx"
139+
value = "my-module-1.0.tar.gz"
140+
141+
[[components.kernel.overlays]]
142+
description = "Register kmod-<name>.inc as Sourcexxxx++"
143+
type = "spec-insert-tag"
144+
tag = "Sourcexxx++"
145+
value = "kmod-<name>.inc"
146+
147+
# Phase injection (repeat for each phase)
148+
[[components.kernel.overlays]]
149+
description = "Run kmod-<name> 'package' phase"
150+
type = "spec-append-lines"
151+
section = "%description"
152+
lines = [
153+
"",
154+
"%global _kmod_phase package",
155+
"%global _kmod_name <name>",
156+
"%include %{_sourcedir}/kmod-<name>.inc",
157+
]
158+
159+
# ... repeat for prep, build, install, files ...
160+
```
161+
162+
### 6. Validate
163+
164+
```bash
165+
azldev comp render -p kernel # Check overlays apply cleanly
166+
azldev comp build -p kernel # Full build + kmod compilation
167+
```
168+
169+
## Source Number Allocation
170+
171+
| Range | Reserved For |
172+
|-------|-------------|
173+
| 5000–5099 | AZL kernel configs and certificates |
174+
| 6000–6099 | kmod-nvidia-open |
175+
| 6100–6199 | (next kmod) |
176+
| 6200–6299 | (next kmod) |
177+
178+
## RPM Output
179+
180+
A successful kernel build produces (among others) the following RPMs, consider kmod-nvidia-open as an example:
181+
182+
```
183+
kernel-6.18.5-1.8.azl4.x86_64.rpm
184+
kernel-core-6.18.5-1.8.azl4.x86_64.rpm
185+
kernel-modules-6.18.5-1.8.azl4.x86_64.rpm
186+
kmod-nvidia-open-595.58.03-6.18.5-1.8.azl4.x86_64.rpm ← kmod subpackage (driver 595.58.03)
187+
```
188+
189+
The kmod RPM contains:
190+
- `/lib/modules/%{KVERREL}/extra/nvidia/*.ko.xz` — compressed kernel modules
191+
- `/etc/modprobe.d/kmod-nvidia-open-595.58.03.conf` — blacklist conflicting modules
192+
- `/etc/depmod.d/kmod-nvidia-open-595.58.03.conf` — depmod override configuration
193+
- `/usr/share/licenses/kmod-nvidia-open-595.58.03/COPYING` — license file
194+
195+
## Constraints and Limitations
196+
197+
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).
198+
199+
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.
200+
201+
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.
202+
203+
4. **Module compression** — the kernel spec's `%post` processing compresses `.ko` files to `.ko.xz`. The `%files` section must reference the compressed names.
204+
205+
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)