Change:
The current support of the load distribution method and in kube-proxy ipvs mode only performs hashing of source IP address to select endpoints. As a result, all connections from a single client (i.e. from a particular source IP) are always forwarded to only one endpoint matching with the hash value of this source IP. If the client opens a vast majority of connections to the k8s cluster, it will result in traffic imbalance as only one endpoint located on one node handles the connections while the remaining endpoints/nodes are idle. Here is an example of the problem when using method for kube-proxy Deploy a service with 4 endpoints located on 4 nodes.Open 200 connections from a client to node IP of any node (e.g. telnet 192.168.1.1 ). All connections receive replies from only one single endpoint.The distribution printout also shows that all connections are forwarded to the endpoint (e.g. 1.0.4.2:5001 in this example)Similar issue is seen with method Connections from a client should be evenly distributed to all endpoints like to avoid unbalanced load distribution between cluster nodes and endpoints. This can be easily done by enabling the source port hash flag that IPVS supports for the methods which performs hashing on both source IP and source port when selecting the target endpoint.
/sig network /area kube-proxy /area ipvs
This issue was raised based on the discussion of the issue
triage/accepted /assign
/triage/accepted
/triage accepted (damn it!)

Discussion:
serv.Flags |= utilipvs.FlagPersistent serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds()) } <ins> // Set the source hash flag needed for the distribution method "mh" if proxier.ipvsScheduler == "mh" { serv.Flags |= utilipvs.FlagSourceHash } </ins> // We need to bind ClusterIP to dummy interface, so set `bindAddr` parameter to `true` in syncService() if err := proxier.syncService(svcPortNameString, serv, true, bindedAddresses); err == nil { activeIPVSServices[serv.String()] = true

serv.Flags |= utilipvs.FlagPersistent serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds()) } <ins> // Set the source hash flag needed for the distribution method "mh" if proxier.ipvsScheduler == "mh" { serv.Flags |= utilipvs.FlagSourceHash } </ins> if err := proxier.syncService(svcPortNameString, serv, true, bindedAddresses); err == nil { activeIPVSServices[serv.String()] = true activeBindAddrs[serv.Address.String()] = true

serv.Flags |= utilipvs.FlagPersistent serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds()) } <ins> // Set the source hash flag needed for the distribution method "mh" if proxier.ipvsScheduler == "mh" { serv.Flags |= utilipvs.FlagSourceHash } </ins> // There is no need to bind Node IP to dummy interface, so set parameter `bindAddr` to `false`. if err := proxier.syncService(svcPortNameString, serv, false, bindedAddresses); err == nil { activeIPVSServices[serv.String()] = true

FlagPersistent = 0x1 // FlagHashed specify IPVS service hash flag FlagHashed = 0x2 <ins> // FlagSourceHash enables IPVS service hashing on source port and source IP FlagSourceHash = 0x10 </ins> ) // Equal check the equality of virtual server.

Timeout:   svc.Timeout, } <del> // Test Flags >= 0x2, valid Flags ranges [0x2, 0x3] </del> <ins> // Test FlagHashed (0x2). A valid flag must include FlagHashed </ins> if svc.Flags&FlagHashed == 0 { <del> return nil, fmt.Errorf("Flags of successfully created IPVS service should be >= %d since every service is hashed into the service table", FlagHashed) </del> <ins> return nil, fmt.Errorf("Flags of successfully created IPVS service should enable the flag (%x) since every service is hashed into the service table", FlagHashed) </ins> } // Sub Flags to 0x2 // 011 -> 001, 010 -> 000

}, VirtualServer{}, true, <del> fmt.Sprintf("IPVS Service Flags should be >= %d, got 0x0", FlagHashed), </del> <ins> fmt.Sprintf("IPVS Service Flags should include %x, got 0x0", FlagHashed), </ins> }, { libipvs.Service{

}, VirtualServer{}, true, <del> fmt.Sprintf("IPVS Service Flags should be >= %d, got 0x1", FlagHashed), </del> <ins> fmt.Sprintf("IPVS Service Flags should include %x, got 0x1", FlagHashed), </ins> }, { libipvs.Service{

}, { libipvs.Service{ <ins> Protocol:      0, Port:          0, FWMark:        0, SchedName:     "mh", Flags:         uint32(FlagPersistent + FlagHashed + FlagSourceHash), Timeout:       0, Netmask:       0xffffffff, AddressFamily: unix.AF_INET, Address:       netutils.ParseIPSloppy("1.2.3.4"), PEName:        "", }, VirtualServer{ Address:   netutils.ParseIPSloppy("1.2.3.4"), Protocol:  "", Port:      0, Scheduler: "mh", Flags:     ServiceFlags(FlagPersistent + FlagSourceHash), Timeout:   0, }, false, "", }, { libipvs.Service{ </ins> Protocol:      unix.IPPROTO_SCTP, Port:          80, FWMark:        0,