Change:
If is true, kube-proxy reads the value and uses it to determine whether or not traffic is local to the Node. In certain cases (e.g. when kube-proxy runs before the Node information has been completely updated), it is possible for kube-proxy to read and store a stale value. This will cause kube-proxy to route traffic incorrectly as the local traffic determination is no longer correct. Note: PodCIDR is immutable once set but it is possible to delete and recreate the Node object to get into this state. (yes, this can happen) /sig network kube-proxy should detect this state and reconfigure/restart with the newly updated . Recreate the Node object with a different PodCIDR after kube-proxy has started on the Node. Impacts all current versions that support <detailsObserved for GCE preemptible/spot VMs, but is a generic problem. </details
/cc
We are watching the node object since we've implemented topology hint, so it would be easier to adapt the code to react on these changes
/triage accepted
for iptables for ipvs
/assign
/reopen The fix in partially solved this problem, but there is still a race in the code. So, when kube-proxy starts it calls that calls that if is set to will wait to get the PodCIDR assigned to the Node object However, the value obtained here is not the value used by the , that is started later in the call If something changes between the node informer is initiated and the starting code gets the PodCIDR, it will get unnoticed and kube-proxy will be operation with an outdated value, causing issue
Reopened this issue. <detailsIn response to : /reopen Instructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details

Discussion:
Hostname      string NodeIP        net.IP <ins> podCIDRs []string // only used for LocalModeNodeCIDR </ins> Proxier proxy.Provider }

nodeConfig := config.NewNodeConfig(currentNodeInformerFactory.Core().V1().Nodes(), s.Config.ConfigSyncPeriod.Duration) // https://issues.k8s.io/111321 if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeNodeCIDR { <del> nodeConfig.RegisterEventHandler(&proxy.NodePodCIDRHandler{}) </del> <ins> nodeConfig.RegisterEventHandler(proxy.NewNodePodCIDRHandler(s.podCIDRs)) </ins> } nodeConfig.RegisterEventHandler(s.Proxier)

if err != nil { return nil, err } <ins> s.podCIDRs = nodeInfo.Spec.PodCIDRs </ins> klog.InfoS("NodeInfo", "podCIDR", nodeInfo.Spec.PodCIDR, "podCIDRs", nodeInfo.Spec.PodCIDRs) }

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" <del> netutils "k8s.io/utils/net" "k8s.io/utils/pointer" </del> clientsetfake "k8s.io/client-go/kubernetes/fake" clientgotesting "k8s.io/client-go/testing" proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config" proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables" utiliptables "k8s.io/kubernetes/pkg/util/iptables" utiliptablestest "k8s.io/kubernetes/pkg/util/iptables/testing" <ins> netutils "k8s.io/utils/net" "k8s.io/utils/pointer" </ins> ) func Test_platformApplyDefaults(t *testing.T) {

} } } <ins> func TestProxyServer_createProxier(t *testing.T) { tests := []struct { name         string node         *v1.Node config       *proxyconfigapi.KubeProxyConfiguration wantPodCIDRs []string }{ { name:         "LocalModeNodeCIDR store the node PodCIDRs obtained", node:         makeNodeWithPodCIDRs("10.0.0.0/24"), config:       &proxyconfigapi.KubeProxyConfiguration{DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR}, wantPodCIDRs: []string{"10.0.0.0/24"}, }, { name:         "LocalModeNodeCIDR store the node PodCIDRs obtained dual stack", node:         makeNodeWithPodCIDRs("10.0.0.0/24", "2001:db2:1/64"), config:       &proxyconfigapi.KubeProxyConfiguration{DetectLocalMode: proxyconfigapi.LocalModeNodeCIDR}, wantPodCIDRs: []string{"10.0.0.0/24", "2001:db2:1/64"}, }, { name:   "LocalModeClusterCIDR does not get the node PodCIDRs", node:   makeNodeWithPodCIDRs("10.0.0.0/24", "2001:db2:1/64"), config: &proxyconfigapi.KubeProxyConfiguration{DetectLocalMode: proxyconfigapi.LocalModeClusterCIDR}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { client := clientsetfake.NewSimpleClientset(tt.node) s := &ProxyServer{ Config:   tt.config, Client:   client, Hostname: "nodename", NodeIP:   netutils.ParseIPSloppy("127.0.0.1"), } _, err := s.createProxier(tt.config) // TODO: mock the exec.Interface to not fail probing iptables if (err != nil) && !strings.Contains(err.Error(), "iptables is not supported for primary IP family") { t.Errorf("ProxyServer.createProxier() error = %v", err) return } if !reflect.DeepEqual(s.podCIDRs, tt.wantPodCIDRs) { t.Errorf("Expected PodCIDRs %v got %v", tt.wantPodCIDRs, s.podCIDRs) } }) } } </ins>

podCIDRs []string } <ins> func NewNodePodCIDRHandler(podCIDRs []string) *NodePodCIDRHandler { return &NodePodCIDRHandler{ podCIDRs: podCIDRs, } } </ins> var _ config.NodeHandler = &NodePodCIDRHandler{} // OnNodeAdd is a handler for Node creates.

newNodePodCIDRs: []string{"192.168.1.0/24", "fd00:1:2:3::/64"}, }, { <ins> name:            "already initialized and same node", oldNodePodCIDRs: []string{"10.0.0.0/24", "fd00:3:2:1::/64"}, newNodePodCIDRs: []string{"10.0.0.0/24", "fd00:3:2:1::/64"}, }, { </ins> name:            "already initialized and different node", oldNodePodCIDRs: []string{"192.168.1.0/24", "fd00:1:2:3::/64"}, newNodePodCIDRs: []string{"10.0.0.0/24", "fd00:3:2:1::/64"},