|
| 1 | +--- |
| 2 | +applyTo: 'SPECS*/**/*.spec' |
| 3 | +description: Always apply these instructions when editing `*.spec` files that build or repackage |
| 4 | +**out-of-tree (OOT) kernel modules**. Such specs are identifiable by the |
| 5 | +presence of `azl_kernel_*` macros (e.g., `azl_kernel_version`, |
| 6 | +`azl_kernel_hwe_version`). |
| 7 | +--- |
| 8 | + |
| 9 | +# Out-of-Tree (OOT) Kernel Module Spec File Conventions |
| 10 | + |
| 11 | +## Instructions context |
| 12 | + |
| 13 | +The specs to be analyzed with these instructions live under: |
| 14 | + |
| 15 | +- `SPECS-NVIDIA/` and `SPECS-AMD/` — **unsigned** (build) specs. |
| 16 | +- `SPECS-NVIDIA-SIGNED/` and `SPECS-AMD-SIGNED/` — **signed** (repackaging) specs. |
| 17 | + |
| 18 | +Above directory pairs are only examples - there may be additional directories for OOT specs, |
| 19 | +but they must follow the same conventions outlined in this document. |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## 1. Kernel and Dependency Version Macros |
| 24 | + |
| 25 | +### 1.1 Resolving the Target Kernel Version |
| 26 | + |
| 27 | +Always use the `azl_kernel_*` macros provided by the build system. **Never** use |
| 28 | +`rpm -q` shell queries to discover the kernel version at build time. |
| 29 | + |
| 30 | +- Example for the **default kernel**: |
| 31 | + |
| 32 | + ```rpm |
| 33 | + %global target_kernel_version_full %{azl_kernel_version}-%{azl_kernel_release}%{?dist} |
| 34 | + %global release_suffix _%{azl_kernel_version}.%{azl_kernel_release} |
| 35 | + ``` |
| 36 | + |
| 37 | +- Example for the **HWE kernel**: |
| 38 | + |
| 39 | + ```rpm |
| 40 | + %global target_kernel_version_full %{azl_kernel_hwe_version}-%{azl_kernel_hwe_release}%{?dist} |
| 41 | + %global release_suffix _%{azl_kernel_hwe_version}.%{azl_kernel_hwe_release} |
| 42 | + ``` |
| 43 | + |
| 44 | +### 1.2 Extending the Release Suffix with Additional Version Components |
| 45 | + |
| 46 | +When the OOT module is tied to both a specific kernel **and** another package |
| 47 | +version (e.g., an NVIDIA driver version), the release suffix may be extended: |
| 48 | + |
| 49 | +```rpm |
| 50 | +%global release_suffix _%{azl_kernel_version}.%{azl_kernel_release}.%{NVIDIA_DRIVER_VERSION} |
| 51 | +``` |
| 52 | + |
| 53 | +This is the exception, not the default. Use it only when the kernel module |
| 54 | +binary is specific to that additional dependency's exact version. |
| 55 | + |
| 56 | +### 1.3 Resolving Non-Kernel Package Version |
| 57 | + |
| 58 | +When the spec also depends on non-kernel packages (i.e., MOFED packages), resolve the version through the |
| 59 | +`azl_<pkg>_*` (i.e., `azl_mlnx_ofa_kernel_*`) macros: |
| 60 | + |
| 61 | +- For the **default kernel**: |
| 62 | + |
| 63 | + ```rpm |
| 64 | + %{!?_mofed_full_version: %define _mofed_full_version %{azl_mlnx_ofa_kernel_version}-%{azl_mlnx_ofa_kernel_release}%{?dist}} |
| 65 | + ``` |
| 66 | + |
| 67 | + Or simpler: |
| 68 | + ```rpm |
| 69 | + %define _mofed_full_version %{azl_mlnx_ofa_kernel_version}-%{azl_mlnx_ofa_kernel_release}%{?dist} |
| 70 | + ``` |
| 71 | + |
| 72 | +- For the **HWE kernel**: |
| 73 | + |
| 74 | + ```rpm |
| 75 | + %{!?_mofed_hwe_full_version: %define _mofed_hwe_full_version %{azl_mlnx_ofa_kernel_hwe_version}-%{azl_mlnx_ofa_kernel_hwe_release}%{?dist}} |
| 76 | + ``` |
| 77 | + |
| 78 | + Or simpler: |
| 79 | + ```rpm |
| 80 | + %define _mofed_hwe_full_version %{azl_mlnx_ofa_kernel_hwe_version}-%{azl_mlnx_ofa_kernel_hwe_release}%{?dist} |
| 81 | + ``` |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## 2. Release Tag Format |
| 86 | + |
| 87 | +### 2.1 Packages/Subpackages Containing OOT Modules |
| 88 | + |
| 89 | +```rpm |
| 90 | +Release: [number][kernel_version_related_suffix]%{?dist} |
| 91 | +``` |
| 92 | + |
| 93 | +Example from `gdrcopy-hwe-kmod` subpackage in `gdrcopy-hwe.spec`. |
| 94 | +```rpm |
| 95 | +Release: %{_release}_%{target_azl_build_kernel_version}.%{target_kernel_release}.%{NVIDIA_DRIVER_VERSION}%{?dist} |
| 96 | +``` |
| 97 | + |
| 98 | +### 2.2 Packages/Subpackages NOT Containing OOT Modules |
| 99 | + |
| 100 | +```rpm |
| 101 | +Release: [number]%{?dist} |
| 102 | +``` |
| 103 | + |
| 104 | +The `[kernel_version_related_suffix]` is **not needed** for subpackages that contain only |
| 105 | +kernel-independent components (usermode binaries, libraries, services, docs). |
| 106 | + |
| 107 | +Example from `gdrcopy` base subpackage in `gdrcopy.spec`. |
| 108 | +```rpm |
| 109 | +Release: %{_release}%{?dist} |
| 110 | +``` |
| 111 | + |
| 112 | +### 2.3 Reusing the Release Number Across Subpackages |
| 113 | + |
| 114 | +When the same release number must appear in multiple subpackages, encode it as a |
| 115 | +macro to avoid repetition: |
| 116 | + |
| 117 | +```rpm |
| 118 | +%{!?_release: %define _release 3} |
| 119 | +``` |
| 120 | + |
| 121 | +Then reference it in each `Release:` tag: |
| 122 | + |
| 123 | +```rpm |
| 124 | +# kmod subpackage (kernel-tied) |
| 125 | +Release: %{_release}%{release_suffix}%{?dist} |
| 126 | +
|
| 127 | +# service subpackage (kernel-independent) |
| 128 | +Release: %{_release}%{?dist} |
| 129 | +``` |
| 130 | + |
| 131 | +--- |
| 132 | + |
| 133 | +## 3. Subpackage Separation |
| 134 | + |
| 135 | +### 3.1 Principle |
| 136 | + |
| 137 | +Subpackages containing OOT kernel modules (`.ko` files) **must not** contain |
| 138 | +components that are not tied to a specific kernel version. Kernel-independent |
| 139 | +components include: |
| 140 | + |
| 141 | +- Usermode binaries and scripts. |
| 142 | +- Shared libraries (`.so` files). |
| 143 | +- Systemd service units. |
| 144 | +- udev rules. |
| 145 | +- Configuration files not specific to the kernel module. |
| 146 | +- Documentation and man pages. |
| 147 | + |
| 148 | +### 3.2 Reference Implementation |
| 149 | + |
| 150 | +The `gdrcopy` spec family is the current exemplar for proper separation: |
| 151 | + |
| 152 | +- `gdrcopy` — userspace library and test binaries. |
| 153 | +- `gdrcopy-service` — systemd service components. |
| 154 | +- `gdrcopy-dkms-src` — DKMS source for runtime compilation. |
| 155 | +- `gdrcopy-kmod` — prebuilt `gdrdrv.ko`, pinned to a specific kernel and NVIDIA |
| 156 | + driver version. |
| 157 | + |
| 158 | +### 3.3 Known Gap |
| 159 | + |
| 160 | +Most current specs (`cuda-open`, `cuda`, `amdgpu`, `amd-ama-driver`, |
| 161 | +`nvidia-vgpu-guest-driver`) bundle kernel modules and usermode components in a |
| 162 | +single package with `%{release_suffix}`. This is a known gap to be addressed in |
| 163 | +future refactoring. New specs **must** follow the separated pattern from the |
| 164 | +start. |
| 165 | + |
| 166 | +--- |
| 167 | + |
| 168 | +## 4. Unsigned / Signed Spec Pair |
| 169 | + |
| 170 | +Every OOT driver requires **two** specs: |
| 171 | + |
| 172 | +### 4.1 Unsigned Spec (Build) |
| 173 | + |
| 174 | +Located in `SPECS-NVIDIA/` or `SPECS-AMD/`. Responsibilities: |
| 175 | + |
| 176 | +- Compile kernel modules from source. |
| 177 | +- Install unsigned `.ko` files (useful for dev testing with kernel lockdown |
| 178 | + disabled). |
| 179 | +- Place unlinked `.o` / `.ko` files in `kmod_o_dir` to be picked up by the |
| 180 | + signing pipeline. |
| 181 | + |
| 182 | +### 4.2 Signed Spec (Repackaging) |
| 183 | + |
| 184 | +Located in `SPECS-NVIDIA-SIGNED/` or `SPECS-AMD-SIGNED/`. Responsibilities: |
| 185 | + |
| 186 | +- Take the unsigned RPM as `Source0`, referenced as |
| 187 | + `<name>-%{version}-%{release}.%{_arch}.rpm`. |
| 188 | +- Strip unsigned `.ko` files from the extracted contents. |
| 189 | +- Install signed `.ko` files provided as additional `Source` entries. |
| 190 | +- Repackage everything into the final RPM. |
| 191 | +- Repeat pre-/post-install scripts from the unsigned spec as needed for the subpackage they override from the unsigned spec. |
| 192 | + |
| 193 | +**Mandatory** in signed specs — prevent RPM post-processing from stripping |
| 194 | +module signatures: |
| 195 | + |
| 196 | +```rpm |
| 197 | +%define __os_install_post %{__os_install_post_leave_signatures} %{nil} |
| 198 | +``` |
| 199 | + |
| 200 | +Signed specs have an **empty `%build` section** — they never compile. |
| 201 | + |
| 202 | +--- |
| 203 | + |
| 204 | +## 5. Build and Runtime Dependencies |
| 205 | + |
| 206 | +### 5.1 Kernel Dependencies |
| 207 | + |
| 208 | +```rpm |
| 209 | +# Build-time |
| 210 | +BuildRequires: kernel-devel = %{target_kernel_version_full} |
| 211 | +BuildRequires: kernel-headers = %{target_kernel_version_full} |
| 212 | +
|
| 213 | +# Runtime |
| 214 | +Requires: kernel = %{target_kernel_version_full} |
| 215 | +``` |
| 216 | + |
| 217 | +For GPU drivers, also add: |
| 218 | + |
| 219 | +```rpm |
| 220 | +Requires: kernel-drivers-gpu = %{target_kernel_version_full} |
| 221 | +``` |
| 222 | + |
| 223 | +For **HWE kernel** variants, replace `kernel`/`kernel-devel` |
| 224 | +with `kernel-hwe`/`kernel-hwe-devel`, and |
| 225 | +`kernel-drivers-gpu` with `kernel-hwe-drivers-gpu`. |
| 226 | + |
| 227 | +> **⚠ BUILD-SYSTEM LIMITATION — `kernel-headers`:** |
| 228 | +> Only the default `kernel-headers` package may appear as a `BuildRequires`. |
| 229 | +> Flavored variants (e.g., `kernel-hwe-headers`) **must not** be used because |
| 230 | +> `kernel-headers` is always pre-installed in the build chroot and conflicts |
| 231 | +> with any other flavor of the headers package. This restriction does **not** |
| 232 | +> apply to `kernel-devel` — using `kernel-hwe-devel` is correct and required |
| 233 | +> for HWE builds. |
| 234 | +
|
| 235 | +### 5.2 MOFED Dependencies |
| 236 | + |
| 237 | +When InfiniBand / GPUDirect RDMA support is needed: |
| 238 | + |
| 239 | +```rpm |
| 240 | +BuildRequires: mlnx-ofa_kernel-devel = %{_mofed_full_version} |
| 241 | +BuildRequires: mlnx-ofa_kernel = %{_mofed_full_version} |
| 242 | +BuildRequires: mlnx-ofa_kernel-modules = %{_mofed_full_version} |
| 243 | +BuildRequires: mlnx-ofa_kernel-source = %{_mofed_full_version} |
| 244 | +
|
| 245 | +Requires: mlnx-ofa_kernel = %{_mofed_full_version} |
| 246 | +Requires: mlnx-ofa_kernel-modules = %{_mofed_full_version} |
| 247 | +``` |
| 248 | + |
| 249 | +For **HWE kernel** variants, use `mlnx-ofa_kernel-hwe-*` package names and |
| 250 | +`%{_mofed_hwe_full_version}`. |
| 251 | + |
| 252 | +--- |
| 253 | + |
| 254 | +## 6. Common Boilerplate |
| 255 | + |
| 256 | +### 6.1 Standard Tags |
| 257 | + |
| 258 | +```rpm |
| 259 | +Vendor: Microsoft Corporation |
| 260 | +Distribution: Azure Linux |
| 261 | +``` |
| 262 | + |
| 263 | +### 6.2 Changelog Format |
| 264 | + |
| 265 | +``` |
| 266 | +* Day Mon DD YYYY Full Name <email@microsoft.com> - VERSION-RELEASE |
| 267 | +- Description of change. |
| 268 | +``` |
| 269 | + |
| 270 | +Date format: `Day Mon DD YYYY` (e.g., `Tue Mar 24 2026`). |
| 271 | + |
| 272 | +--- |
| 273 | + |
| 274 | +## 7. HWE Kernel Variant Naming Cheat Sheet |
| 275 | + |
| 276 | +When creating an HWE variant of an existing spec, apply these substitutions |
| 277 | +throughout the entire spec: |
| 278 | + |
| 279 | +| Default kernel | HWE kernel | |
| 280 | +|---|---| |
| 281 | +| `%azl_kernel_version` | `%azl_kernel_hwe_version` | |
| 282 | +| `%azl_kernel_release` | `%azl_kernel_hwe_release` | |
| 283 | +| `%azl_mlnx_ofa_kernel_version` | `%azl_mlnx_ofa_kernel_hwe_version` | |
| 284 | +| `%azl_mlnx_ofa_kernel_release` | `%azl_mlnx_ofa_kernel_hwe_release` | |
| 285 | +| `kernel` (package name) | `kernel-hwe` | |
| 286 | +| `kernel-devel` | `kernel-hwe-devel` | |
| 287 | +| `kernel-headers` | ~~`kernel-hwe-headers`~~ — **do not substitute for `BuildRequires`** (see §5.1 limitation) | |
| 288 | +| `kernel-drivers-gpu` | `kernel-hwe-drivers-gpu` | |
| 289 | +| `mlnx-ofa_kernel-*` | `mlnx-ofa_kernel-hwe-*` | |
| 290 | +| `_mofed_full_version` | `_mofed_hwe_full_version` | |
| 291 | + |
| 292 | +--- |
| 293 | + |
| 294 | +## 8. Quick-Reference: Minimal Preamble Template |
| 295 | + |
| 296 | +```rpm |
| 297 | +%global _enable_debug_package 0 |
| 298 | +%global debug_package %{nil} |
| 299 | +%global __os_install_post /usr/lib/rpm/brp-compress %{nil} |
| 300 | +%global driver_version <DRIVER_VERSION> |
| 301 | +
|
| 302 | +%global target_kernel_version_full %{azl_kernel_version}-%{azl_kernel_release}%{?dist} |
| 303 | +%global release_suffix _%{azl_kernel_version}.%{azl_kernel_release} |
| 304 | +
|
| 305 | +# Only if MOFED is needed: |
| 306 | +%{!?_mofed_full_version: %define _mofed_full_version %{azl_mlnx_ofa_kernel_version}-%{azl_mlnx_ofa_kernel_release}%{?dist}} |
| 307 | +
|
| 308 | +Name: <package-name> |
| 309 | +Version: %{driver_version} |
| 310 | +Release: 1%{release_suffix}%{?dist} |
| 311 | +Summary: <summary> |
| 312 | +License: <license> |
| 313 | +Vendor: Microsoft Corporation |
| 314 | +Distribution: Azure Linux |
| 315 | +``` |
0 commit comments