Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kube-proxy cleanup: Changing FilterIncorrectIP/CIDR functions to MapIPsToIPFamily that returns a map #96488

Merged
merged 5 commits into from Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions pkg/proxy/iptables/proxier.go
Expand Up @@ -294,10 +294,11 @@ func NewProxier(ipt utiliptables.Interface,
ipFamily = v1.IPv6Protocol
}

var incorrectAddresses []string
nodePortAddresses, incorrectAddresses = utilproxy.FilterIncorrectCIDRVersion(nodePortAddresses, ipFamily)
if len(incorrectAddresses) > 0 {
klog.Warningf("NodePortAddresses of wrong family; %s", incorrectAddresses)
ipFamilyMap := utilproxy.MapCIDRsByIPFamily(nodePortAddresses)
nodePortAddresses = ipFamilyMap[ipFamily]
// Log the IPs not matching the ipFamily
if ips, ok := ipFamilyMap[utilproxy.OtherIPFamily(ipFamily)]; ok && len(ips) > 0 {
klog.Warningf("IP Family: %s, NodePortAddresses of wrong family; %s", ipFamily, strings.Join(ips, ","))
}

proxier := &Proxier{
Expand Down Expand Up @@ -367,17 +368,17 @@ func NewDualStackProxier(
nodePortAddresses []string,
) (proxy.Provider, error) {
// Create an ipv4 instance of the single-stack proxier
nodePortAddresses4, nodePortAddresses6 := utilproxy.FilterIncorrectCIDRVersion(nodePortAddresses, v1.IPv4Protocol)
ipFamilyMap := utilproxy.MapCIDRsByIPFamily(nodePortAddresses)
ipv4Proxier, err := NewProxier(ipt[0], sysctl,
exec, syncPeriod, minSyncPeriod, masqueradeAll, masqueradeBit, localDetectors[0], hostname,
nodeIP[0], recorder, healthzServer, nodePortAddresses4)
nodeIP[0], recorder, healthzServer, ipFamilyMap[v1.IPv4Protocol])
if err != nil {
return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err)
}

ipv6Proxier, err := NewProxier(ipt[1], sysctl,
exec, syncPeriod, minSyncPeriod, masqueradeAll, masqueradeBit, localDetectors[1], hostname,
nodeIP[1], recorder, healthzServer, nodePortAddresses6)
nodeIP[1], recorder, healthzServer, ipFamilyMap[v1.IPv6Protocol])
if err != nil {
return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err)
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/proxy/ipvs/proxier.go
Expand Up @@ -450,11 +450,13 @@ func NewProxier(ipt utiliptables.Interface,

endpointSlicesEnabled := utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceProxying)

