mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Merge pull request #58052 from m1093782566/nodeip-config
Automatic merge from submit-queue (batch tested with PRs 60430, 60115, 58052, 60355, 60116). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Make nodeport ip configurable **What this PR does / why we need it**: By default, kube-proxy accepts everything from NodePort without any filter. It can be a problem for nodes which has both public and private NICs, and people only want to provide a service in private network and avoid exposing any internal service on the public IPs. This PR makes nodeport ip configurable. **Which issue(s) this PR fixes**: Closes: #21070 **Special notes for your reviewer**: Design proposal see: https://github.com/kubernetes/community/pull/1547 Issue in feature repo: https://github.com/kubernetes/features/issues/539 **Release note**: ```release-note Make NodePort IP addresses configurable ```
This commit is contained in:
commit
42378eab40
@ -169,6 +169,8 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
|
|||||||
"NAT timeout for TCP connections in the CLOSE_WAIT state")
|
"NAT timeout for TCP connections in the CLOSE_WAIT state")
|
||||||
fs.BoolVar(&o.config.EnableProfiling, "profiling", o.config.EnableProfiling, "If true enables profiling via web interface on /debug/pprof handler.")
|
fs.BoolVar(&o.config.EnableProfiling, "profiling", o.config.EnableProfiling, "If true enables profiling via web interface on /debug/pprof handler.")
|
||||||
fs.StringVar(&o.config.IPVS.Scheduler, "ipvs-scheduler", o.config.IPVS.Scheduler, "The ipvs scheduler type when proxy mode is ipvs")
|
fs.StringVar(&o.config.IPVS.Scheduler, "ipvs-scheduler", o.config.IPVS.Scheduler, "The ipvs scheduler type when proxy mode is ipvs")
|
||||||
|
fs.StringSliceVar(&o.config.NodePortAddresses, "nodeport-addresses", o.config.NodePortAddresses,
|
||||||
|
"A string slice of values which specify the addresses to use for NodePorts. Values may be valid IP blocks (e.g. 1.2.3.0/24, 1.2.3.4/32). The default empty string slice ([]) means to use all local addresses.")
|
||||||
fs.Var(flag.NewMapStringBool(&o.config.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
|
fs.Var(flag.NewMapStringBool(&o.config.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
|
||||||
"Options are:\n"+strings.Join(utilfeature.DefaultFeatureGate.KnownFeatures(), "\n"))
|
"Options are:\n"+strings.Join(utilfeature.DefaultFeatureGate.KnownFeatures(), "\n"))
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ func newProxyServer(
|
|||||||
nodeIP,
|
nodeIP,
|
||||||
recorder,
|
recorder,
|
||||||
healthzUpdater,
|
healthzUpdater,
|
||||||
|
config.NodePortAddresses,
|
||||||
)
|
)
|
||||||
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)
|
||||||
@ -196,6 +197,7 @@ func newProxyServer(
|
|||||||
recorder,
|
recorder,
|
||||||
healthzServer,
|
healthzServer,
|
||||||
config.IPVS.Scheduler,
|
config.IPVS.Scheduler,
|
||||||
|
config.NodePortAddresses,
|
||||||
)
|
)
|
||||||
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)
|
||||||
@ -226,6 +228,7 @@ func newProxyServer(
|
|||||||
config.IPTables.SyncPeriod.Duration,
|
config.IPTables.SyncPeriod.Duration,
|
||||||
config.IPTables.MinSyncPeriod.Duration,
|
config.IPTables.MinSyncPeriod.Duration,
|
||||||
config.UDPIdleTimeout.Duration,
|
config.UDPIdleTimeout.Duration,
|
||||||
|
config.NodePortAddresses,
|
||||||
)
|
)
|
||||||
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)
|
||||||
|
@ -433,6 +433,9 @@ oomScoreAdj: 17
|
|||||||
portRange: "2-7"
|
portRange: "2-7"
|
||||||
resourceContainer: /foo
|
resourceContainer: /foo
|
||||||
udpIdleTimeout: 123ms
|
udpIdleTimeout: 123ms
|
||||||
|
nodePortAddresses:
|
||||||
|
- "10.20.30.40/16"
|
||||||
|
- "fd00:1::0/64"
|
||||||
`
|
`
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@ -545,6 +548,7 @@ udpIdleTimeout: 123ms
|
|||||||
PortRange: "2-7",
|
PortRange: "2-7",
|
||||||
ResourceContainer: "/foo",
|
ResourceContainer: "/foo",
|
||||||
UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
|
UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
|
||||||
|
NodePortAddresses: []string{"10.20.30.40/16", "fd00:1::0/64"},
|
||||||
}
|
}
|
||||||
|
|
||||||
options := NewOptions()
|
options := NewOptions()
|
||||||
|
@ -92,6 +92,7 @@ func NewHollowProxyOrDie(
|
|||||||
getNodeIP(client, nodeName),
|
getNodeIP(client, nodeName),
|
||||||
recorder,
|
recorder,
|
||||||
nil,
|
nil,
|
||||||
|
[]string{},
|
||||||
)
|
)
|
||||||
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)
|
||||||
|
@ -44,7 +44,9 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
obj.IPTables.MasqueradeBit = utilpointer.Int32Ptr(c.Int31())
|
obj.IPTables.MasqueradeBit = utilpointer.Int32Ptr(c.Int31())
|
||||||
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 = utilpointer.Int32Ptr(c.Int31())
|
obj.OOMScoreAdj = utilpointer.Int32Ptr(c.Int31())
|
||||||
obj.ResourceContainer = c.RandString()
|
obj.ResourceContainer = "foo"
|
||||||
|
obj.ClientConnection.ContentType = "bar"
|
||||||
|
obj.NodePortAddresses = []string{"1.2.3.0/24"}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,14 @@ type KubeProxyConfiguration struct {
|
|||||||
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
||||||
// than 0.
|
// than 0.
|
||||||
ConfigSyncPeriod metav1.Duration
|
ConfigSyncPeriod metav1.Duration
|
||||||
|
// nodePortAddresses is the --nodeport-addresses value for kube-proxy process. Values must be valid
|
||||||
|
// IP blocks. These values are as a parameter to select the interfaces where nodeport works.
|
||||||
|
// In case someone would like to expose a service on localhost for local visit and some other interfaces for
|
||||||
|
// particular purpose, a list of IP blocks would do that.
|
||||||
|
// If set it to "127.0.0.0/8", kube-proxy will only select the loopback interface for NodePort.
|
||||||
|
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
||||||
|
// An empty string slice is meant to select all network interfaces.
|
||||||
|
NodePortAddresses []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||||
|
@ -140,6 +140,14 @@ type KubeProxyConfiguration struct {
|
|||||||
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
// configSyncPeriod is how often configuration from the apiserver is refreshed. Must be greater
|
||||||
// than 0.
|
// than 0.
|
||||||
ConfigSyncPeriod metav1.Duration `json:"configSyncPeriod"`
|
ConfigSyncPeriod metav1.Duration `json:"configSyncPeriod"`
|
||||||
|
// nodePortAddresses is the --nodeport-addresses value for kube-proxy process. Values must be valid
|
||||||
|
// IP blocks. These values are as a parameter to select the interfaces where nodeport works.
|
||||||
|
// In case someone would like to expose a service on localhost for local visit and some other interfaces for
|
||||||
|
// particular purpose, a list of IP blocks would do that.
|
||||||
|
// If set it to "127.0.0.0/8", kube-proxy will only select the loopback interface for NodePort.
|
||||||
|
// If set it to a non-zero IP block, kube-proxy will filter that down to just the IPs that applied to the node.
|
||||||
|
// An empty string slice is meant to select all network interfaces.
|
||||||
|
NodePortAddresses []string `json:"nodePortAddresses"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
// Currently, three modes of proxy are available in Linux platform: 'userspace' (older, going to be EOL), 'iptables'
|
||||||
|
@ -104,6 +104,7 @@ func autoConvert_v1alpha1_KubeProxyConfiguration_To_kubeproxyconfig_KubeProxyCon
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
|
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +139,7 @@ func autoConvert_kubeproxyconfig_KubeProxyConfiguration_To_v1alpha1_KubeProxyCon
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
|
out.NodePortAddresses = *(*[]string)(unsafe.Pointer(&in.NodePortAddresses))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,11 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
|||||||
out.UDPIdleTimeout = in.UDPIdleTimeout
|
out.UDPIdleTimeout = in.UDPIdleTimeout
|
||||||
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
|
if in.NodePortAddresses != nil {
|
||||||
|
in, out := &in.NodePortAddresses, &out.NodePortAddresses
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ func Validate(config *kubeproxyconfig.KubeProxyConfiguration) field.ErrorList {
|
|||||||
allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)"))
|
allErrs = append(allErrs, field.Invalid(newPath.Child("PortRange"), config.PortRange, "must be a valid port range (e.g. 300-2000)"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allErrs = append(allErrs, validateKubeProxyNodePortAddress(config.NodePortAddresses, newPath.Child("NodePortAddresses"))...)
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,3 +240,16 @@ func validateIPVSSchedulerMethod(scheduler kubeproxyconfig.IPVSSchedulerMethod,
|
|||||||
}
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateKubeProxyNodePortAddress(nodePortAddresses []string, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
|
for i := range nodePortAddresses {
|
||||||
|
if _, _, err := net.ParseCIDR(nodePortAddresses[i]); err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath, nodePortAddresses, "must be a valid IP block"))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@ -679,3 +679,73 @@ func TestValidateIPVSSchedulerMethod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateKubeProxyNodePortAddress(t *testing.T) {
|
||||||
|
newPath := field.NewPath("KubeProxyConfiguration")
|
||||||
|
|
||||||
|
successCases := []struct {
|
||||||
|
addresses []string
|
||||||
|
}{
|
||||||
|
{[]string{}},
|
||||||
|
{[]string{"127.0.0.0/8"}},
|
||||||
|
{[]string{"0.0.0.0/0"}},
|
||||||
|
{[]string{"::/0"}},
|
||||||
|
{[]string{"127.0.0.1/32", "1.2.3.0/24"}},
|
||||||
|
{[]string{"127.0.0.0/8"}},
|
||||||
|
{[]string{"127.0.0.1/32"}},
|
||||||
|
{[]string{"::1/128"}},
|
||||||
|
{[]string{"1.2.3.4/32"}},
|
||||||
|
{[]string{"10.20.30.0/24"}},
|
||||||
|
{[]string{"10.20.0.0/16", "100.200.0.0/16"}},
|
||||||
|
{[]string{"10.0.0.0/8"}},
|
||||||
|
{[]string{"2001:db8::/32"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, successCase := range successCases {
|
||||||
|
if errs := validateKubeProxyNodePortAddress(successCase.addresses, newPath.Child("NodePortAddresses")); len(errs) != 0 {
|
||||||
|
t.Errorf("expected success: %v", errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCases := []struct {
|
||||||
|
addresses []string
|
||||||
|
msg string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
addresses: []string{"foo"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{"1.2.3"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{""},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{"10.20.30.40"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{"::1"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{"2001:db8:1"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
addresses: []string{"2001:db8:xyz/64"},
|
||||||
|
msg: "must be a valid IP block",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, errorCase := range errorCases {
|
||||||
|
if errs := validateKubeProxyNodePortAddress(errorCase.addresses, newPath.Child("NodePortAddresses")); len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure for %s", errorCase.msg)
|
||||||
|
} else if !strings.Contains(errs[0].Error(), errorCase.msg) {
|
||||||
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -89,6 +89,11 @@ func (in *KubeProxyConfiguration) DeepCopyInto(out *KubeProxyConfiguration) {
|
|||||||
out.UDPIdleTimeout = in.UDPIdleTimeout
|
out.UDPIdleTimeout = in.UDPIdleTimeout
|
||||||
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
in.Conntrack.DeepCopyInto(&out.Conntrack)
|
||||||
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
out.ConfigSyncPeriod = in.ConfigSyncPeriod
|
||||||
|
if in.NodePortAddresses != nil {
|
||||||
|
in, out := &in.NodePortAddresses, &out.NodePortAddresses
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ go_test(
|
|||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/proxy:go_default_library",
|
"//pkg/proxy:go_default_library",
|
||||||
"//pkg/proxy/util:go_default_library",
|
"//pkg/proxy/util:go_default_library",
|
||||||
|
"//pkg/proxy/util/testing:go_default_library",
|
||||||
"//pkg/util/async:go_default_library",
|
"//pkg/util/async:go_default_library",
|
||||||
"//pkg/util/conntrack:go_default_library",
|
"//pkg/util/conntrack:go_default_library",
|
||||||
"//pkg/util/iptables:go_default_library",
|
"//pkg/util/iptables:go_default_library",
|
||||||
|
@ -341,6 +341,12 @@ type Proxier struct {
|
|||||||
filterRules *bytes.Buffer
|
filterRules *bytes.Buffer
|
||||||
natChains *bytes.Buffer
|
natChains *bytes.Buffer
|
||||||
natRules *bytes.Buffer
|
natRules *bytes.Buffer
|
||||||
|
|
||||||
|
// Values are as a parameter to select the interfaces where nodeport works.
|
||||||
|
nodePortAddresses []string
|
||||||
|
// networkInterfacer defines an interface for several net library functions.
|
||||||
|
// Inject for test purpose.
|
||||||
|
networkInterfacer utilproxy.NetworkInterfacer
|
||||||
}
|
}
|
||||||
|
|
||||||
// listenPortOpener opens ports by calling bind() and listen().
|
// listenPortOpener opens ports by calling bind() and listen().
|
||||||
@ -371,6 +377,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
nodeIP net.IP,
|
nodeIP net.IP,
|
||||||
recorder record.EventRecorder,
|
recorder record.EventRecorder,
|
||||||
healthzServer healthcheck.HealthzUpdater,
|
healthzServer healthcheck.HealthzUpdater,
|
||||||
|
nodePortAddresses []string,
|
||||||
) (*Proxier, error) {
|
) (*Proxier, error) {
|
||||||
// Set the route_localnet sysctl we need for
|
// Set the route_localnet sysctl we need for
|
||||||
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
||||||
@ -422,6 +429,8 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
filterRules: bytes.NewBuffer(nil),
|
filterRules: bytes.NewBuffer(nil),
|
||||||
natChains: bytes.NewBuffer(nil),
|
natChains: bytes.NewBuffer(nil),
|
||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
|
nodePortAddresses: nodePortAddresses,
|
||||||
|
networkInterfacer: utilproxy.RealNetwork{},
|
||||||
}
|
}
|
||||||
burstSyncs := 2
|
burstSyncs := 2
|
||||||
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
||||||
@ -1289,11 +1298,37 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
|
|
||||||
// Finally, tail-call to the nodeports chain. This needs to be after all
|
// Finally, tail-call to the nodeports chain. This needs to be after all
|
||||||
// other service portal rules.
|
// other service portal rules.
|
||||||
writeLine(proxier.natRules,
|
addresses, err := utilproxy.GetNodeAddresses(proxier.nodePortAddresses, proxier.networkInterfacer)
|
||||||
"-A", string(kubeServicesChain),
|
if err != nil {
|
||||||
"-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`,
|
glog.Errorf("Failed to get node ip address matching nodeport cidr")
|
||||||
"-m", "addrtype", "--dst-type", "LOCAL",
|
} else {
|
||||||
"-j", string(kubeNodePortsChain))
|
isIPv6 := proxier.iptables.IsIpv6()
|
||||||
|
for address := range addresses {
|
||||||
|
// TODO(thockin, m1093782566): If/when we have dual-stack support we will want to distinguish v4 from v6 zero-CIDRs.
|
||||||
|
if utilproxy.IsZeroCIDR(address) {
|
||||||
|
args = append(args[:0],
|
||||||
|
"-A", string(kubeServicesChain),
|
||||||
|
"-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`,
|
||||||
|
"-m", "addrtype", "--dst-type", "LOCAL",
|
||||||
|
"-j", string(kubeNodePortsChain))
|
||||||
|
writeLine(proxier.natRules, args...)
|
||||||
|
// Nothing else matters after the zero CIDR.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Ignore IP addresses with incorrect version
|
||||||
|
if isIPv6 && !conntrack.IsIPv6String(address) || !isIPv6 && conntrack.IsIPv6String(address) {
|
||||||
|
glog.Errorf("IP address %s has incorrect IP version", address)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// create nodeport rules for each IP one by one
|
||||||
|
args = append(args[:0],
|
||||||
|
"-A", string(kubeServicesChain),
|
||||||
|
"-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`,
|
||||||
|
"-d", address,
|
||||||
|
"-j", string(kubeNodePortsChain))
|
||||||
|
writeLine(proxier.natRules, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the masqueradeMark has been added then we want to forward that same
|
// If the masqueradeMark has been added then we want to forward that same
|
||||||
// traffic, this allows NodePort traffic to be forwarded even if the default
|
// traffic, this allows NodePort traffic to be forwarded even if the default
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/proxy"
|
"k8s.io/kubernetes/pkg/proxy"
|
||||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
|
utilproxytest "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||||
"k8s.io/kubernetes/pkg/util/async"
|
"k8s.io/kubernetes/pkg/util/async"
|
||||||
"k8s.io/kubernetes/pkg/util/conntrack"
|
"k8s.io/kubernetes/pkg/util/conntrack"
|
||||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||||
@ -405,6 +406,8 @@ func NewFakeProxier(ipt utiliptables.Interface) *Proxier {
|
|||||||
filterRules: bytes.NewBuffer(nil),
|
filterRules: bytes.NewBuffer(nil),
|
||||||
natChains: bytes.NewBuffer(nil),
|
natChains: bytes.NewBuffer(nil),
|
||||||
natRules: bytes.NewBuffer(nil),
|
natRules: bytes.NewBuffer(nil),
|
||||||
|
nodePortAddresses: make([]string, 0),
|
||||||
|
networkInterfacer: utilproxytest.NewFakeNetwork(),
|
||||||
}
|
}
|
||||||
p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
|
p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1)
|
||||||
return p
|
return p
|
||||||
@ -769,6 +772,14 @@ func TestNodePort(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
itf := net.Interface{Index: 0, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0}
|
||||||
|
addrs := []net.Addr{utilproxytest.AddrStruct{Val: "127.0.0.1/16"}}
|
||||||
|
itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
|
||||||
|
addrs1 := []net.Addr{utilproxytest.AddrStruct{Val: "::1/128"}}
|
||||||
|
fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
|
||||||
|
fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
|
||||||
|
fp.nodePortAddresses = []string{}
|
||||||
|
|
||||||
fp.syncProxyRules()
|
fp.syncProxyRules()
|
||||||
|
|
||||||
proto := strings.ToLower(string(api.ProtocolTCP))
|
proto := strings.ToLower(string(api.ProtocolTCP))
|
||||||
@ -1001,6 +1012,11 @@ func onlyLocalNodePorts(t *testing.T, fp *Proxier, ipt *iptablestest.FakeIPTable
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
|
||||||
|
addrs := []net.Addr{utilproxytest.AddrStruct{Val: "10.20.30.51/24"}}
|
||||||
|
fp.networkInterfacer.(*utilproxytest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
|
||||||
|
fp.nodePortAddresses = []string{"10.20.30.0/24"}
|
||||||
|
|
||||||
fp.syncProxyRules()
|
fp.syncProxyRules()
|
||||||
|
|
||||||
proto := strings.ToLower(string(api.ProtocolTCP))
|
proto := strings.ToLower(string(api.ProtocolTCP))
|
||||||
@ -1013,11 +1029,15 @@ func onlyLocalNodePorts(t *testing.T, fp *Proxier, ipt *iptablestest.FakeIPTable
|
|||||||
if !hasJump(kubeNodePortRules, lbChain, "", svcNodePort) {
|
if !hasJump(kubeNodePortRules, lbChain, "", svcNodePort) {
|
||||||
errorf(fmt.Sprintf("Failed to find jump to lb chain %v", lbChain), kubeNodePortRules, t)
|
errorf(fmt.Sprintf("Failed to find jump to lb chain %v", lbChain), kubeNodePortRules, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasJump(kubeNodePortRules, string(KubeMarkMasqChain), "", svcNodePort) {
|
if !hasJump(kubeNodePortRules, string(KubeMarkMasqChain), "", svcNodePort) {
|
||||||
errorf(fmt.Sprintf("Failed to find jump to %s chain for destination IP %d", KubeMarkMasqChain, svcNodePort), kubeNodePortRules, t)
|
errorf(fmt.Sprintf("Failed to find jump to %s chain for destination IP %d", KubeMarkMasqChain, svcNodePort), kubeNodePortRules, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kubeServiceRules := ipt.GetRules(string(kubeServicesChain))
|
||||||
|
if !hasJump(kubeServiceRules, string(kubeNodePortsChain), "10.20.30.51", 0) {
|
||||||
|
errorf(fmt.Sprintf("Failed to find jump to KUBE-NODEPORTS chain %v", string(kubeNodePortsChain)), kubeServiceRules, t)
|
||||||
|
}
|
||||||
|
|
||||||
svcChain := string(servicePortChainName(svcPortName.String(), proto))
|
svcChain := string(servicePortChainName(svcPortName.String(), proto))
|
||||||
lbRules := ipt.GetRules(lbChain)
|
lbRules := ipt.GetRules(lbChain)
|
||||||
if hasJump(lbRules, nonLocalEpChain, "", 0) {
|
if hasJump(lbRules, nonLocalEpChain, "", 0) {
|
||||||
|
@ -18,6 +18,7 @@ go_test(
|
|||||||
"//pkg/proxy:go_default_library",
|
"//pkg/proxy:go_default_library",
|
||||||
"//pkg/proxy/ipvs/testing:go_default_library",
|
"//pkg/proxy/ipvs/testing:go_default_library",
|
||||||
"//pkg/proxy/util:go_default_library",
|
"//pkg/proxy/util:go_default_library",
|
||||||
|
"//pkg/proxy/util/testing:go_default_library",
|
||||||
"//pkg/util/ipset:go_default_library",
|
"//pkg/util/ipset:go_default_library",
|
||||||
"//pkg/util/ipset/testing:go_default_library",
|
"//pkg/util/ipset/testing:go_default_library",
|
||||||
"//pkg/util/iptables:go_default_library",
|
"//pkg/util/iptables:go_default_library",
|
||||||
|
@ -170,6 +170,11 @@ type Proxier struct {
|
|||||||
// lbWhiteListIPSet is the hash:ip,port,net type ipset where stores all service load balancer ingress IP:Port,sourceCIDR pair, any packets
|
// lbWhiteListIPSet is the hash:ip,port,net type ipset where stores all service load balancer ingress IP:Port,sourceCIDR pair, any packets
|
||||||
// from the source CIDR visit ingress IP:Port can pass through.
|
// from the source CIDR visit ingress IP:Port can pass through.
|
||||||
lbWhiteListCIDRSet *IPSet
|
lbWhiteListCIDRSet *IPSet
|
||||||
|
// Values are as a parameter to select the interfaces where nodeport works.
|
||||||
|
nodePortAddresses []string
|
||||||
|
// networkInterfacer defines an interface for several net library functions.
|
||||||
|
// Inject for test purpose.
|
||||||
|
networkInterfacer utilproxy.NetworkInterfacer
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPGetter helps get node network interface IP
|
// IPGetter helps get node network interface IP
|
||||||
@ -253,6 +258,7 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
recorder record.EventRecorder,
|
recorder record.EventRecorder,
|
||||||
healthzServer healthcheck.HealthzUpdater,
|
healthzServer healthcheck.HealthzUpdater,
|
||||||
scheduler string,
|
scheduler string,
|
||||||
|
nodePortAddresses []string,
|
||||||
) (*Proxier, error) {
|
) (*Proxier, error) {
|
||||||
// Set the route_localnet sysctl we need for
|
// Set the route_localnet sysctl we need for
|
||||||
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
|
||||||
@ -336,6 +342,8 @@ func NewProxier(ipt utiliptables.Interface,
|
|||||||
lbWhiteListCIDRSet: NewIPSet(ipset, KubeLoadBalancerSourceCIDRSet, utilipset.HashIPPortNet, isIPv6),
|
lbWhiteListCIDRSet: NewIPSet(ipset, KubeLoadBalancerSourceCIDRSet, utilipset.HashIPPortNet, isIPv6),
|
||||||
nodePortSetTCP: NewIPSet(ipset, KubeNodePortSetTCP, utilipset.BitmapPort, false),
|
nodePortSetTCP: NewIPSet(ipset, KubeNodePortSetTCP, utilipset.BitmapPort, false),
|
||||||
nodePortSetUDP: NewIPSet(ipset, KubeNodePortSetUDP, utilipset.BitmapPort, false),
|
nodePortSetUDP: NewIPSet(ipset, KubeNodePortSetUDP, utilipset.BitmapPort, false),
|
||||||
|
nodePortAddresses: nodePortAddresses,
|
||||||
|
networkInterfacer: utilproxy.RealNetwork{},
|
||||||
}
|
}
|
||||||
burstSyncs := 2
|
burstSyncs := 2
|
||||||
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
|
||||||
@ -1134,6 +1142,7 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
}
|
}
|
||||||
var nodePortSet *IPSet
|
var nodePortSet *IPSet
|
||||||
switch protocol {
|
switch protocol {
|
||||||
|
|
||||||
case "tcp":
|
case "tcp":
|
||||||
nodePortSet = proxier.nodePortSetTCP
|
nodePortSet = proxier.nodePortSetTCP
|
||||||
case "udp":
|
case "udp":
|
||||||
@ -1152,31 +1161,43 @@ func (proxier *Proxier) syncProxyRules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build ipvs kernel routes for each node ip address
|
// Build ipvs kernel routes for each node ip address
|
||||||
nodeIPs, err := proxier.ipGetter.NodeIPs()
|
nodeIPs := make([]net.IP, 0)
|
||||||
|
addresses, err := utilproxy.GetNodeAddresses(proxier.nodePortAddresses, proxier.networkInterfacer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to get node IP, err: %v", err)
|
glog.Errorf("Failed to get node ip address matching nodeport cidr")
|
||||||
} else {
|
continue
|
||||||
for _, nodeIP := range nodeIPs {
|
}
|
||||||
// ipvs call
|
for address := range addresses {
|
||||||
serv := &utilipvs.VirtualServer{
|
if !utilproxy.IsZeroCIDR(address) {
|
||||||
Address: nodeIP,
|
nodeIPs = append(nodeIPs, net.ParseIP(address))
|
||||||
Port: uint16(svcInfo.nodePort),
|
continue
|
||||||
Protocol: string(svcInfo.protocol),
|
}
|
||||||
Scheduler: proxier.ipvsScheduler,
|
// zero cidr
|
||||||
}
|
nodeIPs, err = proxier.ipGetter.NodeIPs()
|
||||||
if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP {
|
if err != nil {
|
||||||
serv.Flags |= utilipvs.FlagPersistent
|
glog.Errorf("Failed to list all node IPs from host, err: %v", err)
|
||||||
serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds)
|
}
|
||||||
}
|
}
|
||||||
// There is no need to bind Node IP to dummy interface, so set parameter `bindAddr` to `false`.
|
for _, nodeIP := range nodeIPs {
|
||||||
if err := proxier.syncService(svcNameString, serv, false); err == nil {
|
// ipvs call
|
||||||
activeIPVSServices[serv.String()] = true
|
serv := &utilipvs.VirtualServer{
|
||||||
if err := proxier.syncEndpoint(svcName, svcInfo.onlyNodeLocalEndpoints, serv); err != nil {
|
Address: nodeIP,
|
||||||
glog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err)
|
Port: uint16(svcInfo.nodePort),
|
||||||
}
|
Protocol: string(svcInfo.protocol),
|
||||||
} else {
|
Scheduler: proxier.ipvsScheduler,
|
||||||
glog.Errorf("Failed to sync service: %v, err: %v", serv, err)
|
}
|
||||||
|
if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP {
|
||||||
|
serv.Flags |= utilipvs.FlagPersistent
|
||||||
|
serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds)
|
||||||
|
}
|
||||||
|
// There is no need to bind Node IP to dummy interface, so set parameter `bindAddr` to `false`.
|
||||||
|
if err := proxier.syncService(svcNameString, serv, false); err == nil {
|
||||||
|
activeIPVSServices[serv.String()] = true
|
||||||
|
if err := proxier.syncEndpoint(svcName, svcInfo.onlyNodeLocalEndpoints, serv); err != nil {
|
||||||
|
glog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
glog.Errorf("Failed to sync service: %v, err: %v", serv, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
||||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
|
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||||
utilipset "k8s.io/kubernetes/pkg/util/ipset"
|
utilipset "k8s.io/kubernetes/pkg/util/ipset"
|
||||||
ipsettest "k8s.io/kubernetes/pkg/util/ipset/testing"
|
ipsettest "k8s.io/kubernetes/pkg/util/ipset/testing"
|
||||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||||
@ -146,6 +147,8 @@ func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset u
|
|||||||
lbWhiteListCIDRSet: NewIPSet(ipset, KubeLoadBalancerSourceCIDRSet, utilipset.HashIPPortNet, false),
|
lbWhiteListCIDRSet: NewIPSet(ipset, KubeLoadBalancerSourceCIDRSet, utilipset.HashIPPortNet, false),
|
||||||
nodePortSetTCP: NewIPSet(ipset, KubeNodePortSetTCP, utilipset.BitmapPort, false),
|
nodePortSetTCP: NewIPSet(ipset, KubeNodePortSetTCP, utilipset.BitmapPort, false),
|
||||||
nodePortSetUDP: NewIPSet(ipset, KubeNodePortSetUDP, utilipset.BitmapPort, false),
|
nodePortSetUDP: NewIPSet(ipset, KubeNodePortSetUDP, utilipset.BitmapPort, false),
|
||||||
|
nodePortAddresses: make([]string, 0),
|
||||||
|
networkInterfacer: proxyutiltest.NewFakeNetwork(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +389,8 @@ func TestNodePort(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fp.nodePortAddresses = []string{"0.0.0.0/0"}
|
||||||
|
|
||||||
fp.syncProxyRules()
|
fp.syncProxyRules()
|
||||||
|
|
||||||
// Check ipvs service and destinations
|
// Check ipvs service and destinations
|
||||||
@ -445,6 +450,8 @@ func TestNodePortNoEndpoint(t *testing.T) {
|
|||||||
)
|
)
|
||||||
makeEndpointsMap(fp)
|
makeEndpointsMap(fp)
|
||||||
|
|
||||||
|
fp.nodePortAddresses = []string{"0.0.0.0/0"}
|
||||||
|
|
||||||
fp.syncProxyRules()
|
fp.syncProxyRules()
|
||||||
|
|
||||||
// Check ipvs service and destinations
|
// Check ipvs service and destinations
|
||||||
@ -847,15 +854,23 @@ func TestOnlyLocalNodePorts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
itf := net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0}
|
||||||
|
addrs := []net.Addr{proxyutiltest.AddrStruct{Val: "100.101.102.103/24"}}
|
||||||
|
itf1 := net.Interface{Index: 1, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
|
||||||
|
addrs1 := []net.Addr{proxyutiltest.AddrStruct{Val: "2001:db8::0/64"}}
|
||||||
|
fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf, addrs)
|
||||||
|
fp.networkInterfacer.(*proxyutiltest.FakeNetwork).AddInterfaceAddr(&itf1, addrs1)
|
||||||
|
fp.nodePortAddresses = []string{"100.101.102.0/24", "2001:db8::0/64"}
|
||||||
|
|
||||||
fp.syncProxyRules()
|
fp.syncProxyRules()
|
||||||
|
|
||||||
// Expect 2 services and 1 destination
|
// Expect 3 services and 1 destination
|
||||||
services, err := ipvs.GetVirtualServers()
|
services, err := ipvs.GetVirtualServers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to get ipvs services, err: %v", err)
|
t.Errorf("Failed to get ipvs services, err: %v", err)
|
||||||
}
|
}
|
||||||
if len(services) != 2 {
|
if len(services) != 3 {
|
||||||
t.Errorf("Expect 2 ipvs services, got %d", len(services))
|
t.Errorf("Expect 3 ipvs services, got %d", len(services))
|
||||||
}
|
}
|
||||||
found := false
|
found := false
|
||||||
for _, svc := range services {
|
for _, svc := range services {
|
||||||
|
@ -155,18 +155,15 @@ func IsProxyLocked(err error) bool {
|
|||||||
// if iptables fails to update or acquire the initial lock. Once a proxier is
|
// if iptables fails to update or acquire the initial lock. Once a proxier is
|
||||||
// created, it will keep iptables up to date in the background and will not
|
// created, it will keep iptables up to date in the background and will not
|
||||||
// terminate if a particular iptables call fails.
|
// terminate if a particular iptables call fails.
|
||||||
func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration) (*Proxier, error) {
|
func NewProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, nodePortAddresses []string) (*Proxier, error) {
|
||||||
return NewCustomProxier(loadBalancer, listenIP, iptables, exec, pr, syncPeriod, minSyncPeriod, udpIdleTimeout, newProxySocket)
|
return NewCustomProxier(loadBalancer, listenIP, iptables, exec, pr, syncPeriod, minSyncPeriod, udpIdleTimeout, nodePortAddresses, newProxySocket)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCustomProxier functions similarly to NewProxier, returning a new Proxier
|
// NewCustomProxier functions similarly to NewProxier, returning a new Proxier
|
||||||
// for the given LoadBalancer and address. The new proxier is constructed using
|
// for the given LoadBalancer and address. The new proxier is constructed using
|
||||||
// the ProxySocket constructor provided, however, instead of constructing the
|
// the ProxySocket constructor provided, however, instead of constructing the
|
||||||
// default ProxySockets.
|
// default ProxySockets.
|
||||||
func NewCustomProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, makeProxySocket ProxySocketFunc) (*Proxier, error) {
|
func NewCustomProxier(loadBalancer LoadBalancer, listenIP net.IP, iptables iptables.Interface, exec utilexec.Interface, pr utilnet.PortRange, syncPeriod, minSyncPeriod, udpIdleTimeout time.Duration, nodePortAddresses []string, makeProxySocket ProxySocketFunc) (*Proxier, error) {
|
||||||
if listenIP == nil {
|
|
||||||
return nil, fmt.Errorf("invalid listen ip for kube-proxy")
|
|
||||||
}
|
|
||||||
if listenIP.Equal(localhostIPv4) || listenIP.Equal(localhostIPv6) {
|
if listenIP.Equal(localhostIPv4) || listenIP.Equal(localhostIPv6) {
|
||||||
return nil, ErrProxyOnLocalhost
|
return nil, ErrProxyOnLocalhost
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"endpoints.go",
|
"endpoints.go",
|
||||||
|
"network.go",
|
||||||
"port.go",
|
"port.go",
|
||||||
"utils.go",
|
"utils.go",
|
||||||
],
|
],
|
||||||
@ -12,8 +13,10 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/apis/core/helper:go_default_library",
|
"//pkg/apis/core/helper:go_default_library",
|
||||||
|
"//pkg/util/conntrack:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,8 +30,10 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
|
"//pkg/proxy/util/testing:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,7 +46,10 @@ filegroup(
|
|||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [":package-srcs"],
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//pkg/proxy/util/testing:all-srcs",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
45
pkg/proxy/util/network.go
Normal file
45
pkg/proxy/util/network.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetworkInterfacer defines an interface for several net library functions. Production
|
||||||
|
// code will forward to net library functions, and unit tests will override the methods
|
||||||
|
// for testing purposes.
|
||||||
|
type NetworkInterfacer interface {
|
||||||
|
Addrs(intf *net.Interface) ([]net.Addr, error)
|
||||||
|
Interfaces() ([]net.Interface, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RealNetwork implements the NetworkInterfacer interface for production code, just
|
||||||
|
// wrapping the underlying net library function calls.
|
||||||
|
type RealNetwork struct{}
|
||||||
|
|
||||||
|
// Addrs wraps net.Interface.Addrs(), it's a part of NetworkInterfacer interface.
|
||||||
|
func (_ RealNetwork) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||||
|
return intf.Addrs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interfaces wraps net.Interfaces(), it's a part of NetworkInterfacer interface.
|
||||||
|
func (_ RealNetwork) Interfaces() ([]net.Interface, error) {
|
||||||
|
return net.Interfaces()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ NetworkInterfacer = &RealNetwork{}
|
22
pkg/proxy/util/testing/BUILD
Normal file
22
pkg/proxy/util/testing/BUILD
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["fake.go"],
|
||||||
|
importpath = "k8s.io/kubernetes/pkg/proxy/util/testing",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
65
pkg/proxy/util/testing/fake.go
Normal file
65
pkg/proxy/util/testing/fake.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
// FakeNetwork implements the NetworkInterfacer interface for test purpose.
|
||||||
|
type FakeNetwork struct {
|
||||||
|
NetworkInterfaces []net.Interface
|
||||||
|
// The key of map Addrs is the network interface name
|
||||||
|
Address map[string][]net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFakeNetwork initializes a FakeNetwork.
|
||||||
|
func NewFakeNetwork() *FakeNetwork {
|
||||||
|
return &FakeNetwork{
|
||||||
|
NetworkInterfaces: make([]net.Interface, 0),
|
||||||
|
Address: make(map[string][]net.Addr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddInterfaceAddr create an interface and its associated addresses for FakeNetwork implementation.
|
||||||
|
func (f *FakeNetwork) AddInterfaceAddr(intf *net.Interface, addrs []net.Addr) {
|
||||||
|
f.NetworkInterfaces = append(f.NetworkInterfaces, *intf)
|
||||||
|
f.Address[intf.Name] = addrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addrs is part of NetworkInterfacer interface.
|
||||||
|
func (f *FakeNetwork) Addrs(intf *net.Interface) ([]net.Addr, error) {
|
||||||
|
return f.Address[intf.Name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interfaces is part of NetworkInterfacer interface.
|
||||||
|
func (f *FakeNetwork) Interfaces() ([]net.Interface, error) {
|
||||||
|
return f.NetworkInterfaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddrStruct implements the net.Addr for test purpose.
|
||||||
|
type AddrStruct struct{ Val string }
|
||||||
|
|
||||||
|
// Network is part of net.Addr interface.
|
||||||
|
func (a AddrStruct) Network() string {
|
||||||
|
return a.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is part of net.Addr interface.
|
||||||
|
func (a AddrStruct) String() string {
|
||||||
|
return a.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ net.Addr = &AddrStruct{}
|
@ -17,15 +17,30 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
|
"k8s.io/kubernetes/pkg/util/conntrack"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IPv4ZeroCIDR = "0.0.0.0/0"
|
||||||
|
IPv6ZeroCIDR = "::/0"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsZeroCIDR(cidr string) bool {
|
||||||
|
if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func IsLocalIP(ip string) (bool, error) {
|
func IsLocalIP(ip string) (bool, error) {
|
||||||
addrs, err := net.InterfaceAddrs()
|
addrs, err := net.InterfaceAddrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -56,3 +71,61 @@ func ShouldSkipService(svcName types.NamespacedName, service *api.Service) bool
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodeAddresses return all matched node IP addresses based on given cidr slice.
|
||||||
|
// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
|
||||||
|
// NetworkInterfacer is injected for test purpose.
|
||||||
|
// We expect the cidrs passed in is already validated.
|
||||||
|
// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
|
||||||
|
// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
|
||||||
|
// only return `0.0.0.0/0`.
|
||||||
|
// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
|
||||||
|
func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
|
||||||
|
uniqueAddressList := sets.NewString()
|
||||||
|
if len(cidrs) == 0 {
|
||||||
|
uniqueAddressList.Insert(IPv4ZeroCIDR)
|
||||||
|
uniqueAddressList.Insert(IPv6ZeroCIDR)
|
||||||
|
return uniqueAddressList, nil
|
||||||
|
}
|
||||||
|
// First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
if IsZeroCIDR(cidr) {
|
||||||
|
uniqueAddressList.Insert(cidr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Second round of iteration to parse IPs based on cidr.
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
if IsZeroCIDR(cidr) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, ipNet, _ := net.ParseCIDR(cidr)
|
||||||
|
itfs, err := nw.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error listing all interfaces from host, error: %v", err)
|
||||||
|
}
|
||||||
|
for _, itf := range itfs {
|
||||||
|
addrs, err := nw.Addrs(&itf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting address from interface %s, error: %v", itf.Name, err)
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if addr == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ip, _, err := net.ParseCIDR(addr.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing CIDR for interface %s, error: %v", itf.Name, err)
|
||||||
|
}
|
||||||
|
if ipNet.Contains(ip) {
|
||||||
|
if conntrack.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
|
||||||
|
uniqueAddressList.Insert(ip.String())
|
||||||
|
}
|
||||||
|
if !conntrack.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
|
||||||
|
uniqueAddressList.Insert(ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uniqueAddressList, nil
|
||||||
|
}
|
||||||
|
@ -17,11 +17,14 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
fake "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestShouldSkipService(t *testing.T) {
|
func TestShouldSkipService(t *testing.T) {
|
||||||
@ -109,3 +112,218 @@ func TestShouldSkipService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InterfaceAddrsPair struct {
|
||||||
|
itf net.Interface
|
||||||
|
addrs []net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNodeAddressses(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
cidrs []string
|
||||||
|
nw *fake.FakeNetwork
|
||||||
|
itfAddrsPairs []InterfaceAddrsPair
|
||||||
|
expected sets.String
|
||||||
|
}{
|
||||||
|
{ // case 0
|
||||||
|
cidrs: []string{"10.20.30.0/24"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "100.200.201.1/24"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("10.20.30.51"),
|
||||||
|
},
|
||||||
|
{ // case 1
|
||||||
|
cidrs: []string{"0.0.0.0/0"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("0.0.0.0/0"),
|
||||||
|
},
|
||||||
|
{ // case 2
|
||||||
|
cidrs: []string{"2001:db8::/32", "::1/128"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("2001:db8::1", "::1"),
|
||||||
|
},
|
||||||
|
{ // case 3
|
||||||
|
cidrs: []string{"::/0"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("::/0"),
|
||||||
|
},
|
||||||
|
{ // case 4
|
||||||
|
cidrs: []string{"127.0.0.1/32"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("127.0.0.1"),
|
||||||
|
},
|
||||||
|
{ // case 5
|
||||||
|
cidrs: []string{"127.0.0.0/8"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.1.1/8"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("127.0.1.1"),
|
||||||
|
},
|
||||||
|
{ // case 6
|
||||||
|
cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "10.20.30.51/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 2, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "100.200.201.1/24"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("10.20.30.51", "100.200.201.1"),
|
||||||
|
},
|
||||||
|
{ // case 7
|
||||||
|
cidrs: []string{"10.20.30.0/24", "100.200.201.0/24"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "192.168.1.2/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString(),
|
||||||
|
},
|
||||||
|
{ // case 8
|
||||||
|
cidrs: []string{},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "192.168.1.2/24"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "127.0.0.1/8"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("0.0.0.0/0", "::/0"),
|
||||||
|
},
|
||||||
|
{ // case 9
|
||||||
|
cidrs: []string{},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "2001:db8::1/32"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("0.0.0.0/0", "::/0"),
|
||||||
|
},
|
||||||
|
{ // case 9
|
||||||
|
cidrs: []string{"1.2.3.0/24", "0.0.0.0/0"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("0.0.0.0/0"),
|
||||||
|
},
|
||||||
|
{ // case 10
|
||||||
|
cidrs: []string{"0.0.0.0/0", "1.2.3.0/24", "::1/128"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("0.0.0.0/0", "::1"),
|
||||||
|
},
|
||||||
|
{ // case 11
|
||||||
|
cidrs: []string{"::/0", "1.2.3.0/24", "::1/128"},
|
||||||
|
nw: fake.NewFakeNetwork(),
|
||||||
|
itfAddrsPairs: []InterfaceAddrsPair{
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 0, MTU: 0, Name: "eth0", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "1.2.3.4/30"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itf: net.Interface{Index: 1, MTU: 0, Name: "lo", HardwareAddr: nil, Flags: 0},
|
||||||
|
addrs: []net.Addr{fake.AddrStruct{Val: "::1/128"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: sets.NewString("::/0", "1.2.3.4"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range testCases {
|
||||||
|
for _, pair := range testCases[i].itfAddrsPairs {
|
||||||
|
testCases[i].nw.AddInterfaceAddr(&pair.itf, pair.addrs)
|
||||||
|
}
|
||||||
|
addrList, err := GetNodeAddresses(testCases[i].cidrs, testCases[i].nw)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("case [%d], unexpected error: %v", i, err)
|
||||||
|
}
|
||||||
|
if !addrList.Equal(testCases[i].expected) {
|
||||||
|
t.Errorf("case [%d], unexpected mismatch, expected: %v, got: %v", i, testCases[i].expected, addrList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user