diff --git a/pkg/controllers/proxy/network_services_controller.go b/pkg/controllers/proxy/network_services_controller.go index 0ccfb1d744..2b08237aa8 100644 --- a/pkg/controllers/proxy/network_services_controller.go +++ b/pkg/controllers/proxy/network_services_controller.go @@ -275,28 +275,46 @@ func (nsc *NetworkServicesController) Run(healthChan chan<- *healthcheck.Control if err != nil { return errors.New("Failed to do add masquerad rule in POSTROUTING chain of nat table due to: %s" + err.Error()) } - + // https://www.kernel.org/doc/Documentation/networking/ipvs-sysctl.txt // enable ipvs connection tracking - err = ensureIpvsConntrack() - if err != nil { - return errors.New("Failed to do sysctl net.ipv4.vs.conntrack=1 due to: %s" + err.Error()) + sysctlErr := utils.SetSysctl("net/ipv4/vs/conntrack", 1) + if sysctlErr != nil { + return errors.New(sysctlErr.Error()) } // LVS failover not working with UDP packets https://access.redhat.com/solutions/58653 - err = ensureIpvsExpireNodestConn() - if err != nil { - return errors.New("Failed to do sysctl net.ipv4.vs.expire_nodest_conn=1 due to: %s" + err.Error()) + sysctlErr = utils.SetSysctl("net/ipv4/vs/expire_nodest_conn", 1) + if sysctlErr != nil { + return errors.New(sysctlErr.Error()) } // LVS failover not working with UDP packets https://access.redhat.com/solutions/58653 - err = ensureIpvsQuiescentTemplate() - if err != nil { - return errors.New("Failed to do sysctl net.ipv4.vs.expire_quiescent_template=1 due to: %s" + err.Error()) + sysctlErr = utils.SetSysctl("net/ipv4/vs/expire_quiescent_template", 1) + if sysctlErr != nil { + return errors.New(sysctlErr.Error()) } - err = ensureIpvsConnReuseMode() - if err != nil { - return fmt.Errorf("failed to set net.ipv4.vs.conn_reuse_mode=0: %s", err) + // https://github.com/kubernetes/kubernetes/pull/71114 + sysctlErr = utils.SetSysctl("net/ipv4/vs/conn_reuse_mode", 0) + if sysctlErr != nil { + // Check if the error is fatal, on older kernels this option does not exist and the same behaviour is default + // if option is not found just log it + if sysctlErr.IsFatal() { + return errors.New(sysctlErr.Error()) + } + glog.Info(sysctlErr.Error()) + } + + // https://github.com/kubernetes/kubernetes/pull/70530/files + sysctlErr = utils.SetSysctl("net/ipv4/conf/all/arp_ignore", 1) + if sysctlErr != nil { + return errors.New(sysctlErr.Error()) + } + + // https://github.com/kubernetes/kubernetes/pull/70530/files + sysctlErr = utils.SetSysctl("net/ipv4/conf/all/arp_announce", 2) + if sysctlErr != nil { + return errors.New(sysctlErr.Error()) } // loop forever unitl notified to stop on stopCh @@ -1405,31 +1423,6 @@ func deleteHairpinIptablesRules() error { return nil } -func ensureIpvsConntrack() error { - return ioutil.WriteFile("/proc/sys/net/ipv4/vs/conntrack", []byte(strconv.Itoa(1)), 0640) -} - -func ensureIpvsConnReuseMode() error { - sysctlPath := "/proc/sys/net/ipv4/vs/conn_reuse_mode" - if _, err := os.Stat(sysctlPath); err != nil { - if os.IsNotExist(err) { - glog.Infof("%s not found, skipping setting net.ipv4.vs.conn_reuse_mode=0 (non fatal error, feature introduced into kernel in 4.1)", sysctlPath) - return nil - } - glog.Errorf("skipping setting net.ipv4.vs.conn_reuse_mode=0, error stating: %s : %s", sysctlPath, err.Error()) - return nil - } - return ioutil.WriteFile(sysctlPath, []byte(strconv.Itoa(0)), 0640) -} - -func ensureIpvsExpireNodestConn() error { - return ioutil.WriteFile("/proc/sys/net/ipv4/vs/expire_nodest_conn", []byte(strconv.Itoa(1)), 0640) -} - -func ensureIpvsQuiescentTemplate() error { - return ioutil.WriteFile("/proc/sys/net/ipv4/vs/expire_quiescent_template", []byte(strconv.Itoa(1)), 0640) -} - func deleteMasqueradeIptablesRule() error { iptablesCmdHandler, err := iptables.New() if err != nil { diff --git a/pkg/utils/sysctl.go b/pkg/utils/sysctl.go new file mode 100644 index 0000000000..6d8377132f --- /dev/null +++ b/pkg/utils/sysctl.go @@ -0,0 +1,41 @@ +package utils + +import ( + "fmt" + "io/ioutil" + "os" + "strconv" +) + +type SysctlError struct { + err string + option string + value int + fatal bool +} + +// Error return the error as string +func (e *SysctlError) Error() string { + return fmt.Sprintf("Sysctl %s=%d : %s", e.option, e.value, e.err) +} + +// IsFatal was the error fatal and reason to exit kube-router +func (e *SysctlError) IsFatal() bool { + return e.fatal +} + +// SetSysctl sets a sysctl value +func SetSysctl(path string, value int) *SysctlError { + sysctlPath := fmt.Sprintf("/proc/sys/%s", path) + if _, err := os.Stat(sysctlPath); err != nil { + if os.IsNotExist(err) { + return &SysctlError{"option not found, Does your kernel version support this feature?", path, value, false} + } + return &SysctlError{"stat error: " + err.Error(), path, value, true} + } + err := ioutil.WriteFile(sysctlPath, []byte(strconv.Itoa(value)), 0640) + if err != nil { + return &SysctlError{"could not set due to: " + err.Error(), path, value, true} + } + return nil +}