diff --git a/pkg/registry/core/service/ipallocator/ipallocator.go b/pkg/registry/core/service/ipallocator/ipallocator.go index 8618d541aff..d407ddf5fda 100644 --- a/pkg/registry/core/service/ipallocator/ipallocator.go +++ b/pkg/registry/core/service/ipallocator/ipallocator.go @@ -484,11 +484,21 @@ func (dry dryRunAllocator) EnableMetrics() { // TODO: move it to k8s.io/utils/net, this is the same as current AddIPOffset() // but using netip.Addr instead of net.IP func addOffsetAddress(address netip.Addr, offset uint64) (netip.Addr, error) { - addressBig := big.NewInt(0).SetBytes(address.AsSlice()) - r := big.NewInt(0).Add(addressBig, big.NewInt(int64(offset))) - addr, ok := netip.AddrFromSlice(r.Bytes()) + addressBytes := address.AsSlice() + addressBig := big.NewInt(0).SetBytes(addressBytes) + r := big.NewInt(0).Add(addressBig, big.NewInt(int64(offset))).Bytes() + // r must be 4 or 16 bytes depending of the ip family + // bigInt conversion to bytes will not take this into consideration + // and drop the leading zeros, so we have to take this into account. + lenDiff := len(addressBytes) - len(r) + if lenDiff > 0 { + r = append(make([]byte, lenDiff), r...) + } else if lenDiff < 0 { + return netip.Addr{}, fmt.Errorf("invalid address %v", r) + } + addr, ok := netip.AddrFromSlice(r) if !ok { - return netip.Addr{}, fmt.Errorf("invalid address %v", r.Bytes()) + return netip.Addr{}, fmt.Errorf("invalid address %v", r) } return addr, nil } diff --git a/pkg/registry/core/service/ipallocator/ipallocator_test.go b/pkg/registry/core/service/ipallocator/ipallocator_test.go index 5e80115278a..6c5c73cde76 100644 --- a/pkg/registry/core/service/ipallocator/ipallocator_test.go +++ b/pkg/registry/core/service/ipallocator/ipallocator_test.go @@ -587,6 +587,18 @@ func Test_addOffsetAddress(t *testing.T) { offset: 128, want: netip.MustParseAddr("192.168.0.128"), }, + { + name: "IPv4 with leading zeros", + address: netip.MustParseAddr("0.0.1.8"), + offset: 138, + want: netip.MustParseAddr("0.0.1.146"), + }, + { + name: "IPv6 with leading zeros", + address: netip.MustParseAddr("00fc::1"), + offset: 255, + want: netip.MustParseAddr("fc::100"), + }, { name: "IPv6 offset 255", address: netip.MustParseAddr("2001:db8:1::101"), @@ -643,6 +655,16 @@ func Test_broadcastAddress(t *testing.T) { subnet: netip.MustParsePrefix("fd00:1:2:3::/64"), want: netip.MustParseAddr("fd00:1:2:3:FFFF:FFFF:FFFF:FFFF"), }, + { + name: "ipv6 00fc::/112", + subnet: netip.MustParsePrefix("00fc::/112"), + want: netip.MustParseAddr("fc::ffff"), + }, + { + name: "ipv6 fc00::/112", + subnet: netip.MustParsePrefix("fc00::/112"), + want: netip.MustParseAddr("fc00::ffff"), + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -888,6 +910,25 @@ func Test_ipIterator_Number(t *testing.T) { } } +func TestAllocateNextFC(t *testing.T) { + _, cidr, err := netutils.ParseCIDRSloppy("fc::/112") + if err != nil { + t.Fatal(err) + } + t.Logf("CIDR %s", cidr) + + r, err := newTestAllocator(cidr) + if err != nil { + t.Fatal(err) + } + defer r.Destroy() + ip, err := r.AllocateNext() + if err != nil { + t.Fatalf("wrong ip %s : %v", ip, err) + } + t.Log(ip.String()) +} + func BenchmarkIPAllocatorAllocateNextIPv4Size1048574(b *testing.B) { _, cidr, err := netutils.ParseCIDRSloppy("10.0.0.0/12") if err != nil {