var incorrectAddresses []string
nodePortAddresses, incorrectAddresses = utilproxy.FilterIncorrectCIDRVersion(nodePortAddresses, ipFamily)
if len(incorrectAddresses) > 0 {
klog.Warningf("NodePortAddresses of wrong family; %s", incorrectAddresses)
ipFamilyMap := utilproxy.MapCIDRsByIPFamily(nodePortAddresses)
nodePortAddresses = ipFamilyMap[ipFamily]
// Log the IPs not matching the ipFamily
if ips, ok := ipFamilyMap[utilproxy.OtherIPFamily(ipFamily)]; ok && len(ips) > 0 {
klog.Warningf("IP Family: %s, NodePortAddresses of wrong family; %s", ipFamily, strings.Join(ips, ","))
}

proxier := &Proxier{
ipFamily: ipFamily,
portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable),
Expand Down Expand Up @@ -532,14 +534,14 @@ func NewDualStackProxier(

safeIpset := newSafeIpset(ipset)

nodePortAddresses4, nodePortAddresses6 := utilproxy.FilterIncorrectCIDRVersion(nodePortAddresses, v1.IPv4Protocol)
ipFamilyMap := utilproxy.MapCIDRsByIPFamily(nodePortAddresses)

// Create an ipv4 instance of the single-stack proxier
ipv4Proxier, err := NewProxier(ipt[0], ipvs, safeIpset, sysctl,
exec, syncPeriod, minSyncPeriod, filterCIDRs(false, excludeCIDRs), strictARP,
tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit,
localDetectors[0], hostname, nodeIP[0],
recorder, healthzServer, scheduler, nodePortAddresses4, kernelHandler)
recorder, healthzServer, scheduler, ipFamilyMap[v1.IPv4Protocol], kernelHandler)
if err != nil {
return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err)
}
Expand All @@ -548,7 +550,7 @@ func NewDualStackProxier(
exec, syncPeriod, minSyncPeriod, filterCIDRs(true, excludeCIDRs), strictARP,
tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit,
localDetectors[1], hostname, nodeIP[1],
nil, nil, scheduler, nodePortAddresses6, kernelHandler)
nil, nil, scheduler, ipFamilyMap[v1.IPv6Protocol], kernelHandler)
if err != nil {
return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err)
}
Expand Down
26 changes: 15 additions & 11 deletions pkg/proxy/service.go
Expand Up @@ -156,15 +156,19 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic
// services, this is actually expected. Hence we downgraded from reporting by events
// to just log lines with high verbosity

var incorrectIPs []string
info.externalIPs, incorrectIPs = utilproxy.FilterIncorrectIPVersion(service.Spec.ExternalIPs, sct.ipFamily)
if len(incorrectIPs) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following external IPs(%s) for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(incorrectIPs, ","), service.Namespace, service.Name)
ipFamilyMap := utilproxy.MapIPsByIPFamily(service.Spec.ExternalIPs)
info.externalIPs = ipFamilyMap[sct.ipFamily]

// Log the IPs not matching the ipFamily
if ips, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(ips) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following external IPs(%s) for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(ips, ","), service.Namespace, service.Name)
}

info.loadBalancerSourceRanges, incorrectIPs = utilproxy.FilterIncorrectCIDRVersion(loadBalancerSourceRanges, sct.ipFamily)
if len(incorrectIPs) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following load balancer source ranges(%s) for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(incorrectIPs, ","), service.Namespace, service.Name)
ipFamilyMap = utilproxy.MapCIDRsByIPFamily(loadBalancerSourceRanges)
info.loadBalancerSourceRanges = ipFamilyMap[sct.ipFamily]
// Log the CIDRs not matching the ipFamily
if cidrs, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(cidrs) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following load balancer source ranges(%s) for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(cidrs, ","), service.Namespace, service.Name)
}

// Obtain Load Balancer Ingress IPs
Expand All @@ -174,14 +178,14 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic
}

if len(ips) > 0 {
correctIPs, incorrectIPs := utilproxy.FilterIncorrectIPVersion(ips, sct.ipFamily)
ipFamilyMap = utilproxy.MapIPsByIPFamily(ips)

if len(incorrectIPs) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following load balancer(%s) ingress ips for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(incorrectIPs, ","), service.Namespace, service.Name)
if ipList, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(ipList) > 0 {
klog.V(4).Infof("service change tracker(%v) ignored the following load balancer(%s) ingress ips for service %v/%v as they don't match IPFamily", sct.ipFamily, strings.Join(ipList, ","), service.Namespace, service.Name)

}
// Create the LoadBalancerStatus with the filtered IPs
for _, ip := range correctIPs {
for _, ip := range ipFamilyMap[sct.ipFamily] {
info.loadBalancerStatus.Ingress = append(info.loadBalancerStatus.Ingress, v1.LoadBalancerIngress{IP: ip})
}
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/proxy/service_test.go
Expand Up @@ -434,7 +434,9 @@ func TestServiceToServiceMap(t *testing.T) {
},
},
{
desc: "service with extra space in LoadBalancerSourceRanges",
desc: "service with extra space in LoadBalancerSourceRanges",
ipFamily: v1.IPv4Protocol,

service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "extra-space",
Expand Down
68 changes: 53 additions & 15 deletions pkg/proxy/util/utils.go
Expand Up @@ -255,26 +255,64 @@ func LogAndEmitIncorrectIPVersionEvent(recorder record.EventRecorder, fieldName,
}
}

