Repository: systemd/mkosi

Issue:
`virtio_net` & `net_failover` dependencies are missing
# Host

Distribution: Arch Linux
Kernel: Linux 6.7.6-arch1-2 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
Mkosi version: 20.2-2

# Description

Adding the `virtio_net` kernel module doesn't pull in the `net_failover` module, and after manually adding that dependency, `net_failover` then doesn't pull in the `failover` module. However, `modinfo` shows that these modules are marked as dependencies:

```
$ modinfo virtio_net
filename:       /lib/modules/6.7.6-arch1-2/kernel/drivers/net/virtio_net.ko.zst
license:        GPL
description:    Virtio network driver
srcversion:     1ABBECCCB19CAE57C48341E
alias:          virtio:d00000001v*
depends:        net_failover
retpoline:      Y
intree:         Y
name:           virtio_net
vermagic:       6.7.6-arch1-2 SMP preempt mod_unload 
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        7C:B1:91:12:73:44:33:30:08:24:A7:45:CB:9A:BA:59:3B:FE:74:E8
sig_hashalgo:   sha512
signature:      30:65:02:31:00:E7:79:24:6A:95:9A:75:B9:F0:55:75:A6:D4:FB:F2:
		99:95:50:88:97:47:F6:5A:00:06:B1:AE:99:09:EB:58:E8:01:28:4C:
		A0:7A:1D:03:AC:FE:B8:CB:BE:81:68:A3:FD:02:30:0C:06:BF:01:C4:
		E9:5C:63:A5:43:F3:9F:BB:EB:5E:7C:55:46:CA:DD:5B:7C:5B:D1:87:
		51:D7:13:60:F1:28:52:34:A9:C2:28:B5:65:9F:43:3E:E0:E5:04:58:
		73:A4:3A
parm:           napi_weight:int
parm:           csum:bool
parm:           gso:bool
parm:           napi_tx:bool

$ modinfo net_failover
filename:       /lib/modules/6.7.6-arch1-2/kernel/drivers/net/net_failover.ko.zst
license:        GPL v2
description:    Failover driver for Paravirtual drivers
srcversion:     DF2C47AF2AEAC55E208CB5C
depends:        failover
retpoline:      Y
intree:         Y
name:           net_failover
vermagic:       6.7.6-arch1-2 SMP preempt mod_unload 
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        7C:B1:91:12:73:44:33:30:08:24:A7:45:CB:9A:BA:59:3B:FE:74:E8
sig_hashalgo:   sha512
signature:      30:66:02:31:00:C8:32:7F:2E:4B:23:17:9C:3C:20:F6:23:60:01:B1:
		B6:4E:DD:87:AF:B7:22:5B:FE:3E:2C:50:95:0C:C6:2D:67:E8:C1:C0:
		AA:17:ED:A1:CF:DF:7B:79:94:DC:02:AF:0A:02:31:00:BB:46:BB:83:
		D0:EA:66:15:75:EA:A0:AB:E2:9F:E6:16:D3:18:DA:AE:F2:5C:B3:FB:
		1F:66:EE:FA:80:9F:29:AB:56:59:70:E6:61:9D:C8:5A:C1:88:D4:FA:
		83:80:16:50
	
$ modinfo failover
filename:       /lib/modules/6.7.6-arch1-2/kernel/net/core/failover.ko.zst
license:        GPL v2
description:    Generic failover infrastructure/interface
srcversion:     F62700FB66EE013904E93EB
depends:        
retpoline:      Y
intree:         Y
name:           failover
vermagic:       6.7.6-arch1-2 SMP preempt mod_unload 
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        7C:B1:91:12:73:44:33:30:08:24:A7:45:CB:9A:BA:59:3B:FE:74:E8
sig_hashalgo:   sha512
signature:      30:64:02:30:48:AF:9A:84:A2:0E:BA:65:95:80:48:BB:13:AF:48:91:
		5A:F5:FA:52:E3:02:D3:BE:62:68:B6:D3:E6:2C:7F:A6:63:08:EA:10:
		A6:68:28:C2:AC:CF:DC:D8:21:3A:14:11:02:30:18:BC:E6:CC:94:21:
		32:D5:AB:DC:C9:8A:5B:EA:E2:D4:F1:9D:FC:07:2D:90:67:D2:DE:3F:
		CD:6E:B7:D3:73:CD:37:B2:05:8F:1B:79:8C:21:38:F8:E3:45:47:B1:
		63:91
```

You can test this by using the following minimal config and running `lsinitrd mkosi.output/debug.efi | grep "failover"` on it.

# Config

```
[Distribution]
Distribution=arch

[Content]
KernelModulesExclude=.*
KernelModulesInclude=
	drivers/net/virtio_net.ko.zst
BuildSourcesEphemeral=yes
MakeInitrd=no
Bootloader=none
Timezone=Europe/London
Locale=en_GB.UTF-8
Packages=
	linux
	systemd

[Output]
Format=uki
ImageId=debug
```


Discussion:

Resolving patch:
diff --git a/mkosi/kmod.py b/mkosi/kmod.py
--- a/mkosi/kmod.py
+++ b/mkosi/kmod.py
@@ -53,8 +53,12 @@ def filter_kernel_modules(
     return sorted(modules)
 
 
+def normalize_module_name(name: str) -> str:
+    return name.replace("_", "-")
+
+
 def module_path_to_name(path: Path) -> str:
-    return path.name.partition(".")[0]
+    return normalize_module_name(path.name.partition(".")[0])
 
 
 def resolve_module_dependencies(
@@ -103,7 +107,7 @@ def resolve_module_dependencies(
             key, sep, value = line.partition("=")
 
         if key in ("depends", "softdep"):
-            depends += [d for d in value.strip().split(",") if d]
+            depends += [normalize_module_name(d) for d in value.strip().split(",") if d]
 
         elif key == "firmware":
             fw = [f for f in (root / "usr/lib/firmware").glob(f"{value.strip()}*")]
@@ -116,7 +120,7 @@ def resolve_module_dependencies(
             # The file names use dashes, but the module names use underscores. We track the names
             # in terms of the file names, since the depends use dashes and therefore filenames as
             # well.
-            name = value.strip().replace("_", "-")
+            name = normalize_module_name(value.strip())
 
             moddep[name] = depends
             firmwaredep[name] = firmware


Test patch: