Add a dummy nftables kube-proxy backend which is just a copy of iptables
This commit is contained in:
		| @@ -553,6 +553,7 @@ API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,V | |||||||
| API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,VolumeConfiguration,FlexVolumePluginDir | API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,VolumeConfiguration,FlexVolumePluginDir | ||||||
| API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,VolumeConfiguration,PersistentVolumeRecyclerConfiguration | API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,VolumeConfiguration,PersistentVolumeRecyclerConfiguration | ||||||
| API rule violation: names_match,k8s.io/kube-proxy/config/v1alpha1,KubeProxyConfiguration,IPTables | API rule violation: names_match,k8s.io/kube-proxy/config/v1alpha1,KubeProxyConfiguration,IPTables | ||||||
|  | API rule violation: names_match,k8s.io/kube-proxy/config/v1alpha1,KubeProxyConfiguration,NFTables | ||||||
| API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,IPTablesDropBit | API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,IPTablesDropBit | ||||||
| API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,IPTablesMasqueradeBit | API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,IPTablesMasqueradeBit | ||||||
| API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ResolverConfig | API rule violation: names_match,k8s.io/kubelet/config/v1beta1,KubeletConfiguration,ResolverConfig | ||||||
|   | |||||||
| @@ -50,6 +50,7 @@ import ( | |||||||
| 	utilipset "k8s.io/kubernetes/pkg/proxy/ipvs/ipset" | 	utilipset "k8s.io/kubernetes/pkg/proxy/ipvs/ipset" | ||||||
| 	utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util" | 	utilipvs "k8s.io/kubernetes/pkg/proxy/ipvs/util" | ||||||
| 	proxymetrics "k8s.io/kubernetes/pkg/proxy/metrics" | 	proxymetrics "k8s.io/kubernetes/pkg/proxy/metrics" | ||||||
|  | 	"k8s.io/kubernetes/pkg/proxy/nftables" | ||||||
| 	proxyutil "k8s.io/kubernetes/pkg/proxy/util" | 	proxyutil "k8s.io/kubernetes/pkg/proxy/util" | ||||||
| 	proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables" | 	proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables" | ||||||
| 	utiliptables "k8s.io/kubernetes/pkg/util/iptables" | 	utiliptables "k8s.io/kubernetes/pkg/util/iptables" | ||||||
| @@ -282,6 +283,67 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio | |||||||
| 				initOnly, | 				initOnly, | ||||||
| 			) | 			) | ||||||
| 		} | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("unable to create proxier: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} else if config.Mode == proxyconfigapi.ProxyModeNFTables { | ||||||
|  | 		klog.InfoS("Using nftables Proxier") | ||||||
|  |  | ||||||
|  | 		if dualStack { | ||||||
|  | 			// Always ordered to match []ipt | ||||||
|  | 			var localDetectors [2]proxyutiliptables.LocalTrafficDetector | ||||||
|  | 			localDetectors, err = getDualStackLocalDetectorTuple(config.DetectLocalMode, config, s.podCIDRs) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, fmt.Errorf("unable to create proxier: %v", err) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// TODO this has side effects that should only happen when Run() is invoked. | ||||||
|  | 			proxier, err = nftables.NewDualStackProxier( | ||||||
|  | 				ipt, | ||||||
|  | 				utilsysctl.New(), | ||||||
|  | 				execer, | ||||||
|  | 				config.NFTables.SyncPeriod.Duration, | ||||||
|  | 				config.NFTables.MinSyncPeriod.Duration, | ||||||
|  | 				config.NFTables.MasqueradeAll, | ||||||
|  | 				*config.NFTables.LocalhostNodePorts, | ||||||
|  | 				int(*config.NFTables.MasqueradeBit), | ||||||
|  | 				localDetectors, | ||||||
|  | 				s.Hostname, | ||||||
|  | 				s.NodeIPs, | ||||||
|  | 				s.Recorder, | ||||||
|  | 				s.HealthzServer, | ||||||
|  | 				config.NodePortAddresses, | ||||||
|  | 				initOnly, | ||||||
|  | 			) | ||||||
|  | 		} else { | ||||||
|  | 			// Create a single-stack proxier if and only if the node does not support dual-stack (i.e, no iptables support). | ||||||
|  | 			var localDetector proxyutiliptables.LocalTrafficDetector | ||||||
|  | 			localDetector, err = getLocalDetector(s.PrimaryIPFamily, config.DetectLocalMode, config, s.podCIDRs) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, fmt.Errorf("unable to create proxier: %v", err) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// TODO this has side effects that should only happen when Run() is invoked. | ||||||
|  | 			proxier, err = nftables.NewProxier( | ||||||
|  | 				s.PrimaryIPFamily, | ||||||
|  | 				iptInterface, | ||||||
|  | 				utilsysctl.New(), | ||||||
|  | 				execer, | ||||||
|  | 				config.NFTables.SyncPeriod.Duration, | ||||||
|  | 				config.NFTables.MinSyncPeriod.Duration, | ||||||
|  | 				config.NFTables.MasqueradeAll, | ||||||
|  | 				*config.NFTables.LocalhostNodePorts, | ||||||
|  | 				int(*config.NFTables.MasqueradeBit), | ||||||
|  | 				localDetector, | ||||||
|  | 				s.Hostname, | ||||||
|  | 				s.NodeIPs[s.PrimaryIPFamily], | ||||||
|  | 				s.Recorder, | ||||||
|  | 				s.HealthzServer, | ||||||
|  | 				config.NodePortAddresses, | ||||||
|  | 				initOnly, | ||||||
|  | 			) | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("unable to create proxier: %v", err) | 			return nil, fmt.Errorf("unable to create proxier: %v", err) | ||||||
| 		} | 		} | ||||||
| @@ -492,6 +554,7 @@ func cleanupAndExit() error { | |||||||
| 	for _, ipt := range ipts { | 	for _, ipt := range ipts { | ||||||
| 		encounteredError = iptables.CleanupLeftovers(ipt) || encounteredError | 		encounteredError = iptables.CleanupLeftovers(ipt) || encounteredError | ||||||
| 		encounteredError = ipvs.CleanupLeftovers(ipvsInterface, ipt, ipsetInterface) || encounteredError | 		encounteredError = ipvs.CleanupLeftovers(ipvsInterface, ipt, ipsetInterface) || encounteredError | ||||||
|  | 		encounteredError = nftables.CleanupLeftovers(ipt) || encounteredError | ||||||
| 	} | 	} | ||||||
| 	if encounteredError { | 	if encounteredError { | ||||||
| 		return errors.New("encountered an error while tearing down rules") | 		return errors.New("encountered an error while tearing down rules") | ||||||
|   | |||||||
| @@ -74,6 +74,12 @@ ipvs: | |||||||
|   excludeCIDRs: |   excludeCIDRs: | ||||||
|     - "10.20.30.40/16" |     - "10.20.30.40/16" | ||||||
|     - "fd00:1::0/64" |     - "fd00:1::0/64" | ||||||
|  | nftables: | ||||||
|  |   masqueradeAll: true | ||||||
|  |   masqueradeBit: 18 | ||||||
|  |   minSyncPeriod: 10s | ||||||
|  |   syncPeriod: 60s | ||||||
|  |   localhostNodePorts: false | ||||||
| kind: KubeProxyConfiguration | kind: KubeProxyConfiguration | ||||||
| metricsBindAddress: "%s" | metricsBindAddress: "%s" | ||||||
| mode: "%s" | mode: "%s" | ||||||
| @@ -218,6 +224,13 @@ nodePortAddresses: | |||||||
| 				SyncPeriod:    metav1.Duration{Duration: 60 * 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{ | ||||||
|  | 				MasqueradeAll:      true, | ||||||
|  | 				MasqueradeBit:      ptr.To[int32](18), | ||||||
|  | 				LocalhostNodePorts: ptr.To(false), | ||||||
|  | 				MinSyncPeriod:      metav1.Duration{Duration: 10 * time.Second}, | ||||||
|  | 				SyncPeriod:         metav1.Duration{Duration: 60 * time.Second}, | ||||||
|  | 			}, | ||||||
| 			MetricsBindAddress: tc.metricsBindAddress, | 			MetricsBindAddress: tc.metricsBindAddress, | ||||||
| 			Mode:               kubeproxyconfig.ProxyMode(tc.mode), | 			Mode:               kubeproxyconfig.ProxyMode(tc.mode), | ||||||
| 			OOMScoreAdj:        ptr.To[int32](17), | 			OOMScoreAdj:        ptr.To[int32](17), | ||||||
|   | |||||||
| @@ -564,6 +564,13 @@ const ( | |||||||
| 	// Robust VolumeManager reconstruction after kubelet restart. | 	// Robust VolumeManager reconstruction after kubelet restart. | ||||||
| 	NewVolumeManagerReconstruction featuregate.Feature = "NewVolumeManagerReconstruction" | 	NewVolumeManagerReconstruction featuregate.Feature = "NewVolumeManagerReconstruction" | ||||||
|  |  | ||||||
|  | 	// owner: @danwinship | ||||||
|  | 	// kep: https://kep.k8s.io/3866 | ||||||
|  | 	// alpha: v1.29 | ||||||
|  | 	// | ||||||
|  | 	// Allows running kube-proxy with `--mode nftables`. | ||||||
|  | 	NFTablesProxyMode featuregate.Feature = "NFTablesProxyMode" | ||||||
|  |  | ||||||
| 	// owner: @aravindhp @LorbusChris | 	// owner: @aravindhp @LorbusChris | ||||||
| 	// kep: http://kep.k8s.io/2271 | 	// kep: http://kep.k8s.io/2271 | ||||||
| 	// alpha: v1.27 | 	// alpha: v1.27 | ||||||
| @@ -1103,6 +1110,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS | |||||||
|  |  | ||||||
| 	NewVolumeManagerReconstruction: {Default: true, PreRelease: featuregate.Beta}, | 	NewVolumeManagerReconstruction: {Default: true, PreRelease: featuregate.Beta}, | ||||||
|  |  | ||||||
|  | 	NFTablesProxyMode: {Default: false, PreRelease: featuregate.Alpha}, | ||||||
|  |  | ||||||
| 	NodeLogQuery: {Default: false, PreRelease: featuregate.Alpha}, | 	NodeLogQuery: {Default: false, PreRelease: featuregate.Alpha}, | ||||||
|  |  | ||||||
| 	NodeOutOfServiceVolumeDetach: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 | 	NodeOutOfServiceVolumeDetach: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 | ||||||
|   | |||||||
							
								
								
									
										62
									
								
								pkg/generated/openapi/zz_generated.openapi.go
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										62
									
								
								pkg/generated/openapi/zz_generated.openapi.go
									
									
									
										generated
									
									
									
								
							| @@ -1095,6 +1095,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA | |||||||
| 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyConntrackConfiguration":                                     schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyConntrackConfiguration(ref), | 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyConntrackConfiguration":                                     schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyConntrackConfiguration(ref), | ||||||
| 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPTablesConfiguration":                                      schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPTablesConfiguration(ref), | 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPTablesConfiguration":                                      schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPTablesConfiguration(ref), | ||||||
| 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration":                                          schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPVSConfiguration(ref), | 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration":                                          schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPVSConfiguration(ref), | ||||||
|  | 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyNFTablesConfiguration":                                      schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyNFTablesConfiguration(ref), | ||||||
| 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyWinkernelConfiguration":                                     schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref), | 		"k8s.io/kube-proxy/config/v1alpha1.KubeProxyWinkernelConfiguration":                                     schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref), | ||||||
| 		"k8s.io/kube-scheduler/config/v1.DefaultPreemptionArgs":                                                 schema_k8sio_kube_scheduler_config_v1_DefaultPreemptionArgs(ref), | 		"k8s.io/kube-scheduler/config/v1.DefaultPreemptionArgs":                                                 schema_k8sio_kube_scheduler_config_v1_DefaultPreemptionArgs(ref), | ||||||
| 		"k8s.io/kube-scheduler/config/v1.Extender":                                                              schema_k8sio_kube_scheduler_config_v1_Extender(ref), | 		"k8s.io/kube-scheduler/config/v1.Extender":                                                              schema_k8sio_kube_scheduler_config_v1_Extender(ref), | ||||||
| @@ -54415,6 +54416,13 @@ func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyConfiguration(ref common.R | |||||||
| 							Ref:         ref("k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration"), | 							Ref:         ref("k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration"), | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|  | 					"nftables": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "nftables contains nftables-related configuration options.", | ||||||
|  | 							Default:     map[string]interface{}{}, | ||||||
|  | 							Ref:         ref("k8s.io/kube-proxy/config/v1alpha1.KubeProxyNFTablesConfiguration"), | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
| 					"winkernel": { | 					"winkernel": { | ||||||
| 						SchemaProps: spec.SchemaProps{ | 						SchemaProps: spec.SchemaProps{ | ||||||
| 							Description: "winkernel contains winkernel-related configuration options.", | 							Description: "winkernel contains winkernel-related configuration options.", | ||||||
| @@ -54489,11 +54497,11 @@ func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyConfiguration(ref common.R | |||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Required: []string{"clientConnection", "hostnameOverride", "bindAddress", "healthzBindAddress", "metricsBindAddress", "bindAddressHardFail", "enableProfiling", "showHiddenMetricsForVersion", "mode", "iptables", "ipvs", "winkernel", "detectLocalMode", "detectLocal", "clusterCIDR", "nodePortAddresses", "oomScoreAdj", "conntrack", "configSyncPeriod", "portRange"}, | 				Required: []string{"clientConnection", "hostnameOverride", "bindAddress", "healthzBindAddress", "metricsBindAddress", "bindAddressHardFail", "enableProfiling", "showHiddenMetricsForVersion", "mode", "iptables", "ipvs", "nftables", "winkernel", "detectLocalMode", "detectLocal", "clusterCIDR", "nodePortAddresses", "oomScoreAdj", "conntrack", "configSyncPeriod", "portRange"}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Dependencies: []string{ | 		Dependencies: []string{ | ||||||
| 			"k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/component-base/config/v1alpha1.ClientConnectionConfiguration", "k8s.io/component-base/logs/api/v1.LoggingConfiguration", "k8s.io/kube-proxy/config/v1alpha1.DetectLocalConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyConntrackConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPTablesConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyWinkernelConfiguration"}, | 			"k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/component-base/config/v1alpha1.ClientConnectionConfiguration", "k8s.io/component-base/logs/api/v1.LoggingConfiguration", "k8s.io/kube-proxy/config/v1alpha1.DetectLocalConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyConntrackConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPTablesConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyNFTablesConfiguration", "k8s.io/kube-proxy/config/v1alpha1.KubeProxyWinkernelConfiguration"}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -54686,6 +54694,56 @@ func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPVSConfiguration(ref comm | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyNFTablesConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||||
|  | 	return common.OpenAPIDefinition{ | ||||||
|  | 		Schema: spec.Schema{ | ||||||
|  | 			SchemaProps: spec.SchemaProps{ | ||||||
|  | 				Description: "KubeProxyNFTablesConfiguration contains nftables-related configuration details for the Kubernetes proxy server.", | ||||||
|  | 				Type:        []string{"object"}, | ||||||
|  | 				Properties: map[string]spec.Schema{ | ||||||
|  | 					"masqueradeBit": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "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].", | ||||||
|  | 							Type:        []string{"integer"}, | ||||||
|  | 							Format:      "int32", | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					"masqueradeAll": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "masqueradeAll tells kube-proxy to SNAT all traffic sent to Service cluster IPs, when using the nftables mode. This may be required with some CNI plugins.", | ||||||
|  | 							Default:     false, | ||||||
|  | 							Type:        []string{"boolean"}, | ||||||
|  | 							Format:      "", | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					"localhostNodePorts": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "localhostNodePorts, if false, tells kube-proxy to disable the legacy behavior of allowing NodePort services to be accessed via localhost. FIXME: remove.", | ||||||
|  | 							Type:        []string{"boolean"}, | ||||||
|  | 							Format:      "", | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					"syncPeriod": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "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.", | ||||||
|  | 							Ref:         ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					"minSyncPeriod": { | ||||||
|  | 						SchemaProps: spec.SchemaProps{ | ||||||
|  | 							Description: "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.", | ||||||
|  | 							Ref:         ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				Required: []string{"masqueradeBit", "masqueradeAll", "localhostNodePorts", "syncPeriod", "minSyncPeriod"}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		Dependencies: []string{ | ||||||
|  | 			"k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { | func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { | ||||||
| 	return common.OpenAPIDefinition{ | 	return common.OpenAPIDefinition{ | ||||||
| 		Schema: spec.Schema{ | 		Schema: spec.Schema{ | ||||||
|   | |||||||
| @@ -43,6 +43,8 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} { | |||||||
| 			obj.HealthzBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536)) | 			obj.HealthzBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536)) | ||||||
| 			obj.IPTables.MasqueradeBit = ptr.To(c.Int31()) | 			obj.IPTables.MasqueradeBit = ptr.To(c.Int31()) | ||||||
| 			obj.IPTables.LocalhostNodePorts = ptr.To(c.RandBool()) | 			obj.IPTables.LocalhostNodePorts = ptr.To(c.RandBool()) | ||||||
|  | 			obj.NFTables.MasqueradeBit = ptr.To(c.Int31()) | ||||||
|  | 			obj.NFTables.LocalhostNodePorts = ptr.To(c.RandBool()) | ||||||
| 			obj.MetricsBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536)) | 			obj.MetricsBindAddress = fmt.Sprintf("%d.%d.%d.%d:%d", c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(256), c.Intn(65536)) | ||||||
| 			obj.OOMScoreAdj = ptr.To(c.Int31()) | 			obj.OOMScoreAdj = ptr.To(c.Int31()) | ||||||
| 			obj.ClientConnection.ContentType = "bar" | 			obj.ClientConnection.ContentType = "bar" | ||||||
|   | |||||||
| @@ -49,6 +49,12 @@ logging: | |||||||
|   verbosity: 0 |   verbosity: 0 | ||||||
| metricsBindAddress: 127.0.0.1:10249 | metricsBindAddress: 127.0.0.1:10249 | ||||||
| mode: "" | mode: "" | ||||||
|  | nftables: | ||||||
|  |   localhostNodePorts: true | ||||||
|  |   masqueradeAll: false | ||||||
|  |   masqueradeBit: 14 | ||||||
|  |   minSyncPeriod: 1s | ||||||
|  |   syncPeriod: 30s | ||||||
| nodePortAddresses: null | nodePortAddresses: null | ||||||
| oomScoreAdj: -999 | oomScoreAdj: -999 | ||||||
| portRange: "" | portRange: "" | ||||||
|   | |||||||
| @@ -49,6 +49,12 @@ logging: | |||||||
|   verbosity: 0 |   verbosity: 0 | ||||||
| metricsBindAddress: 127.0.0.1:10249 | metricsBindAddress: 127.0.0.1:10249 | ||||||
| mode: "" | mode: "" | ||||||
|  | nftables: | ||||||
|  |   localhostNodePorts: true | ||||||
|  |   masqueradeAll: false | ||||||
|  |   masqueradeBit: 14 | ||||||
|  |   minSyncPeriod: 1s | ||||||
|  |   syncPeriod: 30s | ||||||
| nodePortAddresses: null | nodePortAddresses: null | ||||||
| oomScoreAdj: -999 | oomScoreAdj: -999 | ||||||
| portRange: "" | portRange: "" | ||||||
|   | |||||||
| @@ -81,6 +81,28 @@ type KubeProxyIPVSConfiguration struct { | |||||||
| 	UDPTimeout metav1.Duration | 	UDPTimeout metav1.Duration | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // KubeProxyNFTablesConfiguration contains nftables-related configuration | ||||||
|  | // details for the Kubernetes proxy server. | ||||||
|  | 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 | ||||||
|  | 	// masqueradeAll tells kube-proxy to SNAT all traffic sent to Service cluster IPs, | ||||||
|  | 	// when using the nftables mode. This may be required with some CNI plugins. | ||||||
|  | 	MasqueradeAll bool | ||||||
|  | 	// localhostNodePorts, if false, tells kube-proxy to disable the legacy behavior | ||||||
|  | 	// of allowing NodePort services to be accessed via localhost. FIXME: remove. | ||||||
|  | 	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 | ||||||
|  | } | ||||||
|  |  | ||||||
| // KubeProxyConntrackConfiguration contains conntrack settings for | // KubeProxyConntrackConfiguration contains conntrack settings for | ||||||
| // the Kubernetes proxy server. | // the Kubernetes proxy server. | ||||||
| type KubeProxyConntrackConfiguration struct { | type KubeProxyConntrackConfiguration struct { | ||||||
| @@ -195,6 +217,8 @@ type KubeProxyConfiguration struct { | |||||||
| 	IPVS KubeProxyIPVSConfiguration | 	IPVS KubeProxyIPVSConfiguration | ||||||
| 	// winkernel contains winkernel-related configuration options. | 	// winkernel contains winkernel-related configuration options. | ||||||
| 	Winkernel KubeProxyWinkernelConfiguration | 	Winkernel KubeProxyWinkernelConfiguration | ||||||
|  | 	// nftables contains nftables-related configuration options. | ||||||
|  | 	NFTables KubeProxyNFTablesConfiguration | ||||||
|  |  | ||||||
| 	// detectLocalMode determines mode to use for detecting local traffic, defaults to LocalModeClusterCIDR | 	// detectLocalMode determines mode to use for detecting local traffic, defaults to LocalModeClusterCIDR | ||||||
| 	DetectLocalMode LocalMode | 	DetectLocalMode LocalMode | ||||||
| @@ -228,8 +252,8 @@ type KubeProxyConfiguration struct { | |||||||
|  |  | ||||||
| // ProxyMode represents modes used by the Kubernetes proxy server. | // ProxyMode represents modes used by the Kubernetes proxy server. | ||||||
| // | // | ||||||
| // Currently, two modes of proxy are available on Linux platforms: 'iptables' and 'ipvs'. | // Currently, three modes of proxy are available on Linux platforms: 'iptables', 'ipvs', | ||||||
| // One mode of proxy is available on Windows platforms: 'kernelspace'. | // and 'nftables'. One mode of proxy is available on Windows platforms: 'kernelspace'. | ||||||
| // | // | ||||||
| // If the proxy mode is unspecified, the best-available proxy mode will be used (currently this | // If the proxy mode is unspecified, the best-available proxy mode will be used (currently this | ||||||
| // is `iptables` on Linux and `kernelspace` on Windows). If the selected proxy mode cannot be | // is `iptables` on Linux and `kernelspace` on Windows). If the selected proxy mode cannot be | ||||||
| @@ -240,6 +264,7 @@ type ProxyMode string | |||||||
| const ( | const ( | ||||||
| 	ProxyModeIPTables    ProxyMode = "iptables" | 	ProxyModeIPTables    ProxyMode = "iptables" | ||||||
| 	ProxyModeIPVS        ProxyMode = "ipvs" | 	ProxyModeIPVS        ProxyMode = "ipvs" | ||||||
|  | 	ProxyModeNFTables    ProxyMode = "nftables" | ||||||
| 	ProxyModeKernelspace ProxyMode = "kernelspace" | 	ProxyModeKernelspace ProxyMode = "kernelspace" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -71,6 +71,15 @@ func SetDefaults_KubeProxyConfiguration(obj *kubeproxyconfigv1alpha1.KubeProxyCo | |||||||
| 	if obj.IPVS.SyncPeriod.Duration == 0 { | 	if obj.IPVS.SyncPeriod.Duration == 0 { | ||||||
| 		obj.IPVS.SyncPeriod = metav1.Duration{Duration: 30 * time.Second} | 		obj.IPVS.SyncPeriod = metav1.Duration{Duration: 30 * time.Second} | ||||||
| 	} | 	} | ||||||
|  | 	if obj.NFTables.SyncPeriod.Duration == 0 { | ||||||
|  | 		obj.NFTables.SyncPeriod = metav1.Duration{Duration: 30 * time.Second} | ||||||
|  | 	} | ||||||
|  | 	if obj.NFTables.MinSyncPeriod.Duration == 0 { | ||||||
|  | 		obj.NFTables.MinSyncPeriod = metav1.Duration{Duration: 1 * time.Second} | ||||||
|  | 	} | ||||||
|  | 	if obj.NFTables.LocalhostNodePorts == nil { | ||||||
|  | 		obj.NFTables.LocalhostNodePorts = ptr.To(true) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if obj.Conntrack.MaxPerCore == nil { | 	if obj.Conntrack.MaxPerCore == nil { | ||||||
| 		obj.Conntrack.MaxPerCore = ptr.To[int32](32 * 1024) | 		obj.Conntrack.MaxPerCore = ptr.To[int32](32 * 1024) | ||||||
| @@ -83,6 +92,10 @@ func SetDefaults_KubeProxyConfiguration(obj *kubeproxyconfigv1alpha1.KubeProxyCo | |||||||
| 		temp := int32(14) | 		temp := int32(14) | ||||||
| 		obj.IPTables.MasqueradeBit = &temp | 		obj.IPTables.MasqueradeBit = &temp | ||||||
| 	} | 	} | ||||||
|  | 	if obj.NFTables.MasqueradeBit == nil { | ||||||
|  | 		temp := int32(14) | ||||||
|  | 		obj.NFTables.MasqueradeBit = &temp | ||||||
|  | 	} | ||||||
| 	if obj.Conntrack.TCPEstablishedTimeout == nil { | 	if obj.Conntrack.TCPEstablishedTimeout == nil { | ||||||
| 		obj.Conntrack.TCPEstablishedTimeout = &metav1.Duration{Duration: 24 * time.Hour} // 1 day (1/5 default) | 		obj.Conntrack.TCPEstablishedTimeout = &metav1.Duration{Duration: 24 * time.Hour} // 1 day (1/5 default) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -62,6 +62,13 @@ func TestDefaultsKubeProxyConfiguration(t *testing.T) { | |||||||
| 				IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{ | 				IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{ | ||||||
| 					SyncPeriod: metav1.Duration{Duration: 30 * time.Second}, | 					SyncPeriod: metav1.Duration{Duration: 30 * time.Second}, | ||||||
| 				}, | 				}, | ||||||
|  | 				NFTables: kubeproxyconfigv1alpha1.KubeProxyNFTablesConfiguration{ | ||||||
|  | 					MasqueradeBit:      ptr.To[int32](14), | ||||||
|  | 					MasqueradeAll:      false, | ||||||
|  | 					LocalhostNodePorts: ptr.To(true), | ||||||
|  | 					SyncPeriod:         metav1.Duration{Duration: 30 * time.Second}, | ||||||
|  | 					MinSyncPeriod:      metav1.Duration{Duration: 1 * time.Second}, | ||||||
|  | 				}, | ||||||
| 				OOMScoreAdj: &oomScore, | 				OOMScoreAdj: &oomScore, | ||||||
| 				Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{ | 				Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{ | ||||||
| 					MaxPerCore:            &ctMaxPerCore, | 					MaxPerCore:            &ctMaxPerCore, | ||||||
| @@ -102,6 +109,13 @@ func TestDefaultsKubeProxyConfiguration(t *testing.T) { | |||||||
| 				IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{ | 				IPVS: kubeproxyconfigv1alpha1.KubeProxyIPVSConfiguration{ | ||||||
| 					SyncPeriod: metav1.Duration{Duration: 30 * time.Second}, | 					SyncPeriod: metav1.Duration{Duration: 30 * time.Second}, | ||||||
| 				}, | 				}, | ||||||
|  | 				NFTables: kubeproxyconfigv1alpha1.KubeProxyNFTablesConfiguration{ | ||||||
|  | 					MasqueradeBit:      ptr.To[int32](14), | ||||||
|  | 					MasqueradeAll:      false, | ||||||
|  | 					LocalhostNodePorts: ptr.To(true), | ||||||
|  | 					SyncPeriod:         metav1.Duration{Duration: 30 * time.Second}, | ||||||
|  | 					MinSyncPeriod:      metav1.Duration{Duration: 1 * time.Second}, | ||||||
|  | 				}, | ||||||
| 				OOMScoreAdj: &oomScore, | 				OOMScoreAdj: &oomScore, | ||||||
| 				Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{ | 				Conntrack: kubeproxyconfigv1alpha1.KubeProxyConntrackConfiguration{ | ||||||
| 					MaxPerCore:            &ctMaxPerCore, | 					MaxPerCore:            &ctMaxPerCore, | ||||||
|   | |||||||
| @@ -89,6 +89,16 @@ func RegisterConversions(s *runtime.Scheme) error { | |||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if err := s.AddGeneratedConversionFunc((*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 { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err := s.AddGeneratedConversionFunc((*config.KubeProxyNFTablesConfiguration)(nil), (*v1alpha1.KubeProxyNFTablesConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { | ||||||
|  | 		return Convert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration(a.(*config.KubeProxyNFTablesConfiguration), b.(*v1alpha1.KubeProxyNFTablesConfiguration), scope) | ||||||
|  | 	}); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	if err := s.AddGeneratedConversionFunc((*v1alpha1.KubeProxyWinkernelConfiguration)(nil), (*config.KubeProxyWinkernelConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { | 	if err := s.AddGeneratedConversionFunc((*v1alpha1.KubeProxyWinkernelConfiguration)(nil), (*config.KubeProxyWinkernelConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { | ||||||
| 		return Convert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(a.(*v1alpha1.KubeProxyWinkernelConfiguration), b.(*config.KubeProxyWinkernelConfiguration), scope) | 		return Convert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(a.(*v1alpha1.KubeProxyWinkernelConfiguration), b.(*config.KubeProxyWinkernelConfiguration), scope) | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| @@ -144,6 +154,9 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_config_KubeProxyConfiguratio | |||||||
| 	if err := Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(&in.IPVS, &out.IPVS, s); err != nil { | 	if err := Convert_v1alpha1_KubeProxyIPVSConfiguration_To_config_KubeProxyIPVSConfiguration(&in.IPVS, &out.IPVS, s); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if err := Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(&in.NFTables, &out.NFTables, s); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	if err := Convert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(&in.Winkernel, &out.Winkernel, s); err != nil { | 	if err := Convert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(&in.Winkernel, &out.Winkernel, s); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -190,6 +203,9 @@ func autoConvert_config_KubeProxyConfiguration_To_v1alpha1_KubeProxyConfiguratio | |||||||
| 	if err := Convert_config_KubeProxyWinkernelConfiguration_To_v1alpha1_KubeProxyWinkernelConfiguration(&in.Winkernel, &out.Winkernel, s); err != nil { | 	if err := Convert_config_KubeProxyWinkernelConfiguration_To_v1alpha1_KubeProxyWinkernelConfiguration(&in.Winkernel, &out.Winkernel, s); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if err := Convert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration(&in.NFTables, &out.NFTables, s); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	out.DetectLocalMode = v1alpha1.LocalMode(in.DetectLocalMode) | 	out.DetectLocalMode = v1alpha1.LocalMode(in.DetectLocalMode) | ||||||
| 	if err := Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil { | 	if err := Convert_config_DetectLocalConfiguration_To_v1alpha1_DetectLocalConfiguration(&in.DetectLocal, &out.DetectLocal, s); err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -304,6 +320,34 @@ func Convert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfigur | |||||||
| 	return autoConvert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfiguration(in, out, s) | 	return autoConvert_config_KubeProxyIPVSConfiguration_To_v1alpha1_KubeProxyIPVSConfiguration(in, out, s) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func autoConvert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in *v1alpha1.KubeProxyNFTablesConfiguration, out *config.KubeProxyNFTablesConfiguration, s conversion.Scope) error { | ||||||
|  | 	out.MasqueradeBit = (*int32)(unsafe.Pointer(in.MasqueradeBit)) | ||||||
|  | 	out.MasqueradeAll = in.MasqueradeAll | ||||||
|  | 	out.LocalhostNodePorts = (*bool)(unsafe.Pointer(in.LocalhostNodePorts)) | ||||||
|  | 	out.SyncPeriod = in.SyncPeriod | ||||||
|  | 	out.MinSyncPeriod = in.MinSyncPeriod | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration is an autogenerated conversion function. | ||||||
|  | func Convert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in *v1alpha1.KubeProxyNFTablesConfiguration, out *config.KubeProxyNFTablesConfiguration, s conversion.Scope) error { | ||||||
|  | 	return autoConvert_v1alpha1_KubeProxyNFTablesConfiguration_To_config_KubeProxyNFTablesConfiguration(in, out, s) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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.MasqueradeAll = in.MasqueradeAll | ||||||
|  | 	out.LocalhostNodePorts = (*bool)(unsafe.Pointer(in.LocalhostNodePorts)) | ||||||
|  | 	out.SyncPeriod = in.SyncPeriod | ||||||
|  | 	out.MinSyncPeriod = in.MinSyncPeriod | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Convert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration is an autogenerated conversion function. | ||||||
|  | func Convert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration(in *config.KubeProxyNFTablesConfiguration, out *v1alpha1.KubeProxyNFTablesConfiguration, s conversion.Scope) error { | ||||||
|  | 	return autoConvert_config_KubeProxyNFTablesConfiguration_To_v1alpha1_KubeProxyNFTablesConfiguration(in, out, s) | ||||||
|  | } | ||||||
|  |  | ||||||
| func autoConvert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(in *v1alpha1.KubeProxyWinkernelConfiguration, out *config.KubeProxyWinkernelConfiguration, s conversion.Scope) error { | func autoConvert_v1alpha1_KubeProxyWinkernelConfiguration_To_config_KubeProxyWinkernelConfiguration(in *v1alpha1.KubeProxyWinkernelConfiguration, out *config.KubeProxyWinkernelConfiguration, s conversion.Scope) error { | ||||||
| 	out.NetworkName = in.NetworkName | 	out.NetworkName = in.NetworkName | ||||||
| 	out.SourceVip = in.SourceVip | 	out.SourceVip = in.SourceVip | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ import ( | |||||||
| 	logsapi "k8s.io/component-base/logs/api/v1" | 	logsapi "k8s.io/component-base/logs/api/v1" | ||||||
| 	"k8s.io/component-base/metrics" | 	"k8s.io/component-base/metrics" | ||||||
| 	apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" | 	apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" | ||||||
|  | 	"k8s.io/kubernetes/pkg/features" | ||||||
| 	kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" | 	kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" | ||||||
| 	netutils "k8s.io/utils/net" | 	netutils "k8s.io/utils/net" | ||||||
| ) | ) | ||||||
| @@ -47,8 +48,11 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	allErrs = append(allErrs, validateKubeProxyIPTablesConfiguration(config.IPTables, newPath.Child("KubeProxyIPTablesConfiguration"))...) | 	allErrs = append(allErrs, validateKubeProxyIPTablesConfiguration(config.IPTables, newPath.Child("KubeProxyIPTablesConfiguration"))...) | ||||||
| 	if config.Mode == kubeproxyconfig.ProxyModeIPVS { | 	switch config.Mode { | ||||||
|  | 	case kubeproxyconfig.ProxyModeIPVS: | ||||||
| 		allErrs = append(allErrs, validateKubeProxyIPVSConfiguration(config.IPVS, newPath.Child("KubeProxyIPVSConfiguration"))...) | 		allErrs = append(allErrs, validateKubeProxyIPVSConfiguration(config.IPVS, newPath.Child("KubeProxyIPVSConfiguration"))...) | ||||||
|  | 	case kubeproxyconfig.ProxyModeNFTables: | ||||||
|  | 		allErrs = append(allErrs, validateKubeProxyNFTablesConfiguration(config.NFTables, newPath.Child("KubeProxyNFTablesConfiguration"))...) | ||||||
| 	} | 	} | ||||||
| 	allErrs = append(allErrs, validateKubeProxyConntrackConfiguration(config.Conntrack, newPath.Child("KubeProxyConntrackConfiguration"))...) | 	allErrs = append(allErrs, validateKubeProxyConntrackConfiguration(config.Conntrack, newPath.Child("KubeProxyConntrackConfiguration"))...) | ||||||
| 	allErrs = append(allErrs, validateProxyMode(config.Mode, newPath.Child("Mode"))...) | 	allErrs = append(allErrs, validateProxyMode(config.Mode, newPath.Child("Mode"))...) | ||||||
| @@ -152,6 +156,28 @@ func validateKubeProxyIPVSConfiguration(config kubeproxyconfig.KubeProxyIPVSConf | |||||||
| 	return allErrs | 	return allErrs | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func validateKubeProxyNFTablesConfiguration(config kubeproxyconfig.KubeProxyNFTablesConfiguration, fldPath *field.Path) field.ErrorList { | ||||||
|  | 	allErrs := field.ErrorList{} | ||||||
|  |  | ||||||
|  | 	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 validateKubeProxyConntrackConfiguration(config kubeproxyconfig.KubeProxyConntrackConfiguration, fldPath *field.Path) field.ErrorList { | func validateKubeProxyConntrackConfiguration(config kubeproxyconfig.KubeProxyConntrackConfiguration, fldPath *field.Path) field.ErrorList { | ||||||
| 	allErrs := field.ErrorList{} | 	allErrs := field.ErrorList{} | ||||||
|  |  | ||||||
| @@ -198,6 +224,10 @@ func validateProxyModeLinux(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) | |||||||
| 		string(kubeproxyconfig.ProxyModeIPVS), | 		string(kubeproxyconfig.ProxyModeIPVS), | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
|  | 	if utilfeature.DefaultFeatureGate.Enabled(features.NFTablesProxyMode) { | ||||||
|  | 		validModes.Insert(string(kubeproxyconfig.ProxyModeNFTables)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if mode == "" || validModes.Has(string(mode)) { | 	if mode == "" || validModes.Has(string(mode)) { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								pkg/proxy/apis/config/zz_generated.deepcopy.go
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										29
									
								
								pkg/proxy/apis/config/zz_generated.deepcopy.go
									
									
									
										generated
									
									
									
								
							| @@ -80,6 +80,7 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) { | |||||||
| 	in.IPTables.DeepCopyInto(&out.IPTables) | 	in.IPTables.DeepCopyInto(&out.IPTables) | ||||||
| 	in.IPVS.DeepCopyInto(&out.IPVS) | 	in.IPVS.DeepCopyInto(&out.IPVS) | ||||||
| 	out.Winkernel = in.Winkernel | 	out.Winkernel = in.Winkernel | ||||||
|  | 	in.NFTables.DeepCopyInto(&out.NFTables) | ||||||
| 	out.DetectLocal = in.DetectLocal | 	out.DetectLocal = in.DetectLocal | ||||||
| 	if in.NodePortAddresses != nil { | 	if in.NodePortAddresses != nil { | ||||||
| 		in, out := &in.NodePortAddresses, &out.NodePortAddresses | 		in, out := &in.NodePortAddresses, &out.NodePortAddresses | ||||||
| @@ -206,6 +207,34 @@ func (in *KubeProxyIPVSConfiguration) DeepCopy() *KubeProxyIPVSConfiguration { | |||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | ||||||
|  | func (in *KubeProxyNFTablesConfiguration) DeepCopyInto(out *KubeProxyNFTablesConfiguration) { | ||||||
|  | 	*out = *in | ||||||
|  | 	if in.MasqueradeBit != nil { | ||||||
|  | 		in, out := &in.MasqueradeBit, &out.MasqueradeBit | ||||||
|  | 		*out = new(int32) | ||||||
|  | 		**out = **in | ||||||
|  | 	} | ||||||
|  | 	if in.LocalhostNodePorts != nil { | ||||||
|  | 		in, out := &in.LocalhostNodePorts, &out.LocalhostNodePorts | ||||||
|  | 		*out = new(bool) | ||||||
|  | 		**out = **in | ||||||
|  | 	} | ||||||
|  | 	out.SyncPeriod = in.SyncPeriod | ||||||
|  | 	out.MinSyncPeriod = in.MinSyncPeriod | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeProxyNFTablesConfiguration. | ||||||
|  | func (in *KubeProxyNFTablesConfiguration) DeepCopy() *KubeProxyNFTablesConfiguration { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(KubeProxyNFTablesConfiguration) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | ||||||
| func (in *KubeProxyWinkernelConfiguration) DeepCopyInto(out *KubeProxyWinkernelConfiguration) { | func (in *KubeProxyWinkernelConfiguration) DeepCopyInto(out *KubeProxyWinkernelConfiguration) { | ||||||
| 	*out = *in | 	*out = *in | ||||||
|   | |||||||
							
								
								
									
										1613
									
								
								pkg/proxy/nftables/proxier.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1613
									
								
								pkg/proxy/nftables/proxier.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										7065
									
								
								pkg/proxy/nftables/proxier_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7065
									
								
								pkg/proxy/nftables/proxier_test.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -77,6 +77,28 @@ type KubeProxyIPVSConfiguration struct { | |||||||
| 	UDPTimeout metav1.Duration `json:"udpTimeout"` | 	UDPTimeout metav1.Duration `json:"udpTimeout"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // KubeProxyNFTablesConfiguration contains nftables-related configuration | ||||||
|  | // details for the Kubernetes proxy server. | ||||||
|  | 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 `json:"masqueradeBit"` | ||||||
|  | 	// masqueradeAll tells kube-proxy to SNAT all traffic sent to Service cluster IPs, | ||||||
|  | 	// when using the nftables mode. This may be required with some CNI plugins. | ||||||
|  | 	MasqueradeAll bool `json:"masqueradeAll"` | ||||||
|  | 	// localhostNodePorts, if false, tells kube-proxy to disable the legacy behavior | ||||||
|  | 	// of allowing NodePort services to be accessed via localhost. FIXME: remove. | ||||||
|  | 	LocalhostNodePorts *bool `json:"localhostNodePorts"` | ||||||
|  | 	// 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 `json:"syncPeriod"` | ||||||
|  | 	// 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 `json:"minSyncPeriod"` | ||||||
|  | } | ||||||
|  |  | ||||||
| // KubeProxyConntrackConfiguration contains conntrack settings for | // KubeProxyConntrackConfiguration contains conntrack settings for | ||||||
| // the Kubernetes proxy server. | // the Kubernetes proxy server. | ||||||
| type KubeProxyConntrackConfiguration struct { | type KubeProxyConntrackConfiguration struct { | ||||||
| @@ -189,6 +211,8 @@ type KubeProxyConfiguration struct { | |||||||
| 	IPTables KubeProxyIPTablesConfiguration `json:"iptables"` | 	IPTables KubeProxyIPTablesConfiguration `json:"iptables"` | ||||||
| 	// ipvs contains ipvs-related configuration options. | 	// ipvs contains ipvs-related configuration options. | ||||||
| 	IPVS KubeProxyIPVSConfiguration `json:"ipvs"` | 	IPVS KubeProxyIPVSConfiguration `json:"ipvs"` | ||||||
|  | 	// nftables contains nftables-related configuration options. | ||||||
|  | 	NFTables KubeProxyNFTablesConfiguration `json:"nftables"` | ||||||
| 	// winkernel contains winkernel-related configuration options. | 	// winkernel contains winkernel-related configuration options. | ||||||
| 	Winkernel KubeProxyWinkernelConfiguration `json:"winkernel"` | 	Winkernel KubeProxyWinkernelConfiguration `json:"winkernel"` | ||||||
|  |  | ||||||
|   | |||||||
| @@ -57,6 +57,7 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) { | |||||||
| 	in.Logging.DeepCopyInto(&out.Logging) | 	in.Logging.DeepCopyInto(&out.Logging) | ||||||
| 	in.IPTables.DeepCopyInto(&out.IPTables) | 	in.IPTables.DeepCopyInto(&out.IPTables) | ||||||
| 	in.IPVS.DeepCopyInto(&out.IPVS) | 	in.IPVS.DeepCopyInto(&out.IPVS) | ||||||
|  | 	in.NFTables.DeepCopyInto(&out.NFTables) | ||||||
| 	out.Winkernel = in.Winkernel | 	out.Winkernel = in.Winkernel | ||||||
| 	out.DetectLocal = in.DetectLocal | 	out.DetectLocal = in.DetectLocal | ||||||
| 	if in.NodePortAddresses != nil { | 	if in.NodePortAddresses != nil { | ||||||
| @@ -184,6 +185,34 @@ func (in *KubeProxyIPVSConfiguration) DeepCopy() *KubeProxyIPVSConfiguration { | |||||||
| 	return out | 	return out | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | ||||||
|  | func (in *KubeProxyNFTablesConfiguration) DeepCopyInto(out *KubeProxyNFTablesConfiguration) { | ||||||
|  | 	*out = *in | ||||||
|  | 	if in.MasqueradeBit != nil { | ||||||
|  | 		in, out := &in.MasqueradeBit, &out.MasqueradeBit | ||||||
|  | 		*out = new(int32) | ||||||
|  | 		**out = **in | ||||||
|  | 	} | ||||||
|  | 	if in.LocalhostNodePorts != nil { | ||||||
|  | 		in, out := &in.LocalhostNodePorts, &out.LocalhostNodePorts | ||||||
|  | 		*out = new(bool) | ||||||
|  | 		**out = **in | ||||||
|  | 	} | ||||||
|  | 	out.SyncPeriod = in.SyncPeriod | ||||||
|  | 	out.MinSyncPeriod = in.MinSyncPeriod | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeProxyNFTablesConfiguration. | ||||||
|  | func (in *KubeProxyNFTablesConfiguration) DeepCopy() *KubeProxyNFTablesConfiguration { | ||||||
|  | 	if in == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	out := new(KubeProxyNFTablesConfiguration) | ||||||
|  | 	in.DeepCopyInto(out) | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. | ||||||
| func (in *KubeProxyWinkernelConfiguration) DeepCopyInto(out *KubeProxyWinkernelConfiguration) { | func (in *KubeProxyWinkernelConfiguration) DeepCopyInto(out *KubeProxyWinkernelConfiguration) { | ||||||
| 	*out = *in | 	*out = *in | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Dan Winship
					Dan Winship