Skip to content

Commit bee57e5

Browse files
committed
Add support for netip.Addr and netip.Prefix to IPFamily functions.
All the functions that previously took a net.IP or string now also take a netip.Addr. All the functions that previously took a *net.IPNet or string now also take a netip.Prefix.
1 parent 5dd8e44 commit bee57e5

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

net/v2/ipfamily.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package net
1818

1919
import (
2020
"net"
21+
"net/netip"
2122
)
2223

2324
// IPFamily refers to the IP family of an address or CIDR value. Its values are
@@ -36,16 +37,16 @@ const (
3637
)
3738

3839
type ipOrString interface {
39-
net.IP | string
40+
net.IP | netip.Addr | string
4041
}
4142

4243
type cidrOrString interface {
43-
*net.IPNet | string
44+
*net.IPNet | netip.Prefix | string
4445
}
4546

4647
// IPFamilyOf returns the IP family of val (or IPFamilyUnknown if val is nil or invalid).
4748
// IPv6-encoded IPv4 addresses (e.g., "::ffff:1.2.3.4") are considered IPv4. val can be a
48-
// net.IP or a string containing a single IP address.
49+
// net.IP, a netip.Addr, or a string containing a single IP address.
4950
//
5051
// Note that "k8s.io/utils/net/v2".IPFamily intentionally has identical values to
5152
// "k8s.io/api/core/v1".IPFamily and "k8s.io/discovery/v1".AddressType, so you can cast
@@ -59,6 +60,13 @@ func IPFamilyOf[T ipOrString](val T) IPFamily {
5960
case typedVal.To16() != nil:
6061
return IPv6
6162
}
63+
case netip.Addr:
64+
switch {
65+
case typedVal.Is4(), typedVal.Is4In6():
66+
return IPv4
67+
case typedVal.Is6():
68+
return IPv6
69+
}
6270
case string:
6371
return IPFamilyOf(ParseIPSloppy(typedVal))
6472
}
@@ -103,7 +111,7 @@ func IsDualStackPair[T ipOrString](vals []T) bool {
103111

104112
// IPFamilyOfCIDR returns the IP family of val (or IPFamilyUnknown if val is nil or
105113
// invalid). IPv6-encoded IPv4 addresses (e.g., "::ffff:1.2.3.0/120") are considered IPv4.
106-
// val can be a *net.IPNet or a string containing a single CIDR value.
114+
// val can be a *net.IPNet, a netip.Prefix, or a string containing a single CIDR value.
107115
//
108116
// Note that "k8s.io/utils/net/v2".IPFamily intentionally has identical values to
109117
// "k8s.io/api/core/v1".IPFamily and "k8s.io/discovery/v1".AddressType, so you can cast
@@ -120,6 +128,11 @@ func IPFamilyOfCIDR[T cidrOrString](val T) IPFamily {
120128
return family
121129
}
122130
}
131+
case netip.Prefix:
132+
if !typedVal.IsValid() {
133+
return IPFamilyUnknown
134+
}
135+
return IPFamilyOf(typedVal.Addr())
123136
case string:
124137
parsedIP, _, _ := ParseCIDRSloppy(typedVal)
125138
return IPFamilyOf(parsedIP)

net/v2/ipfamily_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package net
1919
import (
2020
"fmt"
2121
"net"
22+
"net/netip"
2223
"testing"
2324
)
2425

@@ -87,8 +88,10 @@ func TestIsDualStack(t *testing.T) {
8788
for _, tc := range testCases {
8889
t.Run(tc.desc, func(t *testing.T) {
8990
netips := make([]net.IP, len(tc.ips))
91+
addrs := make([]netip.Addr, len(tc.ips))
9092
for i := range tc.ips {
9193
netips[i] = ParseIPSloppy(tc.ips[i])
94+
addrs[i], _ = netip.ParseAddr(tc.ips[i])
9295
}
9396

9497
dualStack := IsDualStack(tc.ips)
@@ -106,6 +109,14 @@ func TestIsDualStack(t *testing.T) {
106109
if IsDualStackPair(netips) != (dualStack && len(tc.ips) == 2) {
107110
t.Errorf("IsDualStackIPPair gave wrong result for []net.IP")
108111
}
112+
113+
dualStack = IsDualStack(addrs)
114+
if dualStack != tc.expectedResult {
115+
t.Errorf("expected %v []netip.Addr got %v", tc.expectedResult, dualStack)
116+
}
117+
if IsDualStackPair(addrs) != (dualStack && len(tc.ips) == 2) {
118+
t.Errorf("IsDualStackIPPair gave wrong result for []netip.Addr")
119+
}
109120
})
110121
}
111122
}
@@ -166,8 +177,10 @@ func TestIsDualStackCIDRs(t *testing.T) {
166177
for _, tc := range testCases {
167178
t.Run(tc.desc, func(t *testing.T) {
168179
ipnets := make([]*net.IPNet, len(tc.cidrs))
180+
prefixes := make([]netip.Prefix, len(tc.cidrs))
169181
for i := range tc.cidrs {
170182
_, ipnets[i], _ = ParseCIDRSloppy(tc.cidrs[i])
183+
prefixes[i], _ = netip.ParsePrefix(tc.cidrs[i])
171184
}
172185

173186
dualStack := IsDualStackCIDRs(tc.cidrs)
@@ -185,6 +198,14 @@ func TestIsDualStackCIDRs(t *testing.T) {
185198
if IsDualStackCIDRPair(ipnets) != (dualStack && len(tc.cidrs) == 2) {
186199
t.Errorf("IsDualStackCIDRPair gave wrong result for []*net.IPNet")
187200
}
201+
202+
dualStack = IsDualStackCIDRs(prefixes)
203+
if dualStack != tc.expectedResult {
204+
t.Errorf("expected %v []netip.Prefix got %v", tc.expectedResult, dualStack)
205+
}
206+
if IsDualStackCIDRPair(prefixes) != (dualStack && len(tc.cidrs) == 2) {
207+
t.Errorf("IsDualStackCIDRPair gave wrong result for []netip.Prefix")
208+
}
188209
})
189210
}
190211
}
@@ -221,6 +242,12 @@ func TestIPFamilyOf(t *testing.T) {
221242
isIPv6 := IsIPv6(ip)
222243
checkOneIPFamily(t, ip.String(), tc.family, family, isIPv4, isIPv6)
223244
}
245+
for _, addr := range tc.addrs {
246+
family := IPFamilyOf(addr)
247+
isIPv4 := IsIPv4(addr)
248+
isIPv6 := IsIPv6(addr)
249+
checkOneIPFamily(t, addr.String(), tc.family, family, isIPv4, isIPv6)
250+
}
224251
})
225252
}
226253

