feat: implement device selector for 'physical'

Closes #8090

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
This commit is contained in:
Andrey Smirnov 2024-01-18 21:02:37 +04:00
parent 7d11172896
commit d677901b67
No known key found for this signature in database
GPG Key ID: FE042E3D4085A811
11 changed files with 67 additions and 8 deletions

View File

@ -25,6 +25,12 @@ runc: 1.1.11
Flannel: 0.24.1
Talos is built with Go 1.21.6.
"""
[notes.device_selectors]
title = "Device Selectors"
description = """\
Talos Linux now supports `physical: true` qualifier for device selectors, it selects non-virtual network interfaces (i.e. `en0` is selected, while `bond0` is not).
"""
[make_deps]

View File

@ -210,7 +210,7 @@ func (ctrl *DeviceConfigController) selectDevices(selector talosconfig.NetworkDe
for iter := links.Iterator(); iter.Next(); {
linkStatus := iter.Value().TypedSpec()
match := false
var match optional.Optional[bool]
for _, pair := range [][]string{
{selector.HardwareAddress(), linkStatus.HardwareAddr.String()},
@ -223,15 +223,19 @@ func (ctrl *DeviceConfigController) selectDevices(selector talosconfig.NetworkDe
}
if !glob.Glob(pair[0], pair[1]) {
match = false
match = optional.Some(false)
break
}
match = true
match = optional.Some(true)
}
if match {
if selector.Physical() != nil && match.ValueOr(true) {
match = optional.Some(*selector.Physical() == linkStatus.Physical())
}
if match.ValueOrZero() {
result = append(result, iter.Value())
}
}

View File

@ -12,6 +12,7 @@ import (
"github.com/cosi-project/runtime/pkg/resource/rtestutils"
"github.com/siderolabs/gen/maps"
"github.com/siderolabs/go-pointer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
@ -108,6 +109,13 @@ func (suite *DeviceConfigSpecSuite) TestSelectors() {
},
DeviceAddresses: []string{"192.168.5.0/24"},
},
// device selector which matches physical interfaces
{
DeviceSelector: &v1alpha1.NetworkDeviceSelector{
NetworkDevicePhysical: pointer.To(true),
},
DeviceAddresses: []string{"192.168.6.0/24"},
},
},
},
},
@ -119,6 +127,7 @@ func (suite *DeviceConfigSpecSuite) TestSelectors() {
status := network.NewLinkStatus(network.NamespaceName, "eth0")
status.TypedSpec().Driver = kernelDriver
status.TypedSpec().BusPath = "0000:01:00.0"
status.TypedSpec().Type = nethelpers.LinkEther // physical
suite.Require().NoError(suite.State().Create(suite.Ctx(), status))
status = network.NewLinkStatus(network.NamespaceName, "eth1")
@ -143,6 +152,12 @@ func (suite *DeviceConfigSpecSuite) TestSelectors() {
assert.Equal([]string{"192.168.5.0/24"}, r.TypedSpec().Device.Addresses())
},
)
rtestutils.AssertResources(suite.Ctx(), suite.T(), suite.State(), []string{"eth0/004"},
func(r *network.DeviceConfigSpec, assert *assert.Assertions) {
assert.Equal([]string{"192.168.6.0/24"}, r.TypedSpec().Device.Addresses())
},
)
}
func (suite *DeviceConfigSpecSuite) TestBondSelectors() {

View File

@ -291,6 +291,7 @@ type NetworkDeviceSelector interface {
HardwareAddress() string
PCIID() string
KernelDriver() string
Physical() *bool
}
// Time defines the requirements for a config that pertains to time related

View File

@ -838,6 +838,11 @@ func (s *NetworkDeviceSelector) KernelDriver() string {
return s.NetworkDeviceKernelDriver
}
// Physical implements config.NetworkDeviceSelector interface.
func (s *NetworkDeviceSelector) Physical() *bool {
return s.NetworkDevicePhysical
}
// Network implements the MachineNetwork interface.
func (r *Route) Network() string {
return r.RouteNetwork

View File

@ -2289,6 +2289,8 @@ type NetworkDeviceSelector struct {
NetworkDevicePCIID string `yaml:"pciID,omitempty"`
// description: Kernel driver, supports matching by wildcard.
NetworkDeviceKernelDriver string `yaml:"driver,omitempty"`
// description: Select only physical devices.
NetworkDevicePhysical *bool `yaml:"physical,omitempty"`
}
// ClusterDiscoveryConfig struct configures cluster membership discovery.

View File

@ -3658,6 +3658,13 @@ func (NetworkDeviceSelector) Doc() *encoder.Doc {
Description: "Kernel driver, supports matching by wildcard.",
Comments: [3]string{"" /* encoder.HeadComment */, "Kernel driver, supports matching by wildcard." /* encoder.LineComment */, "" /* encoder.FootComment */},
},
{
Name: "physical",
Type: "bool",
Note: "",
Description: "Select only physical devices.",
Comments: [3]string{"" /* encoder.HeadComment */, "Select only physical devices." /* encoder.LineComment */, "" /* encoder.FootComment */},
},
},
}

View File

@ -161,7 +161,9 @@ func (in *Bond) DeepCopyInto(out *Bond) {
if in.BondDeviceSelectors != nil {
in, out := &in.BondDeviceSelectors, &out.BondDeviceSelectors
*out = make([]NetworkDeviceSelector, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.BondARPIPTarget != nil {
in, out := &in.BondARPIPTarget, &out.BondARPIPTarget
@ -586,7 +588,7 @@ func (in *Device) DeepCopyInto(out *Device) {
if in.DeviceSelector != nil {
in, out := &in.DeviceSelector, &out.DeviceSelector
*out = new(NetworkDeviceSelector)
**out = **in
(*in).DeepCopyInto(*out)
}
if in.DeviceAddresses != nil {
in, out := &in.DeviceAddresses, &out.DeviceAddresses
@ -1101,7 +1103,7 @@ func (in *IfaceSelector) DeepCopyInto(out *IfaceSelector) {
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = new(NetworkDeviceSelector)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}
@ -1856,6 +1858,11 @@ func (in NetworkDeviceList) DeepCopy() NetworkDeviceList {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkDeviceSelector) DeepCopyInto(out *NetworkDeviceSelector) {
*out = *in
if in.NetworkDevicePhysical != nil {
in, out := &in.NetworkDevicePhysical, &out.NetworkDevicePhysical
*out = new(bool)
**out = **in
}
return
}

View File

@ -1175,6 +1175,7 @@ machine:
|`hardwareAddr` |string |Device hardware address, supports matching by wildcard. | |
|`pciID` |string |PCI ID (vendor ID, product ID), supports matching by wildcard. | |
|`driver` |string |Kernel driver, supports matching by wildcard. | |
|`physical` |bool |Select only physical devices. | |
@ -1322,6 +1323,7 @@ machine:
|`hardwareAddr` |string |Device hardware address, supports matching by wildcard. | |
|`pciID` |string |PCI ID (vendor ID, product ID), supports matching by wildcard. | |
|`driver` |string |Kernel driver, supports matching by wildcard. | |
|`physical` |bool |Select only physical devices. | |

View File

@ -39,6 +39,16 @@ spec:
pciID: 1969:E0B1
```
The following qualifiers are available:
- `driver` - matches a device by its driver name
- `hardwareAddr` - matches a device by its hardware address
- `busPath` - matches a device by its PCI bus path
- `pciID` - matches a device by its PCI vendor and device ID
- `physical` - matches only physical devices (vs. virtual devices, e.g. bonds and VLANs)
All qualifiers except for `physical` support wildcard matching using `*` character.
## Using Device Selector for Bonding
Device selectors can be used to configure bonded interfaces:

View File

@ -95,7 +95,7 @@ machine:
network:
interfaces:
- deviceSelector:
busPath: "0*" # should select any hardware network device, if you have just one, it will be selected
physical: true # should select any hardware network device, if you have just one, it will be selected
dhcp: true
vip:
ip: 192.168.0.15