// FilterIncorrectIPVersion filters out the incorrect IP version case from a slice of IP strings.
func FilterIncorrectIPVersion(ipStrings []string, ipfamily v1.IPFamily) ([]string, []string) {
return filterWithCondition(ipStrings, (ipfamily == v1.IPv6Protocol), utilnet.IsIPv6String)
}

// FilterIncorrectCIDRVersion filters out the incorrect IP version case from a slice of CIDR strings.
func FilterIncorrectCIDRVersion(ipStrings []string, ipfamily v1.IPFamily) ([]string, []string) {
return filterWithCondition(ipStrings, (ipfamily == v1.IPv6Protocol), utilnet.IsIPv6CIDRString)
// MapIPsByIPFamily maps a slice of IPs to their respective IP families (v4 or v6)
func MapIPsByIPFamily(ipStrings []string) map[v1.IPFamily][]string {
ipFamilyMap := map[v1.IPFamily][]string{}
for _, ip := range ipStrings {
// Handle only the valid IPs
if ipFamily, err := getIPFamilyFromIP(ip); err == nil {
ipFamilyMap[ipFamily] = append(ipFamilyMap[ipFamily], ip)
} else {
klog.Errorf("Skipping invalid IP: %s", ip)
}
}
return ipFamilyMap
}

func filterWithCondition(strs []string, expectedCondition bool, conditionFunc func(string) bool) ([]string, []string) {
var corrects, incorrects []string
for _, str := range strs {
if conditionFunc(str) != expectedCondition {
incorrects = append(incorrects, str)
// MapCIDRsByIPFamily maps a slice of IPs to their respective IP families (v4 or v6)
func MapCIDRsByIPFamily(cidrStrings []string) map[v1.IPFamily][]string {
ipFamilyMap := map[v1.IPFamily][]string{}
for _, cidr := range cidrStrings {
// Handle only the valid CIDRs
if ipFamily, err := getIPFamilyFromCIDR(cidr); err == nil {
ipFamilyMap[ipFamily] = append(ipFamilyMap[ipFamily], cidr)
} else {
corrects = append(corrects, str)
klog.Errorf("Skipping invalid cidr: %s", cidr)
}
}
return corrects, incorrects
return ipFamilyMap
}

func getIPFamilyFromIP(ipStr string) (v1.IPFamily, error) {
netIP := net.ParseIP(ipStr)
if netIP == nil {
return "", ErrAddressNotAllowed
}

if utilnet.IsIPv6(netIP) {
return v1.IPv6Protocol, nil
}
return v1.IPv4Protocol, nil
}

func getIPFamilyFromCIDR(cidrStr string) (v1.IPFamily, error) {
_, netCIDR, err := net.ParseCIDR(cidrStr)
if err != nil {
return "", ErrAddressNotAllowed
}
if utilnet.IsIPv6CIDR(netCIDR) {
return v1.IPv6Protocol, nil
}
return v1.IPv4Protocol, nil
}

// OtherIPFamily returns the other ip family
func OtherIPFamily(ipFamily v1.IPFamily) v1.IPFamily {
if ipFamily == v1.IPv6Protocol {
return v1.IPv4Protocol
}

return v1.IPv6Protocol
}

// AppendPortIfNeeded appends the given port to IP address unless it is already in
Expand Down
119 changes: 113 additions & 6 deletions pkg/proxy/util/utils_test.go
Expand Up @@ -567,7 +567,7 @@ func TestShuffleStrings(t *testing.T) {
}
}

func TestFilterIncorrectIPVersion(t *testing.T) {
func TestMapIPsByIPFamily(t *testing.T) {
testCases := []struct {
desc string
ipString []string
Expand Down Expand Up @@ -650,15 +650,122 @@ func TestFilterIncorrectIPVersion(t *testing.T) {
for _, testcase := range testCases {
t.Run(testcase.desc, func(t *testing.T) {
ipFamily := v1.IPv4Protocol
otherIPFamily := v1.IPv6Protocol

if testcase.wantIPv6 {
ipFamily = v1.IPv6Protocol
otherIPFamily = v1.IPv4Protocol
}

ipMap := MapIPsByIPFamily(testcase.ipString)

if !reflect.DeepEqual(testcase.expectCorrect, ipMap[ipFamily]) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, ipMap[ipFamily])
}
if !reflect.DeepEqual(testcase.expectIncorrect, ipMap[otherIPFamily]) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, ipMap[otherIPFamily])
}
correct, incorrect := FilterIncorrectIPVersion(testcase.ipString, ipFamily)
if !reflect.DeepEqual(testcase.expectCorrect, correct) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, correct)
})
}
}

func TestMapCIDRsByIPFamily(t *testing.T) {
testCases := []struct {
desc string
ipString []string
wantIPv6 bool
expectCorrect []string
expectIncorrect []string
}{
{
desc: "empty input IPv4",
ipString: []string{},
wantIPv6: false,
expectCorrect: nil,
expectIncorrect: nil,
},
{
desc: "empty input IPv6",
ipString: []string{},
wantIPv6: true,
expectCorrect: nil,
expectIncorrect: nil,
},
{
desc: "want IPv4 and receive IPv6",
ipString: []string{"fd00:20::1/64"},
wantIPv6: false,
expectCorrect: nil,
expectIncorrect: []string{"fd00:20::1/64"},
},
{
desc: "want IPv6 and receive IPv4",
ipString: []string{"192.168.200.2/24"},
wantIPv6: true,
expectCorrect: nil,
expectIncorrect: []string{"192.168.200.2/24"},
},
{
desc: "want IPv6 and receive IPv4 and IPv6",
ipString: []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"},
wantIPv6: true,
expectCorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
},
{
desc: "want IPv4 and receive IPv4 and IPv6",
ipString: []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"},
wantIPv6: false,
expectCorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
},
{
desc: "want IPv4 and receive IPv4 only",
ipString: []string{"192.168.200.2/24", "192.1.34.23/24"},
wantIPv6: false,
expectCorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
expectIncorrect: nil,
},
{
desc: "want IPv6 and receive IPv4 only",
ipString: []string{"192.168.200.2/24", "192.1.34.23/24"},
wantIPv6: true,
expectCorrect: nil,
expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
},
{
desc: "want IPv4 and receive IPv6 only",
ipString: []string{"fd00:20::1/64", "2001:db9::3/64"},
wantIPv6: false,
expectCorrect: nil,
expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
},
{
desc: "want IPv6 and receive IPv6 only",
ipString: []string{"fd00:20::1/64", "2001:db9::3/64"},
wantIPv6: true,
expectCorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
expectIncorrect: nil,
},
}

for _, testcase := range testCases {
t.Run(testcase.desc, func(t *testing.T) {
ipFamily := v1.IPv4Protocol
otherIPFamily := v1.IPv6Protocol

if testcase.wantIPv6 {
ipFamily = v1.IPv6Protocol
otherIPFamily = v1.IPv4Protocol
}

cidrMap := MapCIDRsByIPFamily(testcase.ipString)

if !reflect.DeepEqual(testcase.expectCorrect, cidrMap[ipFamily]) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, cidrMap[ipFamily])
}
if !reflect.DeepEqual(testcase.expectIncorrect, incorrect) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, incorrect)
if !reflect.DeepEqual(testcase.expectIncorrect, cidrMap[otherIPFamily]) {
t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, cidrMap[otherIPFamily])
}
})
}
Expand Down