diff --git a/hack/release.toml b/hack/release.toml index 39312beb3e..566f587af3 100644 --- a/hack/release.toml +++ b/hack/release.toml @@ -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] diff --git a/internal/app/machined/pkg/controllers/network/device_config.go b/internal/app/machined/pkg/controllers/network/device_config.go index b2691cc859..f40cb53f03 100644 --- a/internal/app/machined/pkg/controllers/network/device_config.go +++ b/internal/app/machined/pkg/controllers/network/device_config.go @@ -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()) } } diff --git a/internal/app/machined/pkg/controllers/network/device_config_test.go b/internal/app/machined/pkg/controllers/network/device_config_test.go index 58bac209fa..be073e969b 100644 --- a/internal/app/machined/pkg/controllers/network/device_config_test.go +++ b/internal/app/machined/pkg/controllers/network/device_config_test.go @@ -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() { diff --git a/pkg/machinery/config/config/machine.go b/pkg/machinery/config/config/machine.go index 521ce37a30..55299265e2 100644 --- a/pkg/machinery/config/config/machine.go +++ b/pkg/machinery/config/config/machine.go @@ -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 diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go index 32eded383d..432f338605 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_provider.go @@ -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 diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go index e4e20071ad..9431f613a5 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types.go @@ -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. diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go index 25ad033971..61820b64a9 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_types_doc.go @@ -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 */}, + }, }, } diff --git a/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go b/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go index 815eae8c5f..d37914433f 100644 --- a/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/machinery/config/types/v1alpha1/zz_generated.deepcopy.go @@ -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 } diff --git a/website/content/v1.7/reference/configuration/v1alpha1/config.md b/website/content/v1.7/reference/configuration/v1alpha1/config.md index db78924583..cc467d2e88 100644 --- a/website/content/v1.7/reference/configuration/v1alpha1/config.md +++ b/website/content/v1.7/reference/configuration/v1alpha1/config.md @@ -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. | | diff --git a/website/content/v1.7/talos-guides/network/device-selector.md b/website/content/v1.7/talos-guides/network/device-selector.md index 6de0a56d12..d5f3217648 100644 --- a/website/content/v1.7/talos-guides/network/device-selector.md +++ b/website/content/v1.7/talos-guides/network/device-selector.md @@ -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: diff --git a/website/content/v1.7/talos-guides/network/vip.md b/website/content/v1.7/talos-guides/network/vip.md index a7a45dfb0e..464e15b862 100644 --- a/website/content/v1.7/talos-guides/network/vip.md +++ b/website/content/v1.7/talos-guides/network/vip.md @@ -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