mirror of
				https://github.com/siderolabs/talos.git
				synced 2025-11-04 10:21:13 +01:00 
			
		
		
		
	feat: bring unconfigured links with link carrier up by default
This matches previous networkd implementation to make sure we can run DHCP on the interfaces which are not explicitly brought up. Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
This commit is contained in:
		
							parent
							
								
									02bd657b25
								
							
						
					
					
						commit
						f93c9c8fa6
					
				@ -42,6 +42,11 @@ func (ctrl *LinkConfigController) Inputs() []controller.Input {
 | 
				
			|||||||
			ID:        pointer.ToString(config.V1Alpha1ID),
 | 
								ID:        pointer.ToString(config.V1Alpha1ID),
 | 
				
			||||||
			Kind:      controller.InputWeak,
 | 
								Kind:      controller.InputWeak,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Namespace: network.NamespaceName,
 | 
				
			||||||
 | 
								Type:      network.LinkStatusType,
 | 
				
			||||||
 | 
								Kind:      controller.InputWeak,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -111,7 +116,7 @@ func (ctrl *LinkConfigController) Run(ctx context.Context, r controller.Runtime,
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// parse kernel cmdline for the interface name
 | 
							// parse kernel cmdline for the interface name
 | 
				
			||||||
		cmdlineLink := ctrl.parseCmdline(logger)
 | 
							cmdlineLink, cmdlineIgnored := ctrl.parseCmdline(logger)
 | 
				
			||||||
		if cmdlineLink.Name != "" {
 | 
							if cmdlineLink.Name != "" {
 | 
				
			||||||
			if _, ignored := ignoredInterfaces[cmdlineLink.Name]; !ignored {
 | 
								if _, ignored := ignoredInterfaces[cmdlineLink.Name]; !ignored {
 | 
				
			||||||
				var ids []string
 | 
									var ids []string
 | 
				
			||||||
@ -127,7 +132,7 @@ func (ctrl *LinkConfigController) Run(ctx context.Context, r controller.Runtime,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// parse machine configuration for static routes
 | 
							// parse machine configuration for link specs
 | 
				
			||||||
		if cfgProvider != nil {
 | 
							if cfgProvider != nil {
 | 
				
			||||||
			links := ctrl.parseMachineConfiguration(logger, cfgProvider)
 | 
								links := ctrl.parseMachineConfiguration(logger, cfgProvider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -143,8 +148,56 @@ func (ctrl *LinkConfigController) Run(ctx context.Context, r controller.Runtime,
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// list link for cleanup
 | 
							// bring up any physical link not mentioned explicitly in the machine configuration
 | 
				
			||||||
		list, err := r.List(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined))
 | 
							configuredLinks := map[string]struct{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, linkName := range cmdlineIgnored {
 | 
				
			||||||
 | 
								configuredLinks[linkName] = struct{}{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if cmdlineLink.Name != "" {
 | 
				
			||||||
 | 
								configuredLinks[cmdlineLink.Name] = struct{}{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if cfgProvider != nil {
 | 
				
			||||||
 | 
								for _, device := range cfgProvider.Machine().Network().Devices() {
 | 
				
			||||||
 | 
									configuredLinks[device.Interface()] = struct{}{}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							list, err := r.List(ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("error listing link statuses: %w", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, item := range list.Items {
 | 
				
			||||||
 | 
								linkStatus := item.(*network.LinkStatus) //nolint:errcheck,forcetypeassert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if _, configured := configuredLinks[linkStatus.Metadata().ID()]; !configured {
 | 
				
			||||||
 | 
									if linkStatus.Physical() {
 | 
				
			||||||
 | 
										var ids []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										ids, err = ctrl.apply(ctx, r, []network.LinkSpecSpec{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:        linkStatus.Metadata().ID(),
 | 
				
			||||||
 | 
												Up:          true,
 | 
				
			||||||
 | 
												ConfigLayer: network.ConfigDefault,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											return fmt.Errorf("error applying default link up: %w", err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for _, id := range ids {
 | 
				
			||||||
 | 
											touchedIDs[id] = struct{}{}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// list links for cleanup
 | 
				
			||||||
 | 
							list, err = r.List(ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return fmt.Errorf("error listing resources: %w", err)
 | 
								return fmt.Errorf("error listing resources: %w", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -189,23 +242,23 @@ func (ctrl *LinkConfigController) apply(ctx context.Context, r controller.Runtim
 | 
				
			|||||||
	return ids, nil
 | 
						return ids, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ctrl *LinkConfigController) parseCmdline(logger *zap.Logger) network.LinkSpecSpec {
 | 
					func (ctrl *LinkConfigController) parseCmdline(logger *zap.Logger) (network.LinkSpecSpec, []string) {
 | 
				
			||||||
	if ctrl.Cmdline == nil {
 | 
						if ctrl.Cmdline == nil {
 | 
				
			||||||
		return network.LinkSpecSpec{}
 | 
							return network.LinkSpecSpec{}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	settings, err := ParseCmdlineNetwork(ctrl.Cmdline)
 | 
						settings, err := ParseCmdlineNetwork(ctrl.Cmdline)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logger.Info("ignoring error", zap.Error(err))
 | 
							logger.Info("ignoring error", zap.Error(err))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return network.LinkSpecSpec{}
 | 
							return network.LinkSpecSpec{}, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return network.LinkSpecSpec{
 | 
						return network.LinkSpecSpec{
 | 
				
			||||||
		Name:        settings.LinkName,
 | 
							Name:        settings.LinkName,
 | 
				
			||||||
		Up:          true,
 | 
							Up:          true,
 | 
				
			||||||
		ConfigLayer: network.ConfigCmdline,
 | 
							ConfigLayer: network.ConfigCmdline,
 | 
				
			||||||
	}
 | 
						}, settings.IgnoreInterfaces
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//nolint:gocyclo
 | 
					//nolint:gocyclo
 | 
				
			||||||
 | 
				
			|||||||
@ -97,6 +97,28 @@ func (suite *LinkConfigSuite) assertLinks(requiredIDs []string, check func(*netw
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *LinkConfigSuite) assertNoLinks(unexpectedIDs []string) error {
 | 
				
			||||||
 | 
						unexpIDs := make(map[string]struct{}, len(unexpectedIDs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, id := range unexpectedIDs {
 | 
				
			||||||
 | 
							unexpIDs[id] = struct{}{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, res := range resources.Items {
 | 
				
			||||||
 | 
							_, unexpected := unexpIDs[res.Metadata().ID()]
 | 
				
			||||||
 | 
							if unexpected {
 | 
				
			||||||
 | 
								return retry.ExpectedErrorf("unexpected ID %q", res.Metadata().ID())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (suite *LinkConfigSuite) TestLoopback() {
 | 
					func (suite *LinkConfigSuite) TestLoopback() {
 | 
				
			||||||
	suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{}))
 | 
						suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -289,6 +311,77 @@ func (suite *LinkConfigSuite) TestMachineConfiguration() {
 | 
				
			|||||||
		}))
 | 
							}))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (suite *LinkConfigSuite) TestDefaultUp() {
 | 
				
			||||||
 | 
						suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{
 | 
				
			||||||
 | 
							Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth2"),
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, link := range []string{"eth0", "eth1", "eth2"} {
 | 
				
			||||||
 | 
							linkStatus := network.NewLinkStatus(network.NamespaceName, link)
 | 
				
			||||||
 | 
							linkStatus.TypedSpec().Type = nethelpers.LinkEther
 | 
				
			||||||
 | 
							linkStatus.TypedSpec().LinkState = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							suite.Require().NoError(suite.state.Create(suite.ctx, linkStatus))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u, err := url.Parse("https://foo:6443")
 | 
				
			||||||
 | 
						suite.Require().NoError(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cfg := config.NewMachineConfig(&v1alpha1.Config{
 | 
				
			||||||
 | 
							ConfigVersion: "v1alpha1",
 | 
				
			||||||
 | 
							MachineConfig: &v1alpha1.MachineConfig{
 | 
				
			||||||
 | 
								MachineNetwork: &v1alpha1.NetworkConfig{
 | 
				
			||||||
 | 
									NetworkInterfaces: []*v1alpha1.Device{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											DeviceInterface: "eth0",
 | 
				
			||||||
 | 
											DeviceVlans: []*v1alpha1.Vlan{
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													VlanID:   24,
 | 
				
			||||||
 | 
													VlanCIDR: "10.0.0.1/8",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													VlanID:   48,
 | 
				
			||||||
 | 
													VlanCIDR: "10.0.0.2/8",
 | 
				
			||||||
 | 
												},
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							ClusterConfig: &v1alpha1.ClusterConfig{
 | 
				
			||||||
 | 
								ControlPlane: &v1alpha1.ControlPlaneConfig{
 | 
				
			||||||
 | 
									Endpoint: &v1alpha1.Endpoint{
 | 
				
			||||||
 | 
										URL: u,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.startRuntime()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
 | 
				
			||||||
 | 
							func() error {
 | 
				
			||||||
 | 
								return suite.assertLinks([]string{
 | 
				
			||||||
 | 
									"default/eth1",
 | 
				
			||||||
 | 
								}, func(r *network.LinkSpec) error {
 | 
				
			||||||
 | 
									suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
 | 
				
			||||||
 | 
									suite.Assert().True(r.TypedSpec().Up)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return nil
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
 | 
				
			||||||
 | 
							func() error {
 | 
				
			||||||
 | 
								return suite.assertNoLinks([]string{
 | 
				
			||||||
 | 
									"default/eth0",
 | 
				
			||||||
 | 
									"default/eth2",
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
 | 
							}))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestLinkConfigSuite(t *testing.T) {
 | 
					func TestLinkConfigSuite(t *testing.T) {
 | 
				
			||||||
	suite.Run(t, new(LinkConfigSuite))
 | 
						suite.Run(t, new(LinkConfigSuite))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user