@@ -236,6 +263,12 @@ func TestIPFamilyOf(t *testing.T) {
236263
isIPv6 := IsIPv6(ip)
237264
checkOneIPFamily(t, fmt.Sprintf("%#v", ip), IPFamilyUnknown, family, isIPv4, isIPv6)
238265
}
266+
for _, addr := range tc.addrs {
267+
family := IPFamilyOf(addr)
268+
isIPv4 := IsIPv4(addr)
269+
isIPv6 := IsIPv6(addr)
270+
checkOneIPFamily(t, fmt.Sprintf("%#v", addr), IPFamilyUnknown, family, isIPv4, isIPv6)
271+
}
239272
for _, str := range tc.strings {
240273
family := IPFamilyOf(str)
241274
isIPv4 := IsIPv4(str)
@@ -265,6 +298,12 @@ func TestIPFamilyOfCIDR(t *testing.T) {
265298
isIPv6 := IsIPv6CIDR(ipnet)
266299
checkOneIPFamily(t, ipnet.String(), tc.family, family, isIPv4, isIPv6)
267300
}
301+
for _, prefix := range tc.prefixes {
302+
family := IPFamilyOfCIDR(prefix)
303+
isIPv4 := IsIPv4CIDR(prefix)
304+
isIPv6 := IsIPv6CIDR(prefix)
305+
checkOneIPFamily(t, prefix.String(), tc.family, family, isIPv4, isIPv6)
306+
}
268307
})
269308
}
270309

@@ -284,6 +323,12 @@ func TestIPFamilyOfCIDR(t *testing.T) {
284323
}
285324
checkOneIPFamily(t, str, IPFamilyUnknown, family, isIPv4, isIPv6)
286325
}
326+
for _, prefix := range tc.prefixes {
327+
family := IPFamilyOfCIDR(prefix)
328+
isIPv4 := IsIPv4CIDR(prefix)
329+
isIPv6 := IsIPv6CIDR(prefix)
330+
checkOneIPFamily(t, fmt.Sprintf("%#v", prefix), IPFamilyUnknown, family, isIPv4, isIPv6)
331+
}
287332
for _, str := range tc.strings {
288333
family := IPFamilyOfCIDR(str)
289334
isIPv4 := IsIPv4CIDR(str)

net/v2/ips_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type testIP struct {
4545
// IPFamily tests (unless `skipFamily: true`):
4646
// - Each element of .strings should be identified as .family.
4747
// - Each element of .ips should be identified as .family.
48+
// - Each element of .addrs should be identified as .family.
4849
//
4950
// Parsing tests (unless `skipParse: true`):
5051
// - Each element of .strings should parse to a value equal to .ips[0].
@@ -233,6 +234,7 @@ var goodTestIPs = []testIP{
233234
// IPFamily tests (unless `skipFamily: true`):
234235
// - Each element of .strings should be identified as IPFamilyUnknown.
235236
// - Each element of .ips should be identified as IPFamilyUnknown.
237+
// - Each element of .addrs should be identified as IPFamilyUnknown.
236238
//
237239
// Parsing tests (unless `skipParse: true`):
238240
// - Each element of .strings should fail to parse.
@@ -354,6 +356,7 @@ type testCIDR struct {
354356
// IPFamily tests (unless `skipFamily: true`):
355357
// - Each element of .strings should be identified as .family.
356358
// - Each element of .ipnets should be identified as .family.
359+
// - Each element of .prefixes should be identified as .family.
357360
//
358361
// Parsing tests (unless `skipParse: true`):
359362
// - Each element of .strings should parse to a value "equal" to .ipnets[0].
@@ -597,6 +600,7 @@ var goodTestCIDRs = []testCIDR{
597600
// IPFamily tests (unless `skipFamily: true`):
598601
// - Each element of .strings should be identified as IPFamilyUnknown.
599602
// - Each element of .ipnets should be identified as IPFamilyUnknown.
603+
// - Each element of .prefixes should be identified as IPFamilyUnknown.
600604
//
601605
// Parsing tests (unless `skipParse: true`):
602606
// - Each element of .strings should fail to parse.

0 commit comments

Comments
 (0)