From fcdfeab2ba62ec7c2b76fd7aef70db34c470b7ef Mon Sep 17 00:00:00 2001 From: Orzelius Date: Wed, 25 Mar 2026 21:25:56 +0100 Subject: [PATCH] fix: incorrect route source for on-link routes when processing on-link routes, the source address was incorrectly set to the first address of the interface. This caused issues when the interface had multiple addresses, as the source address may not have been valid for the route. The source address is now set to an empty string, which allows the kernel to automatically select the appropriate source address for the route. Signed-off-by: Orzelius <33936483+Orzelius@users.noreply.github.com> (cherry picked from commit 3400059ccf4811140a4326397d972f68693c708c) --- .../v1alpha1/platform/nocloud/metadata.go | 15 ++-- .../v1alpha1/platform/nocloud/nocloud_test.go | 12 +++ .../expected-v2-nocloud-ipv6-on-link.yaml | 87 +++++++++++++++++++ .../nocloud/testdata/expected-v2.yaml | 2 +- .../testdata/in-v2-nocloud-ipv6-on-link.yaml | 21 +++++ 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-nocloud-ipv6-on-link.yaml create mode 100644 internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-nocloud-ipv6-on-link.yaml diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go index a82de887e..641f64508 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/metadata.go @@ -101,7 +101,7 @@ type Ethernet struct { OnLink bool `yaml:"on-link,omitempty"` } `yaml:"routes,omitempty"` RoutingPolicy []struct { // TODO - From string `yaml:"froom,omitempty"` + From string `yaml:"from,omitempty"` Table uint32 `yaml:"table,omitempty"` } `yaml:"routing-policy,omitempty"` } @@ -733,17 +733,10 @@ func applyNetworkConfigV2Ethernet(name string, eth Ethernet, networkConfig *runt networkConfig.Routes = append(networkConfig.Routes, routeSpec) - if route.OnLink && gw.Is4() { - // This assumes an interface with multiple routes will never have multiple statically set ips. - ipPrefix, err := netip.ParsePrefix(eth.Address[0]) - if err != nil { - return fmt.Errorf("failed to parse route source: %w", err) - } - + if route.OnLink { routeSpec := network.RouteSpecSpec{ ConfigLayer: network.ConfigPlatform, Destination: netip.PrefixFrom(gw, gw.BitLen()), - Source: ipPrefix.Addr(), OutLinkName: name, Scope: nethelpers.ScopeLink, Table: withDefault(nethelpers.RoutingTable(route.Table), nethelpers.TableMain), @@ -753,6 +746,10 @@ func applyNetworkConfigV2Ethernet(name string, eth Ethernet, networkConfig *runt Priority: withDefault(route.Metric, network.DefaultRouteMetric), } + if gw.Is6() { + routeSpec.Family = nethelpers.FamilyInet6 + } + networkConfig.Routes = append(networkConfig.Routes, routeSpec) } } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go index 15ab08fe6..5e39d7626 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/nocloud_test.go @@ -40,6 +40,9 @@ var rawNetworkConfigV2CloudInit []byte //go:embed testdata/in-v2-serverscom.yaml var rawNetworkConfigV2Serverscom []byte +//go:embed testdata/in-v2-nocloud-ipv6-on-link.yaml +var rawNetworkConfigV2NocloudIPv6OnLink []byte + //go:embed testdata/expected-v1.yaml var expectedNetworkConfigV1 string @@ -52,6 +55,9 @@ var expectedNetworkConfigV2 string //go:embed testdata/expected-v2-serverscom.yaml var expectedNetworkConfigV2Serverscom string +//go:embed testdata/expected-v2-nocloud-ipv6-on-link.yaml +var expectedNetworkConfigV2NocloudIPv6OnLink string + func TestParseNetworkConfig(t *testing.T) { t.Parallel() @@ -89,6 +95,12 @@ func TestParseNetworkConfig(t *testing.T) { raw: rawNetworkConfigV2Serverscom, expected: expectedNetworkConfigV2Serverscom, }, + { + name: "V2-nocloud-ipv6-on-link", + raw: rawNetworkConfigV2NocloudIPv6OnLink, + expected: expectedNetworkConfigV2NocloudIPv6OnLink, + expectedNeedsRecocile: true, + }, } { t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-nocloud-ipv6-on-link.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-nocloud-ipv6-on-link.yaml new file mode 100644 index 000000000..14c3643ea --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2-nocloud-ipv6-on-link.yaml @@ -0,0 +1,87 @@ +addresses: + - address: 2a0c:6ec0:b00:c:0:1::/96 + linkName: nic0 + family: inet6 + scope: global + flags: permanent + layer: platform + - address: 10.0.0.0/32 + linkName: nic0 + family: inet4 + scope: global + flags: permanent + layer: platform +links: + - name: nic0 + logical: false + up: true + mtu: 0 + kind: "" + type: netrom + layer: platform +routes: + - family: inet4 + dst: "" + src: "" + gateway: 169.254.0.1 + outLinkName: nic0 + table: main + priority: 1024 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet4 + dst: 169.254.0.1/32 + src: "" + gateway: "" + outLinkName: nic0 + table: main + priority: 1024 + scope: link + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet6 + dst: "" + src: "" + gateway: fe80::1 + outLinkName: nic0 + table: main + priority: 2048 + scope: global + type: unicast + flags: "" + protocol: static + layer: platform + - family: inet6 + dst: fe80::1/128 + src: "" + gateway: "" + outLinkName: nic0 + table: main + priority: 1024 + scope: link + type: unicast + flags: "" + protocol: static + layer: platform +hostnames: + - hostname: talos + domainname: fqdn + layer: platform +resolvers: + - dnsServers: + - 1.1.1.1 + - 2606:4700:4700::1111 + layer: platform +timeServers: [] +operators: [] +externalIPs: [] +metadata: + platform: nocloud + hostname: talos.fqdn + instanceId: "0" + internalDNS: talos.fqdn diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml index 431821162..b97464a81 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/expected-v2.yaml @@ -137,7 +137,7 @@ routes: layer: platform - family: inet4 dst: 192.168.14.1/32 - src: 10.22.14.2 + src: "" gateway: "" outLinkName: eth1 table: main diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-nocloud-ipv6-on-link.yaml b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-nocloud-ipv6-on-link.yaml new file mode 100644 index 000000000..a634a66c9 --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/nocloud/testdata/in-v2-nocloud-ipv6-on-link.yaml @@ -0,0 +1,21 @@ +version: 2 +ethernets: + nic0: + match: + macaddress: "02:xx:xx:xx:xx:xx" + dhcp4: false + dhcp6: false + addresses: + - 2a0c:6ec0:b00:c:0:1::/96 + - 10.0.0.0/32 + routes: + - to: 0.0.0.0/0 + via: 169.254.0.1 + on-link: true + - to: ::/0 + via: fe80::1 + on-link: true + nameservers: + addresses: + - 1.1.1.1 + - 2606:4700:4700::1111