Skip to content

Commit

Permalink
pkg/proxy: refactor npa.GetNodeIPs
Browse files Browse the repository at this point in the history
Signed-off-by: Daman Arora <[email protected]>
  • Loading branch information
aroradaman committed Sep 23, 2024
1 parent 11c0683 commit a3ad527
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 32 deletions.
33 changes: 1 addition & 32 deletions pkg/proxy/util/nodeport_addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,38 +94,7 @@ func (npa *NodePortAddresses) MatchAll() bool {
// IPs are found, it returns an empty list.
// NetworkInterfacer is injected for test purpose.
func (npa *NodePortAddresses) GetNodeIPs(nw NetworkInterfacer) ([]net.IP, error) {
addrs, err := nw.InterfaceAddrs()
if err != nil {
return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %v", err)
}

// Use a map to dedup matches
addresses := make(map[string]net.IP)
for _, cidr := range npa.cidrs {
for _, addr := range addrs {
var ip net.IP
// nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux.
switch v := addr.(type) {
case *net.IPAddr:
ip = v.IP
case *net.IPNet:
ip = v.IP
default:
continue
}

if cidr.Contains(ip) {
addresses[ip.String()] = ip
}
}
}

ips := make([]net.IP, 0, len(addresses))
for _, ip := range addresses {
ips = append(ips, ip)
}

return ips, nil
return FilterInterfaceAddrsByCIDRs(nw, npa.cidrs)
}

// ContainsIPv4Loopback returns true if npa's CIDRs contain an IPv4 loopback address.
Expand Down
46 changes: 46 additions & 0 deletions pkg/proxy/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,49 @@ func IsVIPMode(ing v1.LoadBalancerIngress) bool {
}
return *ing.IPMode == v1.LoadBalancerIPModeVIP
}

// FilterInterfaceAddrsByCIDRs filters the IP addresses of the provided NetworkInterfacer,
// returning only those that belong to any of the CIDRs specified in the given list.
func FilterInterfaceAddrsByCIDRs(nw NetworkInterfacer, cidrs []*net.IPNet) ([]net.IP, error) {
addrs, err := nw.InterfaceAddrs()
if err != nil {
return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %w", err)
}

// Use a map to dedup matches
addresses := make(map[string]net.IP)
for _, cidr := range cidrs {
for _, addr := range addrs {
var ip net.IP
// nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux.
switch v := addr.(type) {
case *net.IPAddr:
ip = v.IP
case *net.IPNet:
ip = v.IP
default:
continue
}

if cidr.Contains(ip) {
addresses[ip.String()] = ip
}
}
}

ips := make([]net.IP, 0, len(addresses))
for _, ip := range addresses {
ips = append(ips, ip)
}

return ips, nil
}

// FilterInterfaceAddrsByCIDRStrings is a wrapper around FilterInterfaceAddrsByCIDRs which accepts CIDRs as list of strings.
func FilterInterfaceAddrsByCIDRStrings(nw NetworkInterfacer, cidrStrings []string) ([]net.IP, error) {
cidrs, err := netutils.ParseCIDRs(cidrStrings)
if err != nil {
return nil, err
}
return FilterInterfaceAddrsByCIDRs(nw, cidrs)
}
58 changes: 58 additions & 0 deletions pkg/proxy/util/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ import (
"reflect"
"testing"

"github.com/stretchr/testify/require"

v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
netutils "k8s.io/utils/net"
)

Expand Down Expand Up @@ -703,3 +706,58 @@ func TestIsZeroCIDR(t *testing.T) {
})
}
}

func TestFilterInterfaceAddrsByCIDRs(t *testing.T) {
networkInterfacer := proxyutiltest.NewFakeNetwork()
var itf net.Interface
var addrs []net.Addr
itf = net.Interface{Index: 0, MTU: 0, Name: "eth1", HardwareAddr: nil, Flags: 0}
addrs = []net.Addr{
&net.IPNet{IP: netutils.ParseIPSloppy("10.10.10.10"), Mask: net.CIDRMask(24, 32)},
&net.IPNet{IP: netutils.ParseIPSloppy("2001:db8::1"), Mask: net.CIDRMask(64, 128)},
}
networkInterfacer.AddInterfaceAddr(&itf, addrs)

itf = net.Interface{Index: 0, MTU: 0, Name: "eth2", HardwareAddr: nil, Flags: 0}
addrs = []net.Addr{
&net.IPNet{IP: netutils.ParseIPSloppy("192.168.0.2"), Mask: net.CIDRMask(24, 32)},
&net.IPNet{IP: netutils.ParseIPSloppy("fd00:4321::2"), Mask: net.CIDRMask(64, 128)},
}
networkInterfacer.AddInterfaceAddr(&itf, addrs)

testCases := []struct {
name string
cidrStrings []string
expected []string
}{
{
name: "ipv4",
cidrStrings: []string{"192.168.0.0/24"},
expected: []string{"192.168.0.2"},
},
{
name: "ipv6",
cidrStrings: []string{"fd00:4321::/64"},
expected: []string{"fd00:4321::2"},
},
{
name: "dual stack",
cidrStrings: []string{"10.10.0.0/16", "2001:db8::/64"},
expected: []string{"10.10.10.10", "2001:db8::1"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cidrs, err := netutils.ParseCIDRs(tc.cidrStrings)
require.NoError(t, err)

ips, err := FilterInterfaceAddrsByCIDRs(networkInterfacer, cidrs)
require.NoError(t, err)
var expected []net.IP
for i := range tc.expected {
expected = append(expected, netutils.ParseIPSloppy(tc.expected[i]))
}
require.Equal(t, expected, ips)
})
}
}

0 comments on commit a3ad527

Please sign in to comment.