Skip to content

Conversation

@cdesiniotis
Copy link
Collaborator

@cdesiniotis cdesiniotis commented Nov 11, 2025

Rather than always binding GPUs to the vfio-pci driver, this commit
introduces logic to see if the running kernel has a VFIO variant
driver available that is a better match for the device. This is required
on Grace-based systems where the nvgrace_gpu_vfio_pci module is required
to be used in favor of the vfio-pci module.

We read the mod.alias file for a given device, then we look through
/lib/modules/${kernel_version}/modules.alias for the vfio_pci alias
that matches with the least number of wildcard ('*') fields.

The code introduced in this commit is inspired by:

https://gitlab.com/libvirt/libvirt/-/commit/82e2fac297105f554f57fb589002933231b4f711

Depends on #127

Testing

On a GB200 compute tray:

# cat /sys/bus/pci/devices/0019\:01\:00.0/modalias 
pci:v000010DEd00002941sv000010DEsd00002046bc03sc02i00

# grep "v000010DEd00002941" /lib/modules/$(uname -r)/modules.alias
alias vfio_pci:v000010DEd00002941sv*sd*bc*sc*i* nvgrace_gpu_vfio_pci

# ./vfio-manage bind -a
INFO[2025-11-25T01:56:36Z] Binding device 0008:01:00.0                  
INFO[2025-11-25T01:56:36Z] Binding device 0008:01:00.0 to driver: nvgrace_gpu_vfio_pci 
INFO[2025-11-25T01:56:36Z] Binding device 0009:01:00.0                  
INFO[2025-11-25T01:56:36Z] Binding device 0009:01:00.0 to driver: nvgrace_gpu_vfio_pci 
INFO[2025-11-25T01:56:36Z] Binding device 0018:01:00.0                  
INFO[2025-11-25T01:56:36Z] Binding device 0018:01:00.0 to driver: nvgrace_gpu_vfio_pci 
INFO[2025-11-25T01:56:36Z] Binding device 0019:01:00.0                  
INFO[2025-11-25T01:56:36Z] Binding device 0019:01:00.0 to driver: nvgrace_gpu_vfio_pci 

# lspci -nnk -d 10de:2941
0008:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel driver in use: nvgrace_gpu_vfio_pci
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0009:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel driver in use: nvgrace_gpu_vfio_pci
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0018:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel driver in use: nvgrace_gpu_vfio_pci
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0019:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel driver in use: nvgrace_gpu_vfio_pci
        Kernel modules: nvidiafb, nvidia_drm, nvidia
        
# ./vfio-manage unbind -a
INFO[2025-11-25T01:59:56Z] Unbinding device 0008:01:00.0                
INFO[2025-11-25T01:59:56Z] Unbinding device 0009:01:00.0                
INFO[2025-11-25T01:59:56Z] Unbinding device 0018:01:00.0                
INFO[2025-11-25T01:59:56Z] Unbinding device 0019:01:00.0

# lspci -nnk -d 10de:2941
0008:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0009:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0018:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel modules: nvidiafb, nvidia_drm, nvidia
0019:01:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2941] (rev a1)
        Subsystem: NVIDIA Corporation Device [10de:2046]
        Kernel modules: nvidiafb, nvidia_drm, nvidia

On a system with one L40 (configured in graphics mode) and one L4 GPU:

# ./vfio-manage bind --all
INFO[2025-11-25T02:00:35Z] Binding device 0000:17:00.0                  
INFO[2025-11-25T02:00:35Z] Binding device 0000:17:00.0 to driver: vfio-pci 
INFO[2025-11-25T02:00:35Z] Binding graphics auxiliary device 0000:17:00.1 to driver: vfio-pci 
INFO[2025-11-25T02:00:35Z] Binding device 0000:3d:00.0                  
INFO[2025-11-25T02:00:35Z] Binding device 0000:3d:00.0 to driver: vfio-pci

