From 1271a20eee7839e5971e1cabd893d2b9adc6fec5 Mon Sep 17 00:00:00 2001 From: zhangzujian Date: Thu, 2 Jan 2025 03:08:17 +0000 Subject: [PATCH] e2e: fix duplicate random cidr Signed-off-by: zhangzujian --- test/e2e/framework/util.go | 135 ++++++++++++++++++++++++++----------- 1 file changed, 96 insertions(+), 39 deletions(-) diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 27c13656417..cbdef4e6802 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -6,8 +6,10 @@ import ( "net" "sort" "strings" + "sync" - "github.com/scylladb/go-set/strset" + "k8s.io/utils/ptr" + "k8s.io/utils/set" "github.com/onsi/ginkgo/v2" @@ -25,35 +27,74 @@ func RandomSuffix() string { return fmt.Sprintf("%d%04d%04d", ginkgo.GinkgoParallelProcess(), rand.IntN(10000), rand.IntN(10000)) } -func RandomCIDR(family string) string { - fnIPv4 := func() string { - cidr := net.IPNet{ - IP: net.ParseIP("10.0.0.0").To4(), - Mask: net.CIDRMask(24, 32), +var ( + randCIDRSeedLock4 sync.Mutex + randCIDRSeedLock6 sync.Mutex + usedRandCIDRSeed4 = set.New[byte]() + usedRandCIDRSeed6 = set.New[uint16]() +) + +func randomCIDR4(seed *byte) string { + ginkgo.GinkgoHelper() + + if seed == nil { + randCIDRSeedLock4.Lock() + defer randCIDRSeedLock4.Unlock() + for usedRandCIDRSeed4.Len() < 0xff+1 { + seed = ptr.To(byte(rand.IntN(0xff + 1))) + if !usedRandCIDRSeed4.Has(*seed) { + usedRandCIDRSeed4.Insert(*seed) + break + } } - cidr.IP[1] = 0xf0 | byte(ginkgo.GinkgoParallelProcess()) - cidr.IP[2] = byte(rand.IntN(0xff + 1)) - return cidr.String() + ExpectNotNil(seed, "failed to generate random ipv4 CIDR seed") } - fnIPv6 := func() string { - cidr := net.IPNet{ - IP: net.ParseIP("fc00:10:ff::").To16(), - Mask: net.CIDRMask(96, 128), + cidr := net.IPNet{ + IP: net.ParseIP("10.0.0.0").To4(), + Mask: net.CIDRMask(24, 32), + } + cidr.IP[1] = 0xf0 + cidr.IP[2] = *seed + return cidr.String() +} + +func randomCIDR6(seed *uint16) string { + ginkgo.GinkgoHelper() + + if seed == nil { + randCIDRSeedLock6.Lock() + defer randCIDRSeedLock6.Unlock() + for usedRandCIDRSeed6.Len() < 0xffff+1 { + seed = ptr.To(uint16(rand.IntN(0xffff + 1))) + if !usedRandCIDRSeed6.Has(*seed) { + usedRandCIDRSeed6.Insert(*seed) + break + } } - cidr.IP[9] = byte(ginkgo.GinkgoParallelProcess()) - cidr.IP[10] = byte(rand.IntN(0xff + 1)) - cidr.IP[11] = byte(rand.IntN(0xff + 1)) - return cidr.String() + ExpectNotNil(seed, "failed to generate random ipv6 CIDR seed") } + cidr := net.IPNet{ + IP: net.ParseIP("fc00:10:ff::").To16(), + Mask: net.CIDRMask(96, 128), + } + cidr.IP[9] = byte(ginkgo.GinkgoParallelProcess()) + cidr.IP[10] = byte((*seed) >> 8) + cidr.IP[11] = byte((*seed) & 0xff) + return cidr.String() +} + +func RandomCIDR(family string) string { + ginkgo.GinkgoHelper() + switch family { case IPv4: - return fnIPv4() + return randomCIDR4(nil) case IPv6: - return fnIPv6() + return randomCIDR6(nil) case Dual: - return fnIPv4() + "," + fnIPv6() + return randomCIDR4(nil) + "," + randomCIDR6(nil) default: Failf("invalid ip family: %q", family) return "" @@ -61,6 +102,8 @@ func RandomCIDR(family string) string { } func sortIPs(ips []string) { + ginkgo.GinkgoHelper() + sort.Slice(ips, func(i, j int) bool { x, err := ipam.NewIP(ips[i]) ExpectNoError(err) @@ -72,6 +115,8 @@ func sortIPs(ips []string) { // ipv4/ipv6 only func RandomExcludeIPs(cidr string, count int) []string { + ginkgo.GinkgoHelper() + if cidr == "" || count == 0 { return nil } @@ -101,6 +146,8 @@ func RandomExcludeIPs(cidr string, count int) []string { // ipv4/ipv6 only func randomSortedIPs(cidr string, count int, sort bool) []string { + ginkgo.GinkgoHelper() + if cidr == "" { return nil } @@ -108,14 +155,14 @@ func randomSortedIPs(cidr string, count int, sort bool) []string { _, ipNet, err := net.ParseCIDR(cidr) ExpectNoError(err) - set := strset.NewWithSize(count) + s := set.New[string]() r := ipam.NewIPRangeFromCIDR(*ipNet) r = ipam.NewIPRange(r.Start().Add(2), r.End().Sub(1)) - for set.Size() != count { - set.Add(r.Random().String()) + for s.Len() != count { + s.Insert(r.Random().String()) } - ips := set.List() + ips := s.UnsortedList() if sort { sortIPs(ips) } @@ -124,6 +171,8 @@ func randomSortedIPs(cidr string, count int, sort bool) []string { } func RandomIPs(cidr, sep string, count int) string { + ginkgo.GinkgoHelper() + cidrV4, cidrV6 := util.SplitStringIP(cidr) ipsV4 := randomSortedIPs(cidrV4, count, false) ipsV6 := randomSortedIPs(cidrV6, count, false) @@ -145,6 +194,8 @@ func RandomIPs(cidr, sep string, count int) string { // ipv4/ipv6 only func randomPool(cidr string, count int) []string { + ginkgo.GinkgoHelper() + if cidr == "" || count == 0 { return nil } @@ -157,8 +208,8 @@ func randomPool(cidr string, count int) []string { ones, bits := ipNet.Mask.Size() rl := ipam.NewEmptyIPRangeList() - set := strset.NewWithSize(count) - for set.Size() != count/4 { + s := set.New[string]() + for s.Len() != count/4 { prefix := (ones+bits)/2 + rand.IntN((bits-ones)/2+1) _, ipNet, err = net.ParseCIDR(fmt.Sprintf("%s/%d", r.Random(), prefix)) ExpectNoError(err) @@ -170,26 +221,26 @@ func randomPool(cidr string, count int) []string { } rl = rl.MergeRange(ipam.NewIPRange(start, end)) - set.Add(ipNet.String()) + s.Insert(ipNet.String()) } - count -= set.Size() + count -= s.Len() m := count / 3 // .. n := count - m // ips := make([]ipam.IP, 0, m*2+n) - ipSet := strset.NewWithSize(cap(ips)) + ipSet := set.New[string]() for len(ips) != cap(ips) { ip := r.Random() if rl.Contains(ip) { continue } - s := ip.String() - if ipSet.Has(s) { + ipStr := ip.String() + if ipSet.Has(ipStr) { continue } ips = append(ips, ip) - ipSet.Add(s) + ipSet.Insert(ipStr) } sort.Slice(ips, func(i, j int) bool { return ips[i].LessThan(ips[j]) }) @@ -201,37 +252,43 @@ func randomPool(cidr string, count int) []string { n1, _ := rl.Find(ips[x]) n2, _ := rl.Find(ips[y]) if n1 == n2 && ips[x].LessThan(ips[y]) { - set.Add(fmt.Sprintf("%s..%s", ips[x].String(), ips[y].String())) + s.Insert(fmt.Sprintf("%s..%s", ips[x].String(), ips[y].String())) i, k = i+1, k+2 continue } } if j != n { - set.Add(ips[k%len(ips)].String()) + s.Insert(ips[k%len(ips)].String()) j, k = j+1, k+1 } } - return set.List() + return s.UnsortedList() } func RandomIPPool(cidr string, count int) []string { + ginkgo.GinkgoHelper() + cidrV4, cidrV6 := util.SplitStringIP(cidr) ipsV4, ipsV6 := randomPool(cidrV4, count), randomPool(cidrV6, count) - set := strset.NewWithSize(len(cidrV4) + len(cidrV6)) - set.Add(ipsV4...) - set.Add(ipsV6...) - return set.List() + s := set.New[string]() + s.Insert(ipsV4...) + s.Insert(ipsV6...) + return s.UnsortedList() } func PrevIP(ip string) string { + ginkgo.GinkgoHelper() + v, err := ipam.NewIP(ip) ExpectNoError(err) return v.Sub(1).String() } func NextIP(ip string) string { + ginkgo.GinkgoHelper() + v, err := ipam.NewIP(ip) ExpectNoError(err) return v.Add(1).String()