Kernel modules in extensions
Use the kernel-version template
Section titled “Use the kernel-version template”Write kernel module packages like this:
extensions: usb-gadget: types: [sysext, confext] version: '1.1.0' packages: kernel-module-libcomposite-{{ avocado.kernel.version }}: '*' kernel-module-u-ether-{{ avocado.kernel.version }}: '*' kernel-module-usb-f-ncm-{{ avocado.kernel.version }}: '*'Don’t write the version out by hand, as in kernel-module-libcomposite-6.6.127-yocto-standard. That works until the next kernel bump, then the install fails with a package name nobody remembers choosing.
How the template gets its value:
- At install time, the CLI resolves one kernel version per sysroot. It uses the version pinned in
avocado.lockif there is one. Otherwise it applies anykernel.versionconstraint, or takes the highest version in the feed. - It substitutes that version into package keys. See Templating for exactly where.
- If a module no longer exists for that kernel,
avocado installfails and names the missing package. That’s a build-time failure, not a boot-time one.
The template has been in the CLI since 0.41.0.
Built-in modules still resolve
Section titled “Built-in modules still resolve”Some kernels build a module in (CONFIG_X=y) rather than as a separate package. Avocado’s kernel recipes use avocado-kernel-builtin-provides.bbclass, which makes the kernel package itself advertise every built-in module as both kernel-module-X and kernel-module-X-<kver>. So the templated name resolves whether the module is built in or not, and you don’t need to know which.
Real example: on the Jetson 6.6 kernel, libcomposite was built in according to meta-avocado’s current kernel config, but still shipped as a separate package in the 2024/edge snapshot 16 feed. The templated name worked in both cases.
Unversioned names
Section titled “Unversioned names”A bare kernel-module-foo: '*' also works in practice. Kernel module packages advertise an unversioned kernel-module-foo name, and the CLI hides every package that belongs to a kernel other than the pinned one (off_kernel_dnf_excludes). The published Jetson BSP extension relies on this, with entries like kernel-module-nvgpu: '*'. Prefer the template in your own extensions anyway. It’s explicit, it fails at install time instead of resolving to something unexpected, and it matches what Avocado’s own Tegra recipes do (their packagegroups spell out kernel-module-*-${KERNEL_VERSION}).
When the kernel changes
Section titled “When the kernel changes”When the kernel pin changes (after avocado unlock or avocado update, for example), the CLI wipes the affected extension, rootfs and initramfs sysroots and reinstalls them. That’s the only automatic cleanup the CLI does (see Build state), and it’s what keeps modules for the old kernel out of the image.
On the device
Section titled “On the device”- When an extension contains any
*.ko,*.ko.xzor*.ko.gzfile, the build automatically addsAVOCADO_ON_MERGE="depmod"to its release file.avocadoctlrunsdepmodafter every merge, so modules shipped in extensions can be found bymodprobe. modprobe: [foo]in an extension becomesAVOCADO_ON_MERGE="modprobe foo". It runs on every merge, afterdepmodand aftersystemctl daemon-reload, with the otheron_mergecommands (details). If it fails, you only get a warning. A service that needs the module should load it too, and fail clearly if it can’t.- A module with no hardware alias (
libcomposite, for example) is never loaded by udev, so something has to load it explicitly. Check withmodinfo -F alias <m>. - Kernel code that asks for a module at runtime (for example configfs creating
functions/ncm.usb0, which loadsusb_f_ncm) finds extension modules too, becausedepmodhas already run. modules-load.dfiles inside extensions don’t work at boot.systemd-modules-loadruns before extensions merge, and nothing re-runs it. Usemodprobe:instead. See Boot and extension merge.- Firmware is different. According to the Jetson BSP’s own notes, the kernel’s firmware loader fails with
-ELOOP(error 40) when it reads firmware through the sysext/usroverlay. That’s why Avocado ships Tegra GPU firmware in the rootfs, not the BSP extension. Plan on putting firmware you add in the rootfs too.