Skip to content

Commit 59d4fa8

Browse files
committed
Fix IPv6 preAllocation canonicalization in IPAM
- Compare IP addresses by parsed value instead of raw strings to handle non-canonical IPv6 formats (::0005 vs ::5). - Also adding regression tests. Signed-off-by: Kashif Khan <[email protected]>
1 parent cf664af commit 59d4fa8

File tree

2 files changed

+74
-8
lines changed

2 files changed

+74
-8
lines changed

ipam/ippool_manager.go

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

1919
import (
2020
"context"
21+
"net"
2122
"reflect"
2223
"strings"
2324

@@ -45,6 +46,15 @@ const (
4546
defaultListLimit = 200
4647
)
4748

49+
func ipEqual(a, b ipamv1.IPAddressStr) bool {
50+
ipA := net.ParseIP(string(a))
51+
ipB := net.ParseIP(string(b))
52+
if ipA == nil || ipB == nil {
53+
return false
54+
}
55+
return ipA.Equal(ipB)
56+
}
57+
4858
// IPPoolManagerInterface is an interface for a IPPoolManager.
4959
type IPPoolManagerInterface interface {
5060
SetFinalizer()
@@ -436,7 +446,7 @@ func (m *IPPoolManager) allocateAddress(addressClaim *ipamv1.IPClaim,
436446
isRequestedIPAllocated := false
437447

438448
// Conflict-case, claim is preAllocated but has requested different IP
439-
if requestedIP != "" && ipPreAllocated && requestedIP != preAllocatedAddress {
449+
if requestedIP != "" && ipPreAllocated && !ipEqual(requestedIP, preAllocatedAddress) {
440450
addressClaim.Status.ErrorMessage = ptr.To("PreAllocation and requested ip address are conflicting")
441451
return "", 0, nil, []ipamv1.IPAddressStr{}, errors.New("PreAllocation and requested ip address are conflicting")
442452
}
@@ -453,15 +463,15 @@ func (m *IPPoolManager) allocateAddress(addressClaim *ipamv1.IPClaim,
453463
}
454464
index++
455465
// Check if requestedIP is present and matches the current address
456-
if requestedIP != "" && allocatedAddress != requestedIP {
466+
if requestedIP != "" && !ipEqual(allocatedAddress, requestedIP) {
457467
continue
458468
}
459-
if requestedIP != "" && allocatedAddress == requestedIP {
469+
if requestedIP != "" && ipEqual(allocatedAddress, requestedIP) {
460470
isRequestedIPAllocated = true
461471
}
462472
// We have a pre-allocated ip, we just need to ensure that it matches the current address
463473
// if it does not, continue and try the next address
464-
if ipPreAllocated && allocatedAddress != preAllocatedAddress {
474+
if ipPreAllocated && !ipEqual(allocatedAddress, preAllocatedAddress) {
465475
continue
466476
}
467477
// Here the two addresses match, so we continue with that one
@@ -527,7 +537,7 @@ func (m *IPPoolManager) capiAllocateAddress(addressClaim *capipamv1beta1.IPAddre
527537
isRequestedIPAllocated := false
528538

529539
// Conflict-case, claim is preAllocated but has requested different IP
530-
if requestedIP != "" && ipPreAllocated && requestedIP != preAllocatedAddress {
540+
if requestedIP != "" && ipPreAllocated && !ipEqual(requestedIP, preAllocatedAddress) {
531541
conditions := clusterv1beta1.Conditions{}
532542
conditions = append(conditions, clusterv1beta1.Condition{
533543
Type: "ErrorMessage",
@@ -553,15 +563,15 @@ func (m *IPPoolManager) capiAllocateAddress(addressClaim *capipamv1beta1.IPAddre
553563
}
554564
index++
555565
// Check if requestedIP is present and matches the current address
556-
if requestedIP != "" && allocatedAddress != requestedIP {
566+
if requestedIP != "" && !ipEqual(allocatedAddress, requestedIP) {
557567
continue
558568
}
559-
if requestedIP != "" && allocatedAddress == requestedIP {
569+
if requestedIP != "" && ipEqual(allocatedAddress, requestedIP) {
560570
isRequestedIPAllocated = true
561571
}
562572
// We have a pre-allocated ip, we just need to ensure that it matches the current address
563573
// if it does not, continue and try the next address
564-
if ipPreAllocated && allocatedAddress != preAllocatedAddress {
574+
if ipPreAllocated && !ipEqual(allocatedAddress, preAllocatedAddress) {
565575
continue
566576
}
567577
// Here the two addresses match, so we continue with that one

ipam/ippool_manager_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,37 @@ var _ = Describe("IPPool manager", func() {
20112011
},
20122012
expectedPrefix: 24,
20132013
}),
2014+
Entry("One pool, IPv6 pre-allocated (non-canonical)", testCaseAllocateAddress{
2015+
ipPool: &ipamv1.IPPool{
2016+
Spec: ipamv1.IPPoolSpec{
2017+
Pools: []ipamv1.Pool{
2018+
{
2019+
Start: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::1")),
2020+
End: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::a")),
2021+
},
2022+
},
2023+
PreAllocations: map[string]ipamv1.IPAddressStr{
2024+
"TestRef": ipamv1.IPAddressStr("2001:db8::0005"),
2025+
},
2026+
Prefix: 64,
2027+
Gateway: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::ffff")),
2028+
DNSServers: []ipamv1.IPAddressStr{
2029+
ipamv1.IPAddressStr("2001:4860:4860::8888"),
2030+
},
2031+
},
2032+
},
2033+
ipClaim: &ipamv1.IPClaim{
2034+
ObjectMeta: metav1.ObjectMeta{
2035+
Name: "TestRef",
2036+
},
2037+
},
2038+
expectedAddress: ipamv1.IPAddressStr("2001:db8::5"),
2039+
expectedGateway: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::ffff")),
2040+
expectedDNSServers: []ipamv1.IPAddressStr{
2041+
ipamv1.IPAddressStr("2001:4860:4860::8888"),
2042+
},
2043+
expectedPrefix: 64,
2044+
}),
20142045
Entry("One pool, pre-allocated, with overrides", testCaseAllocateAddress{
20152046
ipPool: &ipamv1.IPPool{
20162047
Spec: ipamv1.IPPoolSpec{
@@ -2459,6 +2490,31 @@ var _ = Describe("IPPool manager", func() {
24592490
expectedGateway: (*ipamv1.IPAddressStr)(ptr.To("192.168.0.1")),
24602491
expectedPrefix: 24,
24612492
}),
2493+
Entry("One pool, IPv6 pre-allocated (non-canonical)", testCapiCaseAllocateAddress{
2494+
ipPool: &ipamv1.IPPool{
2495+
Spec: ipamv1.IPPoolSpec{
2496+
Pools: []ipamv1.Pool{
2497+
{
2498+
Start: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::1")),
2499+
End: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::a")),
2500+
},
2501+
},
2502+
PreAllocations: map[string]ipamv1.IPAddressStr{
2503+
"TestRef": ipamv1.IPAddressStr("2001:db8::0005"),
2504+
},
2505+
Prefix: 64,
2506+
Gateway: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::ffff")),
2507+
},
2508+
},
2509+
ipAddressClaim: &capipamv1beta1.IPAddressClaim{
2510+
ObjectMeta: metav1.ObjectMeta{
2511+
Name: "TestRef",
2512+
},
2513+
},
2514+
expectedAddress: ipamv1.IPAddressStr("2001:db8::5"),
2515+
expectedGateway: (*ipamv1.IPAddressStr)(ptr.To("2001:db8::ffff")),
2516+
expectedPrefix: 64,
2517+
}),
24622518
Entry("One pool, pre-allocated, with overrides", testCapiCaseAllocateAddress{
24632519
ipPool: &ipamv1.IPPool{
24642520
Spec: ipamv1.IPPoolSpec{

0 commit comments

Comments
 (0)