# lspci -nnk -d 10de:
17:00.0 VGA compatible controller [0300]: NVIDIA Corporation AD102GL [L40] [10de:26b5] (rev a1)
        Subsystem: NVIDIA Corporation AD102GL [L40] [10de:169d]
        Kernel driver in use: vfio-pci
        Kernel modules: nvidiafb, nouveau
17:00.1 Audio device [0403]: NVIDIA Corporation AD102 High Definition Audio Controller [10de:22ba] (rev a1)
        Subsystem: NVIDIA Corporation AD102 High Definition Audio Controller [10de:169d]
        Kernel driver in use: vfio-pci
        Kernel modules: snd_hda_intel
3d:00.0 3D controller [0302]: NVIDIA Corporation AD104GL [L4] [10de:27b8] (rev a1)
        Subsystem: NVIDIA Corporation AD104GL [L4] [10de:16ca]
        Kernel driver in use: vfio-pci
        Kernel modules: nvidiafb, nouveau

# ./vfio-manage unbind --all
INFO[2025-11-25T02:01:08Z] Unbinding device 0000:17:00.0                
INFO[2025-11-25T02:01:08Z] Unbinding device 0000:3d:00.0 

# lspci -nnk -d 10de:
17:00.0 VGA compatible controller [0300]: NVIDIA Corporation AD102GL [L40] [10de:26b5] (rev a1)
        Subsystem: NVIDIA Corporation AD102GL [L40] [10de:169d]
        Kernel modules: nvidiafb, nouveau
17:00.1 Audio device [0403]: NVIDIA Corporation AD102 High Definition Audio Controller [10de:22ba] (rev a1)
        Subsystem: NVIDIA Corporation AD102 High Definition Audio Controller [10de:169d]
        Kernel modules: snd_hda_intel
3d:00.0 3D controller [0302]: NVIDIA Corporation AD104GL [L4] [10de:27b8] (rev a1)
        Subsystem: NVIDIA Corporation AD104GL [L4] [10de:16ca]
        Kernel modules: nvidiafb, nouveau

@coveralls
Copy link

coveralls commented Nov 11, 2025

Pull Request Test Coverage Report for Build 20018055700

Details

  • 84 of 213 (39.44%) changed or added relevant lines in 4 files are covered.
  • 3 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+6.5%) to 6.486%

Changes Missing Coverage Covered Lines Changed/Added Lines %
cmd/vfio-manage/bind.go 0 4 0.0%
cmd/vfio-manage/unbind.go 0 4 0.0%
internal/nvpci/modalias.go 84 122 68.85%
internal/nvpci/nvpci.go 0 83 0.0%
Files with Coverage Reduction New Missed Lines %
internal/nvpci/nvpci.go 3 0.0%
Totals Coverage Status
Change from base Build 19868800624: 6.5%
Covered Lines: 84
Relevant Lines: 1295

💛 - Coveralls

@cdesiniotis cdesiniotis force-pushed the support-variant-vfio-modules branch 2 times, most recently from fcfa6cf to 7829c7f Compare November 18, 2025 18:48
Comment on lines 208 to 256
modAliasPath := filepath.Join(d.Path, "modalias")
modAliasContent, err := os.ReadFile(modAliasPath)
if err != nil {
return "", fmt.Errorf("failed to read modalias file for %s: %w", d.Address, err)
}

modAliasStr := strings.TrimSpace(string(modAliasContent))
modAlias, err := parseModAliasString(modAliasStr)
if err != nil {
return "", fmt.Errorf("failed to parse modalias string %q for device %q: %w", modAliasStr, d.Address, err)
}
logrus.Debugf("modalias for device %q: %+v", d.Address, modAlias)

kernelVersion, err := getKernelVersion()
if err != nil {
return "", fmt.Errorf("failed to get kernel version: %w", err)
}
logrus.Debugf("kernel version: %s", kernelVersion)

