diff --git a/cmd/kube-proxy/app/options.go b/cmd/kube-proxy/app/options.go index 5018a67727d..b643ce66e52 100644 --- a/cmd/kube-proxy/app/options.go +++ b/cmd/kube-proxy/app/options.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "strings" + "time" "github.com/fsnotify/fsnotify" "github.com/spf13/pflag" @@ -79,6 +80,14 @@ type Options struct { hostnameOverride string logger klog.Logger + + // The fields below here are placeholders for flags that can't be directly mapped into + // config.KubeProxyConfiguration. + iptablesSyncPeriod time.Duration + iptablesMinSyncPeriod time.Duration + ipvsSyncPeriod time.Duration + ipvsMinSyncPeriod time.Duration + clusterCIDRs string } // AddFlags adds flags to fs and binds them to options. @@ -120,11 +129,11 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.Int32Var(o.config.IPTables.MasqueradeBit, "iptables-masquerade-bit", ptr.Deref(o.config.IPTables.MasqueradeBit, 14), "If using the iptables or ipvs proxy mode, the bit of the fwmark space to mark packets requiring SNAT with. Must be within the range [0, 31].") fs.BoolVar(&o.config.Linux.MasqueradeAll, "masquerade-all", o.config.Linux.MasqueradeAll, "SNAT all traffic sent via Service cluster IPs. This may be required with some CNI plugins. Only supported on Linux.") fs.BoolVar(o.config.IPTables.LocalhostNodePorts, "iptables-localhost-nodeports", ptr.Deref(o.config.IPTables.LocalhostNodePorts, true), "If false, kube-proxy will disable the legacy behavior of allowing NodePort services to be accessed via localhost. (Applies only to iptables mode and IPv4; localhost NodePorts are never allowed with other proxy modes or with IPv6.)") - fs.DurationVar(&o.config.IPTables.SyncPeriod.Duration, "iptables-sync-period", o.config.IPTables.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.") - fs.DurationVar(&o.config.IPTables.MinSyncPeriod.Duration, "iptables-min-sync-period", o.config.IPTables.MinSyncPeriod.Duration, "The minimum period between iptables rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate iptables resync.") + fs.DurationVar(&o.iptablesSyncPeriod, "iptables-sync-period", o.config.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.") + fs.DurationVar(&o.iptablesMinSyncPeriod, "iptables-min-sync-period", o.config.MinSyncPeriod.Duration, "The minimum period between iptables rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate iptables resync.") - fs.DurationVar(&o.config.IPVS.SyncPeriod.Duration, "ipvs-sync-period", o.config.IPVS.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.") - fs.DurationVar(&o.config.IPVS.MinSyncPeriod.Duration, "ipvs-min-sync-period", o.config.IPVS.MinSyncPeriod.Duration, "The minimum period between IPVS rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate IPVS resync.") + fs.DurationVar(&o.ipvsSyncPeriod, "ipvs-sync-period", o.config.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.") + fs.DurationVar(&o.ipvsMinSyncPeriod, "ipvs-min-sync-period", o.config.MinSyncPeriod.Duration, "The minimum period between IPVS rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate IPVS resync.") fs.StringVar(&o.config.IPVS.Scheduler, "ipvs-scheduler", o.config.IPVS.Scheduler, "The ipvs scheduler type when proxy mode is ipvs") fs.StringSliceVar(&o.config.IPVS.ExcludeCIDRs, "ipvs-exclude-cidrs", o.config.IPVS.ExcludeCIDRs, "A comma-separated list of CIDRs which the ipvs proxier should not touch when cleaning up IPVS rules.") fs.BoolVar(&o.config.IPVS.StrictARP, "ipvs-strict-arp", o.config.IPVS.StrictARP, "Enable strict ARP by setting arp_ignore to 1 and arp_announce to 2") @@ -135,7 +144,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { fs.Var(&o.config.DetectLocalMode, "detect-local-mode", "Mode to use to detect local traffic. This parameter is ignored if a config file is specified by --config.") fs.StringVar(&o.config.DetectLocal.BridgeInterface, "pod-bridge-interface", o.config.DetectLocal.BridgeInterface, "A bridge interface name. When --detect-local-mode is set to BridgeInterface, kube-proxy will consider traffic to be local if it originates from this bridge.") fs.StringVar(&o.config.DetectLocal.InterfaceNamePrefix, "pod-interface-name-prefix", o.config.DetectLocal.InterfaceNamePrefix, "An interface name prefix. When --detect-local-mode is set to InterfaceNamePrefix, kube-proxy will consider traffic to be local if it originates from any interface whose name begins with this prefix.") - fs.StringVar(&o.config.ClusterCIDR, "cluster-cidr", o.config.ClusterCIDR, "The CIDR range of the pods in the cluster. (For dual-stack clusters, this can be a comma-separated dual-stack pair of CIDR ranges.). When --detect-local-mode is set to ClusterCIDR, kube-proxy will consider traffic to be local if its source IP is in this range. (Otherwise it is not used.) "+ + fs.StringVar(&o.clusterCIDRs, "cluster-cidr", strings.Join(o.config.DetectLocal.ClusterCIDRs, ","), "The CIDR range of the pods in the cluster. (For dual-stack clusters, this can be a comma-separated dual-stack pair of CIDR ranges.). When --detect-local-mode is set to ClusterCIDR, kube-proxy will consider traffic to be local if its source IP is in this range. (Otherwise it is not used.) "+ "This parameter is ignored if a config file is specified by --config.") fs.StringSliceVar(&o.config.NodePortAddresses, "nodeport-addresses", o.config.NodePortAddresses, @@ -161,8 +170,6 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { _ = fs.MarkDeprecated("healthz-port", "This flag is deprecated and will be removed in a future release. Please use --healthz-bind-address instead.") fs.Int32Var(&o.metricsPort, "metrics-port", o.metricsPort, "The port to bind the metrics server. Use 0 to disable.") _ = fs.MarkDeprecated("metrics-port", "This flag is deprecated and will be removed in a future release. Please use --metrics-bind-address instead.") - fs.Var(utilflag.PortRangeVar{Val: &o.config.PortRange}, "proxy-port-range", "This was previously used to configure the userspace proxy, but is now unused.") - _ = fs.MarkDeprecated("proxy-port-range", "This flag has no effect and will be removed in a future release.") logsapi.AddFlags(&o.config.Logging, fs) } @@ -216,6 +223,8 @@ func (o *Options) Complete(fs *pflag.FlagSet) error { if err := o.initWatcher(); err != nil { return err } + } else { + o.processV1Alpha1Flags(fs) } o.platformApplyDefaults(o.config) @@ -302,6 +311,25 @@ func (o *Options) processHostnameOverrideFlag() error { return nil } +// processV1Alpha1Flags processes v1alpha1 flags which can't be directly mapped to internal config. +func (o *Options) processV1Alpha1Flags(fs *pflag.FlagSet) { + if fs.Changed("iptables-sync-period") && o.config.Mode != kubeproxyconfig.ProxyModeIPVS { + o.config.SyncPeriod.Duration = o.iptablesSyncPeriod + } + if fs.Changed("iptables-min-sync-period") && o.config.Mode != kubeproxyconfig.ProxyModeIPVS { + o.config.MinSyncPeriod.Duration = o.iptablesMinSyncPeriod + } + if fs.Changed("ipvs-sync-period") && o.config.Mode == kubeproxyconfig.ProxyModeIPVS { + o.config.SyncPeriod.Duration = o.ipvsSyncPeriod + } + if fs.Changed("ipvs-min-sync-period") && o.config.Mode == kubeproxyconfig.ProxyModeIPVS { + o.config.MinSyncPeriod.Duration = o.ipvsMinSyncPeriod + } + if fs.Changed("cluster-cidr") { + o.config.DetectLocal.ClusterCIDRs = strings.Split(o.clusterCIDRs, ",") + } +} + // Validate validates all the required options. func (o *Options) Validate() error { if errs := validation.Validate(o.config); len(errs) != 0 { diff --git a/cmd/kube-proxy/app/options_test.go b/cmd/kube-proxy/app/options_test.go index e8d716c5b65..1d76a09ce67 100644 --- a/cmd/kube-proxy/app/options_test.go +++ b/cmd/kube-proxy/app/options_test.go @@ -20,6 +20,8 @@ import ( "fmt" "os" "path" + "reflect" + "strings" "testing" "time" @@ -194,7 +196,8 @@ nodePortAddresses: Kubeconfig: "/path/to/kubeconfig", QPS: 7, }, - ClusterCIDR: tc.clusterCIDR, + MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, + SyncPeriod: metav1.Duration{Duration: 60 * time.Second}, ConfigSyncPeriod: metav1.Duration{Duration: 15 * time.Second}, Linux: kubeproxyconfig.KubeProxyLinuxConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ @@ -212,26 +215,20 @@ nodePortAddresses: IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{ MasqueradeBit: ptr.To[int32](17), LocalhostNodePorts: ptr.To(true), - MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - SyncPeriod: metav1.Duration{Duration: 60 * time.Second}, }, IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{ - MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - SyncPeriod: metav1.Duration{Duration: 60 * time.Second}, - ExcludeCIDRs: []string{"10.20.30.40/16", "fd00:1::0/64"}, + ExcludeCIDRs: []string{"10.20.30.40/16", "fd00:1::0/64"}, }, NFTables: kubeproxyconfig.KubeProxyNFTablesConfiguration{ MasqueradeBit: ptr.To[int32](18), - MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - SyncPeriod: metav1.Duration{Duration: 60 * time.Second}, }, MetricsBindAddress: tc.metricsBindAddress, Mode: kubeproxyconfig.ProxyMode(tc.mode), - PortRange: "2-7", NodePortAddresses: []string{"10.20.30.40/16", "fd00:1::0/64"}, DetectLocalMode: kubeproxyconfig.LocalModeClusterCIDR, DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ BridgeInterface: "cbr0", + ClusterCIDRs: strings.Split(tc.clusterCIDR, ","), InterfaceNamePrefix: "veth", }, Logging: logsapi.LoggingConfiguration{ @@ -377,6 +374,99 @@ func TestProcessHostnameOverrideFlag(t *testing.T) { } } +// TestProcessV1Alpha1Flags tests processing v1alpha1 flags. +func TestProcessV1Alpha1Flags(t *testing.T) { + testCases := []struct { + name string + flags []string + validate func(*kubeproxyconfig.KubeProxyConfiguration) bool + }{ + { + name: "iptables configuration", + flags: []string{ + "--iptables-sync-period=36s", + "--iptables-min-sync-period=3s", + "--proxy-mode=iptables", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return config.SyncPeriod == metav1.Duration{Duration: 36 * time.Second} && + config.MinSyncPeriod == metav1.Duration{Duration: 3 * time.Second} + }, + }, + { + name: "iptables + ipvs configuration with iptables mode", + flags: []string{ + "--iptables-sync-period=36s", + "--iptables-min-sync-period=3s", + "--ipvs-sync-period=16s", + "--ipvs-min-sync-period=7s", + "--proxy-mode=iptables", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return config.SyncPeriod == metav1.Duration{Duration: 36 * time.Second} && + config.MinSyncPeriod == metav1.Duration{Duration: 3 * time.Second} + }, + }, + { + name: "winkernel configuration", + flags: []string{ + "--iptables-sync-period=36s", + "--iptables-min-sync-period=3s", + "--proxy-mode=kernelspace", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return config.SyncPeriod == metav1.Duration{Duration: 36 * time.Second} && + config.MinSyncPeriod == metav1.Duration{Duration: 3 * time.Second} + }, + }, + { + name: "ipvs + iptables configuration with ipvs mode", + flags: []string{ + "--iptables-sync-period=36s", + "--iptables-min-sync-period=3s", + "--ipvs-sync-period=16s", + "--ipvs-min-sync-period=7s", + "--proxy-mode=ipvs", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return config.SyncPeriod == metav1.Duration{Duration: 16 * time.Second} && + config.MinSyncPeriod == metav1.Duration{Duration: 7 * time.Second} + }, + }, + { + name: "ipvs configuration", + flags: []string{ + "--ipvs-sync-period=16s", + "--ipvs-min-sync-period=7s", + "--proxy-mode=ipvs", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return config.SyncPeriod == metav1.Duration{Duration: 16 * time.Second} && + config.MinSyncPeriod == metav1.Duration{Duration: 7 * time.Second} + }, + }, + { + name: "cluster cidr", + flags: []string{ + "--cluster-cidr=2002:0:0:1234::/64,10.0.0.0/14", + }, + validate: func(config *kubeproxyconfig.KubeProxyConfiguration) bool { + return reflect.DeepEqual(config.DetectLocal.ClusterCIDRs, []string{"2002:0:0:1234::/64", "10.0.0.0/14"}) + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + options := NewOptions() + fs := new(pflag.FlagSet) + options.AddFlags(fs) + require.NoError(t, fs.Parse(tc.flags)) + options.processV1Alpha1Flags(fs) + require.True(t, tc.validate(options.config)) + }) + } +} + // TestOptionsComplete checks that command line flags are combined with a // config properly. func TestOptionsComplete(t *testing.T) { diff --git a/cmd/kube-proxy/app/server.go b/cmd/kube-proxy/app/server.go index c0dc1bd0a90..5706e307f44 100644 --- a/cmd/kube-proxy/app/server.go +++ b/cmd/kube-proxy/app/server.go @@ -25,7 +25,6 @@ import ( "net" "net/http" "os" - "strings" "time" "github.com/spf13/cobra" @@ -222,7 +221,7 @@ func newProxyServer(ctx context.Context, config *kubeproxyconfig.KubeProxyConfig } if len(config.HealthzBindAddress) > 0 { - s.HealthzServer = healthcheck.NewProxierHealthServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration) + s.HealthzServer = healthcheck.NewProxierHealthServer(config.HealthzBindAddress, 2*config.SyncPeriod.Duration) } err = s.platformSetup(ctx) @@ -271,8 +270,7 @@ func checkBadConfig(s *ProxyServer) error { // we can at least take note of whether there is any explicitly-dual-stack // configuration. anyDualStackConfig := false - clusterCIDRs := strings.Split(s.Config.ClusterCIDR, ",") - for _, config := range [][]string{clusterCIDRs, s.Config.NodePortAddresses, s.Config.IPVS.ExcludeCIDRs, s.podCIDRs} { + for _, config := range [][]string{s.Config.DetectLocal.ClusterCIDRs, s.Config.NodePortAddresses, s.Config.IPVS.ExcludeCIDRs, s.podCIDRs} { if dual, _ := netutils.IsDualStackCIDRStrings(config); dual { anyDualStackConfig = true break @@ -314,14 +312,11 @@ func checkBadIPConfig(s *ProxyServer, dualStackSupported bool) (err error, fatal clusterType = fmt.Sprintf("%s-only", s.PrimaryIPFamily) } - if s.Config.ClusterCIDR != "" { - clusterCIDRs := strings.Split(s.Config.ClusterCIDR, ",") - if badCIDRs(clusterCIDRs, badFamily) { - errors = append(errors, fmt.Errorf("cluster is %s but clusterCIDRs contains only IPv%s addresses", clusterType, badFamily)) - if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeClusterCIDR && !dualStackSupported { - // This has always been a fatal error - fatal = true - } + if badCIDRs(s.Config.DetectLocal.ClusterCIDRs, badFamily) { + errors = append(errors, fmt.Errorf("cluster is %s but clusterCIDRs contains only IPv%s addresses", clusterType, badFamily)) + if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeClusterCIDR && !dualStackSupported { + // This has always been a fatal error + fatal = true } } diff --git a/cmd/kube-proxy/app/server_linux.go b/cmd/kube-proxy/app/server_linux.go index 9e3121b09ba..d29ba6f3c1b 100644 --- a/cmd/kube-proxy/app/server_linux.go +++ b/cmd/kube-proxy/app/server_linux.go @@ -26,7 +26,6 @@ import ( "errors" "fmt" goruntime "runtime" - "strings" "time" "github.com/google/cadvisor/machine" @@ -178,8 +177,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. ipt, utilsysctl.New(), exec.New(), - config.IPTables.SyncPeriod.Duration, - config.IPTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.Linux.MasqueradeAll, *config.IPTables.LocalhostNodePorts, int(*config.IPTables.MasqueradeBit), @@ -202,8 +201,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. iptInterface, utilsysctl.New(), exec.New(), - config.IPTables.SyncPeriod.Duration, - config.IPTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.Linux.MasqueradeAll, *config.IPTables.LocalhostNodePorts, int(*config.IPTables.MasqueradeBit), @@ -238,8 +237,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. ipsetInterface, utilsysctl.New(), execer, - config.IPVS.SyncPeriod.Duration, - config.IPVS.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.IPVS.ExcludeCIDRs, config.IPVS.StrictARP, config.IPVS.TCPTimeout.Duration, @@ -266,8 +265,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. ipsetInterface, utilsysctl.New(), execer, - config.IPVS.SyncPeriod.Duration, - config.IPVS.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.IPVS.ExcludeCIDRs, config.IPVS.StrictARP, config.IPVS.TCPTimeout.Duration, @@ -295,8 +294,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. // TODO this has side effects that should only happen when Run() is invoked. proxier, err = nftables.NewDualStackProxier( ctx, - config.NFTables.SyncPeriod.Duration, - config.NFTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.Linux.MasqueradeAll, int(*config.NFTables.MasqueradeBit), localDetectors, @@ -313,8 +312,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. proxier, err = nftables.NewProxier( ctx, s.PrimaryIPFamily, - config.NFTables.SyncPeriod.Duration, - config.NFTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, config.Linux.MasqueradeAll, int(*config.NFTables.MasqueradeBit), localDetectors[s.PrimaryIPFamily], @@ -477,12 +476,11 @@ func getLocalDetectors(logger klog.Logger, primaryIPFamily v1.IPFamily, config * switch config.DetectLocalMode { case proxyconfigapi.LocalModeClusterCIDR: - clusterCIDRs := strings.Split(strings.TrimSpace(config.ClusterCIDR), ",") - for family, cidrs := range proxyutil.MapCIDRsByIPFamily(clusterCIDRs) { + for family, cidrs := range proxyutil.MapCIDRsByIPFamily(config.DetectLocal.ClusterCIDRs) { localDetectors[family] = proxyutil.NewDetectLocalByCIDR(cidrs[0].String()) } if !localDetectors[primaryIPFamily].IsImplemented() { - logger.Info("Detect-local-mode set to ClusterCIDR, but no cluster CIDR specified for primary IP family", "ipFamily", primaryIPFamily, "clusterCIDR", config.ClusterCIDR) + logger.Info("Detect-local-mode set to ClusterCIDR, but no cluster CIDR specified for primary IP family", "ipFamily", primaryIPFamily, "clusterCIDRs", config.DetectLocal.ClusterCIDRs) } case proxyconfigapi.LocalModeNodeCIDR: diff --git a/cmd/kube-proxy/app/server_linux_test.go b/cmd/kube-proxy/app/server_linux_test.go index ad4d28ca001..4a2e17721ba 100644 --- a/cmd/kube-proxy/app/server_linux_test.go +++ b/cmd/kube-proxy/app/server_linux_test.go @@ -121,7 +121,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, single-stack IPv4 cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -133,7 +135,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, single-stack IPv6 cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv6Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -145,7 +149,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, single-stack IPv6 cluster with single-stack IPv4 config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv6Protocol, // This will output a warning that there is no IPv6 CIDR but it @@ -159,7 +165,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, single-stack IPv4 cluster with single-stack IPv6 config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv4Protocol, // This will output a warning that there is no IPv4 CIDR but it @@ -173,7 +181,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, dual-stack IPv4-primary cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "10.0.0.0/14,2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14", "2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -185,7 +195,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, dual-stack IPv6-primary cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "2002:0:0:1234::/64,10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64", "10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv6Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -197,7 +209,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, IPv4-primary kube-proxy / IPv6-primary config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "2002:0:0:1234::/64,10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64", "10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -209,7 +223,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeClusterCIDR, no ClusterCIDR", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR, - ClusterCIDR: "", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{""}, + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -222,7 +238,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, single-stack IPv4 cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv4Protocol, nodePodCIDRs: []string{"10.0.0.0/24"}, @@ -235,7 +253,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, single-stack IPv6 cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv6Protocol, nodePodCIDRs: []string{"2002::1234:abcd:ffff:0:0/96"}, @@ -248,7 +268,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, single-stack IPv6 cluster with single-stack IPv4 config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv6Protocol, nodePodCIDRs: []string{"10.0.0.0/24"}, @@ -263,7 +285,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, single-stack IPv4 cluster with single-stack IPv6 config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv4Protocol, nodePodCIDRs: []string{"2002::1234:abcd:ffff:0:0/96"}, @@ -278,7 +302,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, dual-stack IPv4-primary cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "10.0.0.0/14,2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14", "2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv4Protocol, nodePodCIDRs: []string{"10.0.0.0/24", "2002::1234:abcd:ffff:0:0/96"}, @@ -291,7 +317,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, dual-stack IPv6-primary cluster", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "2002:0:0:1234::/64,10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"2002:0:0:1234::/64", "10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv6Protocol, nodePodCIDRs: []string{"2002::1234:abcd:ffff:0:0/96", "10.0.0.0/24"}, @@ -304,7 +332,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, IPv6-primary kube-proxy / IPv4-primary config", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "10.0.0.0/14,2002:0:0:1234::/64", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14", "2002:0:0:1234::/64"}, + }, }, primaryIPFamily: v1.IPv6Protocol, nodePodCIDRs: []string{"10.0.0.0/24", "2002::1234:abcd:ffff:0:0/96"}, @@ -317,7 +347,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeNodeCIDR, no PodCIDRs", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR, - ClusterCIDR: "", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{""}, + }, }, primaryIPFamily: v1.IPv4Protocol, nodePodCIDRs: []string{}, @@ -331,7 +363,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "unknown LocalMode", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalMode("abcd"), - ClusterCIDR: "10.0.0.0/14", + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/14"}, + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -344,7 +378,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeBridgeInterface", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeBridgeInterface, - DetectLocal: proxyconfigapi.DetectLocalConfiguration{BridgeInterface: "eth"}, + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + BridgeInterface: "eth", + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -356,7 +392,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeBridgeInterface, strange bridge name", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeBridgeInterface, - DetectLocal: proxyconfigapi.DetectLocalConfiguration{BridgeInterface: "1234567890123456789"}, + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + BridgeInterface: "1234567890123456789", + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -369,7 +407,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeInterfaceNamePrefix", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeInterfaceNamePrefix, - DetectLocal: proxyconfigapi.DetectLocalConfiguration{InterfaceNamePrefix: "eth"}, + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + InterfaceNamePrefix: "eth", + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ @@ -381,7 +421,9 @@ func Test_getLocalDetectors(t *testing.T) { name: "LocalModeInterfaceNamePrefix, strange interface name", config: &proxyconfigapi.KubeProxyConfiguration{ DetectLocalMode: proxyconfigapi.LocalModeInterfaceNamePrefix, - DetectLocal: proxyconfigapi.DetectLocalConfiguration{InterfaceNamePrefix: "1234567890123456789"}, + DetectLocal: proxyconfigapi.DetectLocalConfiguration{ + InterfaceNamePrefix: "1234567890123456789", + }, }, primaryIPFamily: v1.IPv4Protocol, expected: map[v1.IPFamily]proxyutil.LocalTrafficDetector{ diff --git a/cmd/kube-proxy/app/server_test.go b/cmd/kube-proxy/app/server_test.go index bf51857a696..e76a272d7ef 100644 --- a/cmd/kube-proxy/app/server_test.go +++ b/cmd/kube-proxy/app/server_test.go @@ -305,7 +305,9 @@ func Test_checkBadConfig(t *testing.T) { name: "single-stack NodePortAddresses with single-stack config", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "10.0.0.0/8", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/8"}, + }, NodePortAddresses: []string{"192.168.0.0/24"}, }, PrimaryIPFamily: v1.IPv4Protocol, @@ -316,7 +318,9 @@ func Test_checkBadConfig(t *testing.T) { name: "dual-stack NodePortAddresses with dual-stack config", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "10.0.0.0/8,fd09::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/8", "fd09::/64"}, + }, NodePortAddresses: []string{"192.168.0.0/24", "fd03::/64"}, }, PrimaryIPFamily: v1.IPv4Protocol, @@ -337,7 +341,9 @@ func Test_checkBadConfig(t *testing.T) { name: "single-stack NodePortAddresses with dual-stack config", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "10.0.0.0/8,fd09::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/8", "fd09::/64"}, + }, NodePortAddresses: []string{"192.168.0.0/24"}, }, PrimaryIPFamily: v1.IPv4Protocol, @@ -348,7 +354,9 @@ func Test_checkBadConfig(t *testing.T) { name: "wrong-single-stack NodePortAddresses", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "fd09::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"fd09::/64"}, + }, NodePortAddresses: []string{"192.168.0.0/24"}, }, PrimaryIPFamily: v1.IPv6Protocol, @@ -392,7 +400,9 @@ func Test_checkBadIPConfig(t *testing.T) { name: "ok single-stack clusterCIDR", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "10.0.0.0/8", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/8"}, + }, }, PrimaryIPFamily: v1.IPv4Protocol, }, @@ -403,7 +413,9 @@ func Test_checkBadIPConfig(t *testing.T) { name: "ok dual-stack clusterCIDR", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "10.0.0.0/8,fd01:2345::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"10.0.0.0/8", "fd01:2345::/64"}, + }, }, PrimaryIPFamily: v1.IPv4Protocol, }, @@ -414,7 +426,9 @@ func Test_checkBadIPConfig(t *testing.T) { name: "ok reversed dual-stack clusterCIDR", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "fd01:2345::/64,10.0.0.0/8", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"fd01:2345::/64", "10.0.0.0/8"}, + }, }, PrimaryIPFamily: v1.IPv4Protocol, }, @@ -425,7 +439,9 @@ func Test_checkBadIPConfig(t *testing.T) { name: "wrong-family clusterCIDR", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "fd01:2345::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"fd01:2345::/64"}, + }, }, PrimaryIPFamily: v1.IPv4Protocol, }, @@ -438,7 +454,9 @@ func Test_checkBadIPConfig(t *testing.T) { name: "wrong-family clusterCIDR when using ClusterCIDR LocalDetector", proxy: &ProxyServer{ Config: &kubeproxyconfig.KubeProxyConfiguration{ - ClusterCIDR: "fd01:2345::/64", + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"fd01:2345::/64"}, + }, DetectLocalMode: kubeproxyconfig.LocalModeClusterCIDR, }, PrimaryIPFamily: v1.IPv4Protocol, diff --git a/cmd/kube-proxy/app/server_windows.go b/cmd/kube-proxy/app/server_windows.go index 4f34e7e2947..1d7f5d451ff 100644 --- a/cmd/kube-proxy/app/server_windows.go +++ b/cmd/kube-proxy/app/server_windows.go @@ -91,8 +91,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. if dualStackMode { proxier, err = winkernel.NewDualStackProxier( - config.IPTables.SyncPeriod.Duration, - config.IPTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, s.Hostname, s.NodeIPs, s.Recorder, @@ -103,8 +103,8 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. } else { proxier, err = winkernel.NewProxier( s.PrimaryIPFamily, - config.IPTables.SyncPeriod.Duration, - config.IPTables.MinSyncPeriod.Duration, + config.SyncPeriod.Duration, + config.MinSyncPeriod.Duration, s.Hostname, s.NodeIPs[s.PrimaryIPFamily], s.Recorder, diff --git a/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/after/v1alpha1.yaml b/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/after/v1alpha1.yaml index faf62d0e922..fb0ac230c3b 100644 --- a/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/after/v1alpha1.yaml +++ b/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/after/v1alpha1.yaml @@ -35,7 +35,7 @@ ipvs: minSyncPeriod: 0s scheduler: "" strictARP: false - syncPeriod: 30s + syncPeriod: 0s tcpFinTimeout: 0s tcpTimeout: 0s udpTimeout: 0s @@ -54,8 +54,8 @@ mode: "" nftables: masqueradeAll: false masqueradeBit: 14 - minSyncPeriod: 1s - syncPeriod: 30s + minSyncPeriod: 0s + syncPeriod: 0s nodePortAddresses: null oomScoreAdj: -999 portRange: "" diff --git a/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/roundtrip/default/v1alpha1.yaml b/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/roundtrip/default/v1alpha1.yaml index faf62d0e922..fb0ac230c3b 100644 --- a/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/roundtrip/default/v1alpha1.yaml +++ b/pkg/proxy/apis/config/scheme/testdata/KubeProxyConfiguration/roundtrip/default/v1alpha1.yaml @@ -35,7 +35,7 @@ ipvs: minSyncPeriod: 0s scheduler: "" strictARP: false - syncPeriod: 30s + syncPeriod: 0s tcpFinTimeout: 0s tcpTimeout: 0s udpTimeout: 0s @@ -54,8 +54,8 @@ mode: "" nftables: masqueradeAll: false masqueradeBit: 14 - minSyncPeriod: 1s - syncPeriod: 30s + minSyncPeriod: 0s + syncPeriod: 0s nodePortAddresses: null oomScoreAdj: -999 portRange: "" diff --git a/pkg/proxy/apis/config/types.go b/pkg/proxy/apis/config/types.go index 5f1c415b89f..c811ed1d133 100644 --- a/pkg/proxy/apis/config/types.go +++ b/pkg/proxy/apis/config/types.go @@ -53,27 +53,11 @@ type KubeProxyIPTablesConfiguration struct { // iptables mode and IPv4; localhost NodePorts are never allowed with other proxy // modes or with IPv6.) LocalhostNodePorts *bool - // syncPeriod is an interval (e.g. '5s', '1m', '2h22m') indicating how frequently - // various re-synchronizing and cleanup operations are performed. Must be greater - // than 0. - SyncPeriod metav1.Duration - // minSyncPeriod is the minimum period between iptables rule resyncs (e.g. '5s', - // '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will - // result in an immediate iptables resync. - MinSyncPeriod metav1.Duration } // KubeProxyIPVSConfiguration contains ipvs-related configuration // details for the Kubernetes proxy server. type KubeProxyIPVSConfiguration struct { - // syncPeriod is an interval (e.g. '5s', '1m', '2h22m') indicating how frequently - // various re-synchronizing and cleanup operations are performed. Must be greater - // than 0. - SyncPeriod metav1.Duration - // minSyncPeriod is the minimum period between IPVS rule resyncs (e.g. '5s', '1m', - // '2h22m'). A value of 0 means every Service or EndpointSlice change will result - // in an immediate IPVS resync. - MinSyncPeriod metav1.Duration // scheduler is the IPVS scheduler to use Scheduler string // excludeCIDRs is a list of CIDRs which the ipvs proxier should not touch @@ -99,14 +83,6 @@ type KubeProxyNFTablesConfiguration struct { // masqueradeBit is the bit of the iptables fwmark space to use for SNAT if using // the nftables proxy mode. Values must be within the range [0, 31]. MasqueradeBit *int32 - // syncPeriod is an interval (e.g. '5s', '1m', '2h22m') indicating how frequently - // various re-synchronizing and cleanup operations are performed. Must be greater - // than 0. - SyncPeriod metav1.Duration - // minSyncPeriod is the minimum period between iptables rule resyncs (e.g. '5s', - // '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will - // result in an immediate iptables resync. - MinSyncPeriod metav1.Duration } // KubeProxyConntrackConfiguration contains conntrack settings for @@ -165,6 +141,10 @@ type DetectLocalConfiguration struct { // LocalModeBridgeInterface, kube-proxy will consider traffic to be local if // it originates from this bridge. BridgeInterface string + // clusterCIDRs is the dual-stack list of CIDR ranges of the pods in the cluster. When + // DetectLocalMode is set to LocalModeClusterCIDR, kube-proxy will consider + // traffic to be local if its source IP is in the range of any given CIDR. + ClusterCIDRs []string // interfaceNamePrefix is an interface name prefix. When DetectLocalMode is set to // LocalModeInterfaceNamePrefix, kube-proxy will consider traffic to be local if // it originates from any interface whose name begins with this prefix. @@ -236,12 +216,6 @@ type KubeProxyConfiguration struct { DetectLocalMode LocalMode // detectLocal contains optional configuration settings related to DetectLocalMode. DetectLocal DetectLocalConfiguration - // clusterCIDR is the CIDR range of the pods in the cluster. (For dual-stack - // clusters, this can be a comma-separated dual-stack pair of CIDR ranges.). When - // DetectLocalMode is set to LocalModeClusterCIDR, kube-proxy will consider - // traffic to be local if its source IP is in this range. (Otherwise it is not - // used.) - ClusterCIDR string // nodePortAddresses is a list of CIDR ranges that contain valid node IPs, or // alternatively, the single string 'primary'. If set to a list of CIDRs, @@ -251,12 +225,17 @@ type KubeProxyConfiguration struct { // object. If unset, NodePort connections will be accepted on all local IPs. NodePortAddresses []string + // syncPeriod is an interval (e.g. '5s', '1m', '2h22m') indicating how frequently + // various re-synchronizing and cleanup operations are performed. Must be greater + // than 0. + SyncPeriod metav1.Duration + // minSyncPeriod is the minimum period between proxier rule resyncs (e.g. '5s', + // '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will + // result in an immediate proxier resync. + MinSyncPeriod metav1.Duration // configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater // than 0. ConfigSyncPeriod metav1.Duration - - // portRange was previously used to configure the userspace proxy, but is now unused. - PortRange string } // ProxyMode represents modes used by the Kubernetes proxy server. diff --git a/pkg/proxy/apis/config/v1alpha1/conversion.go b/pkg/proxy/apis/config/v1alpha1/conversion.go index 1d8f197c06d..304909932ca 100644 --- a/pkg/proxy/apis/config/v1alpha1/conversion.go +++ b/pkg/proxy/apis/config/v1alpha1/conversion.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + "strings" + "k8s.io/apimachinery/pkg/conversion" "k8s.io/kube-proxy/config/v1alpha1" "k8s.io/kubernetes/pkg/proxy/apis/config" @@ -36,6 +38,22 @@ func Convert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguration(in default: out.IPTables.MasqueradeAll = in.Linux.MasqueradeAll } + + switch in.Mode { + case config.ProxyModeIPVS: + out.IPVS.SyncPeriod = in.SyncPeriod + out.IPVS.MinSyncPeriod = in.MinSyncPeriod + case config.ProxyModeNFTables: + out.NFTables.SyncPeriod = in.SyncPeriod + out.NFTables.MinSyncPeriod = in.MinSyncPeriod + default: + out.IPTables.SyncPeriod = in.SyncPeriod + out.IPTables.MinSyncPeriod = in.MinSyncPeriod + } + + if len(in.DetectLocal.ClusterCIDRs) > 0 { + out.ClusterCIDR = strings.Join(in.DetectLocal.ClusterCIDRs, ",") + } return nil } @@ -53,6 +71,22 @@ func Convert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguration(in default: out.Linux.MasqueradeAll = in.IPTables.MasqueradeAll } + + switch config.ProxyMode(in.Mode) { + case config.ProxyModeIPVS: + out.SyncPeriod = in.IPVS.SyncPeriod + out.MinSyncPeriod = in.IPVS.MinSyncPeriod + case config.ProxyModeNFTables: + out.SyncPeriod = in.NFTables.SyncPeriod + out.MinSyncPeriod = in.NFTables.MinSyncPeriod + default: + out.SyncPeriod = in.IPTables.SyncPeriod + out.MinSyncPeriod = in.IPTables.MinSyncPeriod + } + + if len(in.ClusterCIDR) > 0 { + out.DetectLocal.ClusterCIDRs = strings.Split(in.ClusterCIDR, ",") + } return nil } @@ -61,7 +95,17 @@ func Convert_v1alpha1_KubeProxyIPTablesConfiguration_To_config_KubeProxyIPTables return autoConvert_v1alpha1_KubeProxyIPTablesConfiguration_To_config_KubeProxyIPTablesConfiguration(in, out, scope) } +// Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration is defined here, because public conversion is not auto-generated due to existing warnings. +func Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(in *v1alpha1.KubeProxyIPVSConfiguration, out *config.KubeProxyIPVSConfiguration, scope conversion.Scope) error { + return autoConvert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(in, out, scope) +} + // Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration is defined here, because public conversion is not auto-generated due to existing warnings. func Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in *v1alpha1.KubeProxyNFTablesConfiguration, out *config.KubeProxyNFTablesConfiguration, scope conversion.Scope) error { return autoConvert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in, out, scope) } + +// Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration is defined here, because public conversion is not auto-generated due to existing warnings. +func Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error { + return autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in, out, s) +} diff --git a/pkg/proxy/apis/config/v1alpha1/zz_generated.conversion.go b/pkg/proxy/apis/config/v1alpha1/zz_generated.conversion.go index e2624e13de6..b61d6aaeeda 100644 --- a/pkg/proxy/apis/config/v1alpha1/zz_generated.conversion.go +++ b/pkg/proxy/apis/config/v1alpha1/zz_generated.conversion.go @@ -44,11 +44,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*config.DetectLocalConfiguration)(nil), (*v1alpha1.DetectLocalConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(a.(*config.DetectLocalConfiguration), b.(*v1alpha1.DetectLocalConfiguration), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*v1alpha1.KubeProxyConntrackConfiguration)(nil), (*config.KubeProxyConntrackConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_KubeProxyConntrackConfiguration_To_config_KubeProxyConntrackConfiguration(a.(*v1alpha1.KubeProxyConntrackConfiguration), b.(*config.KubeProxyConntrackConfiguration), scope) }); err != nil { @@ -64,11 +59,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1alpha1.KubeProxyIPVSConfiguration)(nil), (*config.KubeProxyIPVSConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(a.(*v1alpha1.KubeProxyIPVSConfiguration), b.(*config.KubeProxyIPVSConfiguration), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*config.KubeProxyIPVSConfiguration)(nil), (*v1alpha1.KubeProxyIPVSConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfiguration(a.(*config.KubeProxyIPVSConfiguration), b.(*v1alpha1.KubeProxyIPVSConfiguration), scope) }); err != nil { @@ -89,6 +79,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*config.DetectLocalConfiguration)(nil), (*v1alpha1.DetectLocalConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(a.(*config.DetectLocalConfiguration), b.(*v1alpha1.DetectLocalConfiguration), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*config.KubeProxyConfiguration)(nil), (*v1alpha1.KubeProxyConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguration(a.(*config.KubeProxyConfiguration), b.(*v1alpha1.KubeProxyConfiguration), scope) }); err != nil { @@ -104,6 +99,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1alpha1.KubeProxyIPVSConfiguration)(nil), (*config.KubeProxyIPVSConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(a.(*v1alpha1.KubeProxyIPVSConfiguration), b.(*config.KubeProxyIPVSConfiguration), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1alpha1.KubeProxyNFTablesConfiguration)(nil), (*config.KubeProxyNFTablesConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(a.(*v1alpha1.KubeProxyNFTablesConfiguration), b.(*config.KubeProxyNFTablesConfiguration), scope) }); err != nil { @@ -125,15 +125,11 @@ func Convert_v1alpha1_DetectLocalConfiguration_To_config_DetectLocalConfiguratio func autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error { out.BridgeInterface = in.BridgeInterface + // WARNING: in.ClusterCIDRs requires manual conversion: does not exist in peer-type out.InterfaceNamePrefix = in.InterfaceNamePrefix return nil } -// Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration is an autogenerated conversion function. -func Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in *config.DetectLocalConfiguration, out *v1alpha1.DetectLocalConfiguration, s conversion.Scope) error { - return autoConvert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(in, out, s) -} - func autoConvert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguration(in *v1alpha1.KubeProxyConfiguration, out *config.KubeProxyConfiguration, s conversion.Scope) error { out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) if err := componentbaseconfigv1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { @@ -164,12 +160,12 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguratio if err := Convert_v1alpha1_DetectLocalConfiguration_To_config_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil { return err } - out.ClusterCIDR = in.ClusterCIDR + // WARNING: in.ClusterCIDR requires manual conversion: does not exist in peer-type out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses)) // WARNING: in.OOMScoreAdj requires manual conversion: does not exist in peer-type // WARNING: in.Conntrack requires manual conversion: does not exist in peer-type out.ConfigSyncPeriod = in.ConfigSyncPeriod - out.PortRange = in.PortRange + // WARNING: in.PortRange requires manual conversion: does not exist in peer-type // WARNING: in.WindowsRunAsService requires manual conversion: does not exist in peer-type return nil } @@ -206,10 +202,10 @@ func autoConvert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguratio if err := Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil { return err } - out.ClusterCIDR = in.ClusterCIDR out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses)) + // WARNING: in.SyncPeriod requires manual conversion: does not exist in peer-type + // WARNING: in.MinSyncPeriod requires manual conversion: does not exist in peer-type out.ConfigSyncPeriod = in.ConfigSyncPeriod - out.PortRange = in.PortRange return nil } @@ -249,16 +245,14 @@ func autoConvert_v1alpha1_KubeProxyIPTablesConfiguration_To_config_KubeProxyIPTa out.MasqueradeBit = (*int32)(unsafe.Pointer(in.MasqueradeBit)) // WARNING: in.MasqueradeAll requires manual conversion: does not exist in peer-type out.LocalhostNodePorts = (*bool)(unsafe.Pointer(in.LocalhostNodePorts)) - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod + // WARNING: in.SyncPeriod requires manual conversion: does not exist in peer-type + // WARNING: in.MinSyncPeriod requires manual conversion: does not exist in peer-type return nil } func autoConvert_config_KubeProxyIPTablesConfiguration_To_v1alpha1_KubeProxyIPTablesConfiguration(in *config.KubeProxyIPTablesConfiguration, out *v1alpha1.KubeProxyIPTablesConfiguration, s conversion.Scope) error { out.MasqueradeBit = (*int32)(unsafe.Pointer(in.MasqueradeBit)) out.LocalhostNodePorts = (*bool)(unsafe.Pointer(in.LocalhostNodePorts)) - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod return nil } @@ -268,8 +262,8 @@ func Convert_config_KubeProxyIPTablesConfiguration_To_v1alpha1_KubeProxyIPTables } func autoConvert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(in *v1alpha1.KubeProxyIPVSConfiguration, out *config.KubeProxyIPVSConfiguration, s conversion.Scope) error { - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod + // WARNING: in.SyncPeriod requires manual conversion: does not exist in peer-type + // WARNING: in.MinSyncPeriod requires manual conversion: does not exist in peer-type out.Scheduler = in.Scheduler out.ExcludeCIDRs = *(*[]string)(unsafe.Pointer(&in.ExcludeCIDRs)) out.StrictARP = in.StrictARP @@ -279,14 +273,7 @@ func autoConvert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConf return nil } -// Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration is an autogenerated conversion function. -func Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(in *v1alpha1.KubeProxyIPVSConfiguration, out *config.KubeProxyIPVSConfiguration, s conversion.Scope) error { - return autoConvert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(in, out, s) -} - func autoConvert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfiguration(in *config.KubeProxyIPVSConfiguration, out *v1alpha1.KubeProxyIPVSConfiguration, s conversion.Scope) error { - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod out.Scheduler = in.Scheduler out.ExcludeCIDRs = *(*[]string)(unsafe.Pointer(&in.ExcludeCIDRs)) out.StrictARP = in.StrictARP @@ -304,15 +291,13 @@ func Convert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfigur func autoConvert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in *v1alpha1.KubeProxyNFTablesConfiguration, out *config.KubeProxyNFTablesConfiguration, s conversion.Scope) error { out.MasqueradeBit = (*int32)(unsafe.Pointer(in.MasqueradeBit)) // WARNING: in.MasqueradeAll requires manual conversion: does not exist in peer-type - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod + // WARNING: in.SyncPeriod requires manual conversion: does not exist in peer-type + // WARNING: in.MinSyncPeriod requires manual conversion: does not exist in peer-type return nil } func autoConvert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration(in *config.KubeProxyNFTablesConfiguration, out *v1alpha1.KubeProxyNFTablesConfiguration, s conversion.Scope) error { out.MasqueradeBit = (*int32)(unsafe.Pointer(in.MasqueradeBit)) - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod return nil } diff --git a/pkg/proxy/apis/config/validation/validation.go b/pkg/proxy/apis/config/validation/validation.go index 3325db88713..3568f50b29e 100644 --- a/pkg/proxy/apis/config/validation/validation.go +++ b/pkg/proxy/apis/config/validation/validation.go @@ -23,7 +23,6 @@ import ( "strconv" "strings" - utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -61,6 +60,15 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList { if config.ConfigSyncPeriod.Duration <= 0 { allErrs = append(allErrs, field.Invalid(newPath.Child("ConfigSyncPeriod"), config.ConfigSyncPeriod, "must be greater than 0")) } + if config.SyncPeriod.Duration <= 0 { + allErrs = append(allErrs, field.Invalid(newPath.Child("SyncPeriod"), config.SyncPeriod, "must be greater than 0")) + } + if config.MinSyncPeriod.Duration < 0 { + allErrs = append(allErrs, field.Invalid(newPath.Child("MinSyncPeriod"), config.MinSyncPeriod, "must be greater than or equal to 0")) + } + if config.MinSyncPeriod.Duration > config.SyncPeriod.Duration { + allErrs = append(allErrs, field.Invalid(newPath.Child("SyncPeriod"), config.MinSyncPeriod, fmt.Sprintf("must be greater than or equal to %s", newPath.Child("MinSyncPeriod").String()))) + } if netutils.ParseIPSloppy(config.BindAddress) == nil { allErrs = append(allErrs, field.Invalid(newPath.Child("BindAddress"), config.BindAddress, "not a valid textual representation of an IP address")) @@ -71,39 +79,11 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList { } allErrs = append(allErrs, validateHostPort(config.MetricsBindAddress, newPath.Child("MetricsBindAddress"))...) - if config.ClusterCIDR != "" { - cidrs := strings.Split(config.ClusterCIDR, ",") - switch { - case len(cidrs) > 2: - allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")) - // if DualStack and two cidrs validate if there is at least one of each IP family - case len(cidrs) == 2: - isDual, err := netutils.IsDualStackCIDRStrings(cidrs) - if err != nil || !isDual { - allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "must be a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")) - } - // if we are here means that len(cidrs) == 1, we need to validate it - default: - if _, _, err := netutils.ParseCIDRSloppy(config.ClusterCIDR); err != nil { - allErrs = append(allErrs, field.Invalid(newPath.Child("ClusterCIDR"), config.ClusterCIDR, "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")) - } - } - } - - if _, err := utilnet.ParsePortRange(config.PortRange); err != nil { - allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)")) - } - allErrs = append(allErrs, validateKubeProxyNodePortAddress(config.NodePortAddresses, newPath.Child("NodePortAddresses"))...) allErrs = append(allErrs, validateShowHiddenMetricsVersion(config.ShowHiddenMetricsForVersion, newPath.Child("ShowHiddenMetricsForVersion"))...) allErrs = append(allErrs, validateDetectLocalMode(config.DetectLocalMode, newPath.Child("DetectLocalMode"))...) - if config.DetectLocalMode == kubeproxyconfig.LocalModeBridgeInterface { - allErrs = append(allErrs, validateInterface(config.DetectLocal.BridgeInterface, newPath.Child("InterfaceName"))...) - } - if config.DetectLocalMode == kubeproxyconfig.LocalModeInterfaceNamePrefix { - allErrs = append(allErrs, validateInterface(config.DetectLocal.InterfaceNamePrefix, newPath.Child("InterfacePrefix"))...) - } + allErrs = append(allErrs, validateDetectLocalConfiguration(config.DetectLocalMode, config.DetectLocal, newPath.Child("DetectLocalConfiguration"))...) allErrs = append(allErrs, logsapi.Validate(&config.Logging, effectiveFeatures, newPath.Child("logging"))...) return allErrs @@ -115,37 +95,12 @@ func validateKubeProxyIPTablesConfiguration(config kubeproxyconfig.KubeProxyIPTa if config.MasqueradeBit != nil && (*config.MasqueradeBit < 0 || *config.MasqueradeBit > 31) { allErrs = append(allErrs, field.Invalid(fldPath.Child("MasqueradeBit"), config.MasqueradeBit, "must be within the range [0, 31]")) } - - if config.SyncPeriod.Duration <= 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.SyncPeriod, "must be greater than 0")) - } - - if config.MinSyncPeriod.Duration < 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("MinSyncPeriod"), config.MinSyncPeriod, "must be greater than or equal to 0")) - } - - if config.MinSyncPeriod.Duration > config.SyncPeriod.Duration { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.MinSyncPeriod, fmt.Sprintf("must be greater than or equal to %s", fldPath.Child("MinSyncPeriod").String()))) - } - return allErrs } func validateKubeProxyIPVSConfiguration(config kubeproxyconfig.KubeProxyIPVSConfiguration, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if config.SyncPeriod.Duration <= 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.SyncPeriod, "must be greater than 0")) - } - - if config.MinSyncPeriod.Duration < 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("MinSyncPeriod"), config.MinSyncPeriod, "must be greater than or equal to 0")) - } - - if config.MinSyncPeriod.Duration > config.SyncPeriod.Duration { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.MinSyncPeriod, fmt.Sprintf("must be greater than or equal to %s", fldPath.Child("MinSyncPeriod").String()))) - } - allErrs = append(allErrs, validateIPVSTimeout(config, fldPath)...) allErrs = append(allErrs, validateIPVSExcludeCIDRs(config.ExcludeCIDRs, fldPath.Child("ExcludeCidrs"))...) @@ -159,18 +114,6 @@ func validateKubeProxyNFTablesConfiguration(config kubeproxyconfig.KubeProxyNFTa allErrs = append(allErrs, field.Invalid(fldPath.Child("MasqueradeBit"), config.MasqueradeBit, "must be within the range [0, 31]")) } - if config.SyncPeriod.Duration <= 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.SyncPeriod, "must be greater than 0")) - } - - if config.MinSyncPeriod.Duration < 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("MinSyncPeriod"), config.MinSyncPeriod, "must be greater than or equal to 0")) - } - - if config.MinSyncPeriod.Duration > config.SyncPeriod.Duration { - allErrs = append(allErrs, field.Invalid(fldPath.Child("SyncPeriod"), config.MinSyncPeriod, fmt.Sprintf("must be greater than or equal to %s", fldPath.Child("MinSyncPeriod").String()))) - } - return allErrs } @@ -366,3 +309,41 @@ func validateInterface(iface string, fldPath *field.Path) field.ErrorList { } return allErrs } + +func validateDualStackCIDRStrings(cidrStrings []string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + switch { + case len(cidrStrings) == 0: + allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must contain at least one CIDR")) + case len(cidrStrings) > 2: + allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")) + default: + for i, cidrString := range cidrStrings { + if _, _, err := netutils.ParseCIDRSloppy(cidrString); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Index(i), cidrString, "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")) + } + } + if len(cidrStrings) == 2 { + ifDualStack, err := netutils.IsDualStackCIDRStrings(cidrStrings) + if err == nil && !ifDualStack { + allErrs = append(allErrs, field.Invalid(fldPath, cidrStrings, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")) + } + } + } + return allErrs +} + +func validateDetectLocalConfiguration(mode kubeproxyconfig.LocalMode, config kubeproxyconfig.DetectLocalConfiguration, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + switch mode { + case kubeproxyconfig.LocalModeBridgeInterface: + allErrs = append(allErrs, validateInterface(config.BridgeInterface, fldPath.Child("InterfaceName"))...) + case kubeproxyconfig.LocalModeInterfaceNamePrefix: + allErrs = append(allErrs, validateInterface(config.InterfaceNamePrefix, fldPath.Child("InterfacePrefix"))...) + case kubeproxyconfig.LocalModeClusterCIDR: + if len(config.ClusterCIDRs) > 0 { + allErrs = append(allErrs, validateDualStackCIDRStrings(config.ClusterCIDRs, fldPath.Child("ClusterCIDRs"))...) + } + } + return allErrs +} diff --git a/pkg/proxy/apis/config/validation/validation_other_test.go b/pkg/proxy/apis/config/validation/validation_other_test.go deleted file mode 100644 index 330b8f9b0f9..00000000000 --- a/pkg/proxy/apis/config/validation/validation_other_test.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build !windows -// +build !windows - -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package validation - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/validation/field" - kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" -) - -var ( - kubeProxyConfigNewPath = field.NewPath("KubeProxyConfiguration") - osKubeProxyConfigTestCases = map[string]struct { - mutateConfigFunc func(*kubeproxyconfig.KubeProxyConfiguration) - expectedErrs field.ErrorList - }{ - // Windows doesn't support IPVS, so this test will fail. - "IPVS mode selected without providing required SyncPeriod": { - mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.Mode = kubeproxyconfig.ProxyModeIPVS - }, - expectedErrs: field.ErrorList{field.Invalid(kubeProxyConfigNewPath.Child("KubeProxyIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0")}, - }, - } -) diff --git a/pkg/proxy/apis/config/validation/validation_test.go b/pkg/proxy/apis/config/validation/validation_test.go index 2f55f76c15a..cd964bcfba8 100644 --- a/pkg/proxy/apis/config/validation/validation_test.go +++ b/pkg/proxy/apis/config/validation/validation_test.go @@ -36,12 +36,14 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { BindAddress: "192.168.59.103", HealthzBindAddress: "0.0.0.0:10256", MetricsBindAddress: "127.0.0.1:10249", - ClusterCIDR: "192.168.59.0/24", - ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second}, - IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, + DetectLocalMode: kubeproxyconfig.LocalModeClusterCIDR, + DetectLocal: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"192.168.59.0/24"}, }, + SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, + MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, + ConfigSyncPeriod: metav1.Duration{Duration: 1 * time.Second}, + IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{}, Linux: kubeproxyconfig.KubeProxyLinuxConfiguration{ Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ MaxPerCore: ptr.To[int32](1), @@ -70,10 +72,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { config.Mode = kubeproxyconfig.ProxyModeKernelspace } else { config.Mode = kubeproxyconfig.ProxyModeIPVS - config.IPVS = kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - } } }, }, @@ -87,7 +85,7 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { config.BindAddress = "fd00:192:168:59::103" config.HealthzBindAddress = "" config.MetricsBindAddress = "[::1]:10249" - config.ClusterCIDR = "fd00:192:168:59::/64" + config.DetectLocal.ClusterCIDRs = []string{"fd00:192:168:59::/64"} }, }, "alternate healthz port": { @@ -97,12 +95,12 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { }, "ClusterCIDR is wrong IP family": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.ClusterCIDR = "fd00:192:168::/64" + config.DetectLocal.ClusterCIDRs = []string{"fd00:192:168:59::/64"} }, }, "ClusterCIDR is dual-stack": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64" + config.DetectLocal.ClusterCIDRs = []string{"192.168.59.0/24", "fd00:192:168::/64"} }, }, "LocalModeInterfaceNamePrefix": { @@ -139,41 +137,31 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { }, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MetricsBindAddress"), "127.0.0.1", "must be IP:port")}, }, - "ClusterCIDR missing subset range": { - mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.ClusterCIDR = "192.168.59.0" - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")}, - }, - "Invalid number of ClusterCIDRs": { - mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.ClusterCIDR = "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16" - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterCIDR"), "192.168.59.0/24,fd00:192:168::/64,10.0.0.0/16", "only one CIDR allowed or a valid DualStack CIDR (e.g. 10.100.0.0/16,fde4:8dba:82e1::/48)")}, - }, "ConfigSyncPeriod must be > 0": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { config.ConfigSyncPeriod = metav1.Duration{Duration: -1 * time.Second} }, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ConfigSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than 0")}, }, - "interfacePrefix is empty": { + "SyncPeriod must be > 0": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.DetectLocalMode = kubeproxyconfig.LocalModeInterfaceNamePrefix - config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{ - InterfaceNamePrefix: "", - } + config.SyncPeriod = metav1.Duration{Duration: -5 * time.Second} }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfacePrefix"), "", "must not be empty")}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SyncPeriod"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than 0"), + field.Invalid(newPath.Child("SyncPeriod"), metav1.Duration{Duration: 2 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.MinSyncPeriod")}, }, - "bridgeInterfaceName is empty": { + "MinSyncPeriod must be > 0": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { - config.DetectLocalMode = kubeproxyconfig.LocalModeBridgeInterface - config.DetectLocal = kubeproxyconfig.DetectLocalConfiguration{ - InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix - } + config.MinSyncPeriod = metav1.Duration{Duration: -2 * time.Second} }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("InterfaceName"), "", "must not be empty")}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("MinSyncPeriod"), metav1.Duration{Duration: -2 * time.Second}, "must be greater than or equal to 0")}, + }, + "SyncPeriod must be >= MinSyncPeriod": { + mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { + config.SyncPeriod = metav1.Duration{Duration: 1 * time.Second} + config.MinSyncPeriod = metav1.Duration{Duration: 5 * time.Second} + }, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.MinSyncPeriod")}, }, "invalid DetectLocalMode": { mutateConfigFunc: func(config *kubeproxyconfig.KubeProxyConfiguration) { @@ -191,10 +179,6 @@ func TestValidateKubeProxyConfiguration(t *testing.T) { }, } - for name, testCase := range osKubeProxyConfigTestCases { - testCases[name] = testCase - } - for name, testCase := range testCases { t.Run(name, func(t *testing.T) { config := baseConfig.DeepCopy() @@ -216,53 +200,18 @@ func TestValidateKubeProxyIPTablesConfiguration(t *testing.T) { config kubeproxyconfig.KubeProxyIPTablesConfiguration expectedErrs field.ErrorList }{ - "valid iptables config": { - config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, - }, - expectedErrs: field.ErrorList{}, - }, "valid custom MasqueradeBit": { config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ MasqueradeBit: ptr.To[int32](5), - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, }, expectedErrs: field.ErrorList{}, }, - "SyncPeriod must be > 0": { - config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - SyncPeriod: metav1.Duration{Duration: -5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than 0"), - field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: 2 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPTablesConfiguration.MinSyncPeriod")}, - }, - "MinSyncPeriod must be > 0": { - config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - MasqueradeBit: ptr.To[int32](5), - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.MinSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0")}, - }, "MasqueradeBit cannot be < 0": { config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ MasqueradeBit: ptr.To[int32](-10), - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, }, expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.MasqueradeBit"), ptr.To[int32](-10), "must be within the range [0, 31]")}, }, - "SyncPeriod must be >= MinSyncPeriod": { - config: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - MasqueradeBit: ptr.To[int32](5), - SyncPeriod: metav1.Duration{Duration: 1 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPTablesConfiguration.SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPTablesConfiguration.MinSyncPeriod")}, - }, } { t.Run(name, func(t *testing.T) { errs := validateKubeProxyIPTablesConfiguration(testCase.config, newPath.Child("KubeIPTablesConfiguration")) @@ -277,60 +226,8 @@ func TestValidateKubeProxyIPVSConfiguration(t *testing.T) { config kubeproxyconfig.KubeProxyIPVSConfiguration expectedErrs field.ErrorList }{ - "SyncPeriod is not greater than 0": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: -5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 2 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: -5 * time.Second}, "must be greater than 0"), - field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 2 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")}, - }, - "SyncPeriod cannot be 0": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 0 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 0}, "must be greater than 0"), - field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 10 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")}, - }, - "MinSyncPeriod cannot be less than 0": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: -1 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.MinSyncPeriod"), metav1.Duration{Duration: -1 * time.Second}, "must be greater than or equal to 0")}, - }, - "SyncPeriod must be greater than MinSyncPeriod": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 1 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - }, - expectedErrs: field.ErrorList{field.Invalid(newPath.Child("KubeIPVSConfiguration.SyncPeriod"), metav1.Duration{Duration: 5 * time.Second}, "must be greater than or equal to KubeProxyConfiguration.KubeIPVSConfiguration.MinSyncPeriod")}, - }, - "SyncPeriod == MinSyncPeriod": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - }, - expectedErrs: field.ErrorList{}, - }, - "SyncPeriod should be > MinSyncPeriod": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 10 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - }, - expectedErrs: field.ErrorList{}, - }, - "MinSyncPeriod can be 0": { - config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, - MinSyncPeriod: metav1.Duration{Duration: 0 * time.Second}, - }, - expectedErrs: field.ErrorList{}, - }, "IPVS Timeout can be 0": { config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, TCPTimeout: metav1.Duration{Duration: 0 * time.Second}, TCPFinTimeout: metav1.Duration{Duration: 0 * time.Second}, UDPTimeout: metav1.Duration{Duration: 0 * time.Second}, @@ -339,7 +236,6 @@ func TestValidateKubeProxyIPVSConfiguration(t *testing.T) { }, "IPVS Timeout > 0": { config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, TCPTimeout: metav1.Duration{Duration: 1 * time.Second}, TCPFinTimeout: metav1.Duration{Duration: 2 * time.Second}, UDPTimeout: metav1.Duration{Duration: 3 * time.Second}, @@ -348,7 +244,6 @@ func TestValidateKubeProxyIPVSConfiguration(t *testing.T) { }, "TCP,TCPFin,UDP Timeouts < 0": { config: kubeproxyconfig.KubeProxyIPVSConfiguration{ - SyncPeriod: metav1.Duration{Duration: 5 * time.Second}, TCPTimeout: metav1.Duration{Duration: -1 * time.Second}, UDPTimeout: metav1.Duration{Duration: -1 * time.Second}, TCPFinTimeout: metav1.Duration{Duration: -1 * time.Second}, @@ -842,3 +737,154 @@ func TestValidateKubeProxyExcludeCIDRs(t *testing.T) { }) } } + +func TestValidateDetectLocalConfiguration(t *testing.T) { + newPath := field.NewPath("KubeProxyConfiguration") + + testCases := []struct { + name string + mode kubeproxyconfig.LocalMode + config kubeproxyconfig.DetectLocalConfiguration + expectedErrs field.ErrorList + }{ + { + name: "valid interface name prefix", + mode: kubeproxyconfig.LocalModeInterfaceNamePrefix, + config: kubeproxyconfig.DetectLocalConfiguration{ + InterfaceNamePrefix: "vethabcde", + }, + expectedErrs: field.ErrorList{}, + }, + { + name: "valid bridge interface", + mode: kubeproxyconfig.LocalModeBridgeInterface, + config: kubeproxyconfig.DetectLocalConfiguration{ + BridgeInterface: "avz", + }, + expectedErrs: field.ErrorList{}, + }, + { + name: "interfacePrefix is empty", + mode: kubeproxyconfig.LocalModeInterfaceNamePrefix, + config: kubeproxyconfig.DetectLocalConfiguration{ + InterfaceNamePrefix: "", + }, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("InterfacePrefix"), "", "must not be empty")}, + }, + { + name: "bridgeInterfaceName is empty", + mode: kubeproxyconfig.LocalModeBridgeInterface, + config: kubeproxyconfig.DetectLocalConfiguration{ + InterfaceNamePrefix: "eth0", // we won't care about prefix since mode is not prefix + }, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("InterfaceName"), "", "must not be empty")}, + }, + { + name: "valid cluster cidr", + mode: kubeproxyconfig.LocalModeClusterCIDR, + config: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"192.168.59.0/24", "fd00:192:168::/64"}, + }, + expectedErrs: field.ErrorList{}, + }, + { + name: "invalid number of cluster cidrs", + mode: kubeproxyconfig.LocalModeClusterCIDR, + config: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"192.168.59.0/24", "fd00:192:168::/64", "10.0.0.0/16"}, + }, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("ClusterCIDRs"), []string{"192.168.59.0/24", "fd00:192:168::/64", "10.0.0.0/16"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")}, + }, + { + name: "invalid cluster cidr", + mode: kubeproxyconfig.LocalModeClusterCIDR, + config: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{"192.168.59.0"}, + }, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DetectLocal").Child("ClusterCIDRs").Index(0), "192.168.59.0", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")}, + }, + { + name: "empty cluster cidrs with cluster cidr mode", + mode: kubeproxyconfig.LocalModeClusterCIDR, + config: kubeproxyconfig.DetectLocalConfiguration{ + ClusterCIDRs: []string{}, + }, + expectedErrs: field.ErrorList{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + errs := validateDetectLocalConfiguration(tc.mode, tc.config, newPath.Child("DetectLocal")) + assert.Equalf(t, len(tc.expectedErrs), len(errs), + "expected %d errors, got %d errors: %v", len(tc.expectedErrs), len(errs), errs, + ) + for i, err := range errs { + assert.Equal(t, tc.expectedErrs[i].Error(), err.Error()) + } + }) + } +} + +func TestValidateDualStackCIDRStrings(t *testing.T) { + newPath := field.NewPath("KubeProxyConfiguration") + + testCases := []struct { + name string + cidrStrings []string + expectedErrs field.ErrorList + }{ + { + name: "empty cidr string", + cidrStrings: []string{}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{}, "must contain at least one CIDR")}, + }, + { + name: "single ipv4 cidr", + cidrStrings: []string{"192.168.0.0/16"}, + expectedErrs: field.ErrorList{}, + }, + { + name: "single ipv6 cidr", + cidrStrings: []string{"fd00:10:96::/112"}, + expectedErrs: field.ErrorList{}, + }, + { + name: "dual stack cidr pair", + cidrStrings: []string{"172.16.200.0/24", "fde4:8dba:82e1::/48"}, + expectedErrs: field.ErrorList{}, + }, + { + name: "multiple ipv4 cidrs", + cidrStrings: []string{"10.100.0.0/16", "192.168.0.0/16", "fde4:8dba:82e1::/48"}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{"10.100.0.0/16", "192.168.0.0/16", "fde4:8dba:82e1::/48"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")}, + }, + { + name: "multiple ipv6 cidrs", + cidrStrings: []string{"fd00:10:96::/112", "fde4:8dba:82e1::/48"}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList"), []string{"fd00:10:96::/112", "fde4:8dba:82e1::/48"}, "must be a either a single CIDR or dual-stack pair of CIDRs (e.g. [10.100.0.0/16, fde4:8dba:82e1::/48]")}, + }, + { + name: "malformed ipv4 cidr", + cidrStrings: []string{"fde4:8dba:82e1::/48", "172.16.200.0:24"}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList").Index(1), "172.16.200.0:24", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")}, + }, + { + name: "malformed ipv6 cidr", + cidrStrings: []string{"fd00:10:96::", "192.168.0.0/16"}, + expectedErrs: field.ErrorList{field.Invalid(newPath.Child("DualStackCIDRList").Index(0), "fd00:10:96::", "must be a valid CIDR block (e.g. 10.100.0.0/16 or fde4:8dba:82e1::/48)")}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + errs := validateDualStackCIDRStrings(tc.cidrStrings, newPath.Child("DualStackCIDRList")) + assert.Equalf(t, len(tc.expectedErrs), len(errs), + "expected %d errors, got %d errors: %v", len(tc.expectedErrs), len(errs), errs, + ) + for i, err := range errs { + assert.Equal(t, tc.expectedErrs[i].Error(), err.Error()) + } + }) + } +} diff --git a/pkg/proxy/apis/config/validation/validation_windows_test.go b/pkg/proxy/apis/config/validation/validation_windows_test.go deleted file mode 100644 index 49e1eb2889c..00000000000 --- a/pkg/proxy/apis/config/validation/validation_windows_test.go +++ /dev/null @@ -1,32 +0,0 @@ -//go:build windows -// +build windows - -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package validation - -import ( - "k8s.io/apimachinery/pkg/util/validation/field" - kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" -) - -var ( - osKubeProxyConfigTestCases = map[string]struct { - mutateConfigFunc func(*kubeproxyconfig.KubeProxyConfiguration) - expectedErrs field.ErrorList - }{} -) diff --git a/pkg/proxy/apis/config/zz_generated.deepcopy.go b/pkg/proxy/apis/config/zz_generated.deepcopy.go index 57c07f696dd..9a3cec904bc 100644 --- a/pkg/proxy/apis/config/zz_generated.deepcopy.go +++ b/pkg/proxy/apis/config/zz_generated.deepcopy.go @@ -29,6 +29,11 @@ import ( // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DetectLocalConfiguration) DeepCopyInto(out *DetectLocalConfiguration) { *out = *in + if in.ClusterCIDRs != nil { + in, out := &in.ClusterCIDRs, &out.ClusterCIDRs + *out = make([]string, len(*in)) + copy(*out, *in) + } return } @@ -61,12 +66,14 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) { in.IPVS.DeepCopyInto(&out.IPVS) out.Winkernel = in.Winkernel in.NFTables.DeepCopyInto(&out.NFTables) - out.DetectLocal = in.DetectLocal + in.DetectLocal.DeepCopyInto(&out.DetectLocal) if in.NodePortAddresses != nil { in, out := &in.NodePortAddresses, &out.NodePortAddresses *out = make([]string, len(*in)) copy(*out, *in) } + out.SyncPeriod = in.SyncPeriod + out.MinSyncPeriod = in.MinSyncPeriod out.ConfigSyncPeriod = in.ConfigSyncPeriod return } @@ -140,8 +147,6 @@ func (in *KubeProxyIPTablesConfiguration) DeepCopyInto(out *KubeProxyIPTablesCon *out = new(bool) **out = **in } - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod return } @@ -158,8 +163,6 @@ func (in *KubeProxyIPTablesConfiguration) DeepCopy() *KubeProxyIPTablesConfigura // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubeProxyIPVSConfiguration) DeepCopyInto(out *KubeProxyIPVSConfiguration) { *out = *in - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod if in.ExcludeCIDRs != nil { in, out := &in.ExcludeCIDRs, &out.ExcludeCIDRs *out = make([]string, len(*in)) @@ -211,8 +214,6 @@ func (in *KubeProxyNFTablesConfiguration) DeepCopyInto(out *KubeProxyNFTablesCon *out = new(int32) **out = **in } - out.SyncPeriod = in.SyncPeriod - out.MinSyncPeriod = in.MinSyncPeriod return }