Merge pull request #27751 from containers/renovate/tags.cncf.io-container-device-interface-1.x

fix(deps): update module tags.cncf.io/container-device-interface to v1.1.0
This commit is contained in:
Paul Holzinger
2025-12-11 20:42:35 +01:00
committed by GitHub
8 changed files with 178 additions and 34 deletions

4
go.mod
View File

@@ -77,7 +77,7 @@ require (
gopkg.in/inf.v0 v0.9.1
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/yaml v1.6.0
tags.cncf.io/container-device-interface v1.0.2-0.20251120202831-139ffec09210
tags.cncf.io/container-device-interface v1.1.0
)
require (
@@ -190,5 +190,5 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
tags.cncf.io/container-device-interface/specs-go v1.0.1-0.20251120202831-139ffec09210 // indirect
tags.cncf.io/container-device-interface/specs-go v1.1.0 // indirect
)

8
go.sum
View File

@@ -600,7 +600,7 @@ sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
src.elv.sh v0.16.0-rc1.0.20220116211855-fda62502ad7f h1:pjVeIo9Ba6K1Wy+rlwX91zT7A+xGEmxiNRBdN04gDTQ=
src.elv.sh v0.16.0-rc1.0.20220116211855-fda62502ad7f/go.mod h1:kPbhv5+fBeUh85nET3wWhHGUaUQ64nZMJ8FwA5v5Olg=
tags.cncf.io/container-device-interface v1.0.2-0.20251120202831-139ffec09210 h1:ucIvxFr8UEFjsROkGrjxb3BKqZZpfifkRT9nLgeMD9U=
tags.cncf.io/container-device-interface v1.0.2-0.20251120202831-139ffec09210/go.mod h1:kIlIMADdgOVbyLj4ZvEtCvHXqFXqxfbVKKKgBZt8NgQ=
tags.cncf.io/container-device-interface/specs-go v1.0.1-0.20251120202831-139ffec09210 h1:SDIHrIFfJP54QHSdPS0VfwcVYodmkp6y/OPL/ceoejs=
tags.cncf.io/container-device-interface/specs-go v1.0.1-0.20251120202831-139ffec09210/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ=
tags.cncf.io/container-device-interface v1.1.0 h1:RnxNhxF1JOu6CJUVpetTYvrXHdxw9j9jFYgZpI+anSY=
tags.cncf.io/container-device-interface v1.1.0/go.mod h1:76Oj0Yqp9FwTx/pySDc8Bxjpg+VqXfDb50cKAXVJ34Q=
tags.cncf.io/container-device-interface/specs-go v1.1.0 h1:QRZVeAceQM+zTZe12eyfuJuuzp524EKYwhmvLd+h+yQ=
tags.cncf.io/container-device-interface/specs-go v1.1.0/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ=

4
vendor/modules.txt vendored
View File

@@ -1208,12 +1208,12 @@ gopkg.in/yaml.v3
# sigs.k8s.io/yaml v1.6.0
## explicit; go 1.22
sigs.k8s.io/yaml
# tags.cncf.io/container-device-interface v1.0.2-0.20251120202831-139ffec09210
# tags.cncf.io/container-device-interface v1.1.0
## explicit; go 1.21
tags.cncf.io/container-device-interface/internal/validation
tags.cncf.io/container-device-interface/internal/validation/k8s
tags.cncf.io/container-device-interface/pkg/cdi
tags.cncf.io/container-device-interface/pkg/parser
# tags.cncf.io/container-device-interface/specs-go v1.0.1-0.20251120202831-139ffec09210
# tags.cncf.io/container-device-interface/specs-go v1.1.0
## explicit; go 1.19
tags.cncf.io/container-device-interface/specs-go

View File