modulesAliasFilePath := filepath.Join("/lib/modules", kernelVersion, "modules.alias")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we extract our file paths into constants?

const (
	kernelModulesRoot = "/lib/modules"
	modulesAliasFileName = "modules.alias"
)

We can also create helper functions to create the paths:

func getModulesAliasPath(kernelVersion string) string {
	return filepath.Join(kernelModulesRoot, kernelVersion, modulesAliasFileName)
}

func getDeviceModaliasPath(devicePath string) string {
	return filepath.Join(devicePath, "modalias")
}

This way, callers don't need to know the exact path structure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved /lib/modules to a constant. I have decided against moving modules.alias to a constant -- for files that we are only opening once, I prefer to read the filenames in-line (instead of jumping to a constant). Obviously, if we need to refer to this filename in multiple parts of the code in the future, I would be happy to move this to a constant.

Comment on lines 203 to 261
if matches, score := matchField(deviceModAlias.vendor, patternModAlias.vendor); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.device, patternModAlias.device); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.subvendor, patternModAlias.subvendor); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.subdevice, patternModAlias.subdevice); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.baseClass, patternModAlias.baseClass); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.subClass, patternModAlias.subClass); !matches {
return false, 0
} else {
specificity += score
}

if matches, score := matchField(deviceModAlias.interface_, patternModAlias.interface_); !matches {
return false, 0
} else {
specificity += score
}

return true, specificity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to use slices of getters here to shorten this code?

type fieldGetter func(*modAlias) string

fields := []struct {
    getter fieldGetter
}{
    {func(m *modAlias) string { return m.vendor }},
    {func(m *modAlias) string { return m.device }},
    // ... etc
}

for _, field := range fields {
    deviceVal := field.getter(deviceModAlias)
    patternVal := field.getter(patternModAlias)
    if matches, score := matchField(deviceVal, patternVal); !matches {
        return false, 0
    }
    specificity += score
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the implementation significantly. I believe it is simpler now. Let me know what you think.

for _, line := range lines {
line = strings.TrimSpace(line)

if !strings.HasPrefix(line, "alias vfio_pci:") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract this to a named constant?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@cdesiniotis cdesiniotis marked this pull request as ready for review November 18, 2025 21:42
@cdesiniotis cdesiniotis force-pushed the support-variant-vfio-modules branch 2 times, most recently from ff28e1c to b5da7d9 Compare November 22, 2025 00:28
@cdesiniotis cdesiniotis changed the title wip: update vfio-manage to choose best VFIO driver Update vfio-manage to choose best VFIO driver Nov 22, 2025
@cdesiniotis cdesiniotis force-pushed the support-variant-vfio-modules branch 2 times, most recently from a95b741 to ad775b1 Compare November 25, 2025 01:54
@cdesiniotis cdesiniotis force-pushed the support-variant-vfio-modules branch 2 times, most recently from 64f0f28 to 26d70dd Compare December 8, 2025 05:31
Rather than always binding GPUs to the vfio-pci driver, this commit
introduces logic to see if the running kernel has a VFIO variant
driver available that is a better match for the device. This is required
on Grace-based systems where the nvgrace_gpu_vfio_pci module is required
to be used in favor of the vfio-pci module.

We read the mod.alias file for a given device, then we look through
/lib/modules/${kernel_version}/modules.alias for the vfio_pci alias
that matches with the least number of wildcard ('*') fields.

The code introduced in this commit is inspired by:

https://gitlab.com/libvirt/libvirt/-/commit/82e2fac297105f554f57fb589002933231b4f711

Signed-off-by: Christopher Desiniotis <cdesiniotis@nvidia.com>
Signed-off-by: Christopher Desiniotis <cdesiniotis@nvidia.com>
Copy link
Member

@karthikvetrivel karthikvetrivel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work on this, Chris! LGTM.

batman_approves

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants