Made IPVS and iptables modes of kube-proxy fully randomize masquerading if possible

Work around Linux kernel bug that sometimes causes multiple flows to
get mapped to the same IP:PORT and consequently some suffer packet
drops.

Also made the same update in kubelet.

Also added cross-pointers between the two bodies of code, in comments.

Some day we should eliminate the duplicate code.  But today is not
that day.
This commit is contained in:
Mike Spreitzer
2019-08-26 22:47:21 -04:00
parent 7600f91b30
commit d86d1defa1
8 changed files with 123 additions and 8 deletions

View File

@@ -780,12 +780,20 @@ func (proxier *Proxier) syncProxyRules() {
// Install the kubernetes-specific postrouting rules. We use a whole chain for
// this so that it is easier to flush and change, for example if the mark
// value should ever change.
writeLine(proxier.natRules, []string{
// NB: THIS MUST MATCH the corresponding code in the kubelet
masqRule := []string{
"-A", string(kubePostroutingChain),
"-m", "comment", "--comment", `"kubernetes service traffic requiring SNAT"`,
"-m", "mark", "--mark", proxier.masqueradeMark,
"-j", "MASQUERADE",
}...)
}
if proxier.iptables.HasRandomFully() {
masqRule = append(masqRule, "--random-fully")
klog.V(3).Info("Using `--random-fully` in the MASQUERADE rule for iptables")
} else {
klog.V(2).Info("Not using `--random-fully` in the MASQUERADE rule for iptables because the local version of iptables does not support it")
}
writeLine(proxier.natRules, masqRule...)
// Install the kubernetes-specific masquerade mark rule. We use a whole chain for
// this so that it is easier to flush and change, for example if the mark

View File

@@ -438,6 +438,15 @@ func hasSrcType(rules []iptablestest.Rule, srcType string) bool {
return false
}
func hasMasqRandomFully(rules []iptablestest.Rule) bool {
for _, r := range rules {
if r[iptablestest.Masquerade] == "--random-fully" {
return true
}
}
return false
}
func TestHasJump(t *testing.T) {
testCases := map[string]struct {
rules []iptablestest.Rule
@@ -784,6 +793,25 @@ func TestNodePort(t *testing.T) {
}
}
func TestMasqueradeRule(t *testing.T) {
for _, testcase := range []bool{false, true} {
ipt := iptablestest.NewFake().SetHasRandomFully(testcase)
fp := NewFakeProxier(ipt, false)
makeServiceMap(fp)
makeEndpointsMap(fp)
fp.syncProxyRules()
postRoutingRules := ipt.GetRules(string(kubePostroutingChain))
if !hasJump(postRoutingRules, "MASQUERADE", "", 0) {
errorf(fmt.Sprintf("Failed to find -j MASQUERADE in %s chain", kubePostroutingChain), postRoutingRules, t)
}
if hasMasqRandomFully(postRoutingRules) != testcase {
probs := map[bool]string{false: "found", true: "did not find"}
errorf(fmt.Sprintf("%s --random-fully in -j MASQUERADE rule in %s chain when HasRandomFully()==%v", probs[testcase], kubePostroutingChain, testcase), postRoutingRules, t)
}
}
}
func TestExternalIPsReject(t *testing.T) {
ipt := iptablestest.NewFake()
fp := NewFakeProxier(ipt, false)