@@ -113,6 +113,14 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
}
}
if len(e.NetDevices) > 0 {
// specgen is currently missing functionality to set Linux NetDevices,
// so we use a locally rolled function for now.
for _, dev := range e.NetDevices {
specgenAddLinuxNetDevice(&specgen, dev.HostInterfaceName, (&LinuxNetDevice{dev}).toOCI())
}
}
if len(e.Mounts) > 0 {
for _, m := range e.Mounts {
specgen.RemoveMount(m.ContainerPath)
@@ -162,6 +170,24 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
return nil
}
func specgenAddLinuxNetDevice(specgen *ocigen.Generator, hostIf string, netDev *oci.LinuxNetDevice) {
if specgen == nil || netDev == nil {
return
}
ensureLinuxNetDevices(specgen.Config)
specgen.Config.Linux.NetDevices[hostIf] = *netDev
}
// Ensure OCI Spec Linux NetDevices map is not nil.
func ensureLinuxNetDevices(spec *oci.Spec) {
if spec.Linux == nil {
spec.Linux = &oci.Linux{}
}
if spec.Linux.NetDevices == nil {
spec.Linux.NetDevices = map[string]oci.LinuxNetDevice{}
}
}
// Validate container edits.
func (e *ContainerEdits) Validate() error {
if e == nil || e.ContainerEdits == nil {
@@ -191,6 +217,9 @@ func (e *ContainerEdits) Validate() error {
return err
}
}
if err := ValidateNetDevices(e.NetDevices); err != nil {
return err
}
return nil
}
@@ -210,6 +239,7 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
e.Env = append(e.Env, o.Env...)
e.DeviceNodes = append(e.DeviceNodes, o.DeviceNodes...)
e.NetDevices = append(e.NetDevices, o.NetDevices...)
e.Hooks = append(e.Hooks, o.Hooks...)
e.Mounts = append(e.Mounts, o.Mounts...)
if o.IntelRdt != nil {
@@ -244,6 +274,9 @@ func (e *ContainerEdits) isEmpty() bool {
if e.IntelRdt != nil {
return false
}
if len(e.NetDevices) > 0 {
return false
}
return true
}
@@ -257,6 +290,49 @@ func ValidateEnv(env []string) error {
return nil
}
// ValidateNetDevices validates the given net devices.
func ValidateNetDevices(devices []*cdi.LinuxNetDevice) error {
var (
hostSeen = map[string]string{}
nameSeen = map[string]string{}
)
for _, dev := range devices {
if err := (&LinuxNetDevice{dev}).Validate(); err != nil {
return err
}
if other, ok := hostSeen[dev.HostInterfaceName]; ok {
return fmt.Errorf("invalid linux net device, duplicate HostInterfaceName %q with names %q and %q",
dev.HostInterfaceName, dev.Name, other)
}
hostSeen[dev.HostInterfaceName] = dev.Name
if other, ok := nameSeen[dev.Name]; ok {
return fmt.Errorf("invalid linux net device, duplicate Name %q with HostInterfaceName %q and %q",
dev.Name, dev.HostInterfaceName, other)
}
nameSeen[dev.Name] = dev.HostInterfaceName
}
return nil
}
// LinuxNetDevice is a CDI Spec LinuxNetDevice wrapper, used for OCI conversion and validating.
type LinuxNetDevice struct {
*cdi.LinuxNetDevice
}
// Validate LinuxNetDevice.
func (d *LinuxNetDevice) Validate() error {
if d.HostInterfaceName == "" {
return errors.New("invalid linux net device, empty HostInterfaceName")
}
if d.Name == "" {
return errors.New("invalid linux net device, empty Name")
}
return nil
}
// DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
type DeviceNode struct {
*cdi.DeviceNode

View File

@@ -21,6 +21,7 @@ package cdi
import (
"errors"
"fmt"
"os"
"golang.org/x/sys/unix"
)
@@ -31,16 +32,28 @@ const (
fifoDevice = "p"
)
type deviceInfo struct {
// cgroup properties
deviceType string
major int64
minor int64
// device node properties
fileMode os.FileMode
}
// deviceInfoFromPath takes the path to a device and returns its type,
// major and minor device numbers.
//
// It was adapted from https://github.com/opencontainers/runc/blob/v1.1.9/libcontainer/devices/device_unix.go#L30-L69
func deviceInfoFromPath(path string) (devType string, major, minor int64, _ error) {
func deviceInfoFromPath(path string) (*deviceInfo, error) {
var stat unix.Stat_t
err := unix.Lstat(path, &stat)
if err != nil {
return "", 0, 0, err
return nil, err
}
var devType string
switch stat.Mode & unix.S_IFMT {
case unix.S_IFBLK:
devType = blockDevice
@@ -49,38 +62,71 @@ func deviceInfoFromPath(path string) (devType string, major, minor int64, _ erro
case unix.S_IFIFO:
devType = fifoDevice
default:
return "", 0, 0, errors.New("not a device node")
return nil, errors.New("not a device node")
}
devNumber := uint64(stat.Rdev) //nolint:unconvert // Rdev is uint32 on e.g. MIPS.
return devType, int64(unix.Major(devNumber)), int64(unix.Minor(devNumber)), nil
di := deviceInfo{
deviceType: devType,
major: int64(unix.Major(devNumber)),
minor: int64(unix.Minor(devNumber)),
fileMode: os.FileMode(stat.Mode &^ unix.S_IFMT),
}
return &di, nil
}
// fillMissingInfo fills in missing mandatory attributes from the host device.
func (d *DeviceNode) fillMissingInfo() error {
hasMinimalSpecification := d.Type != "" && (d.Major != 0 || d.Type == fifoDevice)
// Ensure that the host path and the container path match.
if d.HostPath == "" {
d.HostPath = d.Path
}
if d.Type != "" && (d.Major != 0 || d.Type == "p") {
// Try to extract the device info from the host path.
di, err := deviceInfoFromPath(d.HostPath)
if err != nil {
// The error is only considered fatal if the device is not already
// minimally specified since it is allowed for a device vendor to fully
// specify a device node specification.
if !hasMinimalSpecification {
return fmt.Errorf("failed to stat CDI host device %q: %w", d.HostPath, err)
}
return nil
}
deviceType, major, minor, err := deviceInfoFromPath(d.HostPath)
if err != nil {
return fmt.Errorf("failed to stat CDI host device %q: %w", d.HostPath, err)
// Even for minimally-specified device nodes, we update the file mode if
// required. This is useful for rootless containers where device node
// requests may be treated as bind mounts.
if d.FileMode == nil {
d.FileMode = &di.fileMode
}
// If the device is minimally specified, we make no further updates and
// don't perform additional checks.
if hasMinimalSpecification {
return nil
}
if d.Type == "" {
d.Type = deviceType
} else {
if d.Type != deviceType {
return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
d.Path, d.HostPath, d.Type, deviceType)
}
d.Type = di.deviceType
}
if d.Major == 0 && d.Type != "p" {
d.Major = major
d.Minor = minor
if d.Type != di.deviceType {
return fmt.Errorf("CDI device (%q, %q), host type mismatch (%s, %s)",
d.Path, d.HostPath, d.Type, di.deviceType)
}
// For a fifoDevice, we do not update the major and minor number.
if d.Type == fifoDevice {
return nil
}
// Update the major and minor number for the device node if required.
if d.Major == 0 {
d.Major = di.major
d.Minor = di.minor
}
return nil

View File

@@ -63,3 +63,10 @@ func (i *IntelRdt) toOCI() *spec.LinuxIntelRdt {
EnableMonitoring: i.EnableMonitoring,
}
}
// toOCI returns the opencontainers runtime Spec LinuxNetDevice for this LinuxNetDevice.
func (d *LinuxNetDevice) toOCI() *spec.LinuxNetDevice {
return &spec.LinuxNetDevice{
Name: d.Name,
}
}

View File

@@ -24,12 +24,13 @@ type Device struct {
// ContainerEdits are edits a container runtime must make to the OCI spec to expose the device.
type ContainerEdits struct {
Env []string `json:"env,omitempty" yaml:"env,omitempty"`
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty" yaml:"deviceNodes,omitempty"`
Hooks []*Hook `json:"hooks,omitempty" yaml:"hooks,omitempty"`
Mounts []*Mount `json:"mounts,omitempty" yaml:"mounts,omitempty"`
IntelRdt *IntelRdt `json:"intelRdt,omitempty" yaml:"intelRdt,omitempty"` // Added in v0.7.0
AdditionalGIDs []uint32 `json:"additionalGids,omitempty" yaml:"additionalGids,omitempty"` // Added in v0.7.0
Env []string `json:"env,omitempty" yaml:"env,omitempty"`
DeviceNodes []*DeviceNode `json:"deviceNodes,omitempty" yaml:"deviceNodes,omitempty"`
NetDevices []*LinuxNetDevice `json:"netDevices,omitempty" yaml:"netDevices,omitempty"` // Added in v1.1.0
Hooks []*Hook `json:"hooks,omitempty" yaml:"hooks,omitempty"`
Mounts []*Mount `json:"mounts,omitempty" yaml:"mounts,omitempty"`
IntelRdt *IntelRdt `json:"intelRdt,omitempty" yaml:"intelRdt,omitempty"` // Added in v0.7.0
AdditionalGIDs []uint32 `json:"additionalGids,omitempty" yaml:"additionalGids,omitempty"` // Added in v0.7.0
}
// DeviceNode represents a device node that needs to be added to the OCI spec.
@@ -67,6 +68,12 @@ type IntelRdt struct {
ClosID string `json:"closID,omitempty" yaml:"closID,omitempty"`
L3CacheSchema string `json:"l3CacheSchema,omitempty" yaml:"l3CacheSchema,omitempty"`
MemBwSchema string `json:"memBwSchema,omitempty" yaml:"memBwSchema,omitempty"`
Schemata []string `json:"schemata,omitempty" yaml:"schemata,omitempty"`
EnableMonitoring bool `json:"enableMonitoring,omitempty" yaml:"enableMonitoring,omitempty"`
Schemata []string `json:"schemata,omitempty" yaml:"schemata,omitempty"` // Added in v1.1.0.
EnableMonitoring bool `json:"enableMonitoring,omitempty" yaml:"enableMonitoring,omitempty"` // Added in v1.1.0.
}
// LinuxNetDevice represents an OCI LinuxNetDevice to be added to the OCI Spec.
type LinuxNetDevice struct {
HostInterfaceName string `json:"hostInterfaceName" yaml:"hostInterfaceName"`
Name string `json:"name" yaml:"name"`
}

View File

@@ -25,7 +25,7 @@ import (
const (
// CurrentVersion is the current version of the Spec.
CurrentVersion = "1.0.0"
CurrentVersion = "1.1.0"
// vCurrent is the current version as a semver-comparable type
vCurrent version = "v" + CurrentVersion
@@ -150,12 +150,20 @@ func requiresV110(spec *Spec) bool {
}
}
if len(spec.ContainerEdits.NetDevices) > 0 {
return true
}
for _, dev := range spec.Devices {
if i := dev.ContainerEdits.IntelRdt; i != nil {
if i.Schemata != nil || i.EnableMonitoring {
return true
}
}
if len(dev.ContainerEdits.NetDevices) > 0 {
return true
}
}
return false