Skip to content

Commit

Permalink
pkg/rand: replace SafeRand by global source in math/rand
Browse files Browse the repository at this point in the history
Since Go 1.20 the top-level math/rand functions are auto-seeded by
default, see https://go.dev/doc/go1.20#library and
golang/go#54880. They also use the runtime's
lock-free fastrand64 function when 1. Seed has not been called and 2.
GODEBUG=randautoseed=0 is not used, see
golang/go#49892.

This allows to drop SafeRand and use the global source again. SafeRand
was originally introduced in commit fac5dde ("rand: add and use
concurrency-safe PRNG source") to fix #10988 by providing a
concurrency-safe PRNG source other than the global math/rand source
which could be used at the time because it can't be interfered with from
unrelated packages by means of calling rand.Seed, see #10575. rand.Seed
is deprecated since Go 1.20 and per the paragraph above the global
source is seeded by default. This makes it unlikely that packages would
interfere with the global PRNG state anymore and the top-level math/rand
functions are safe to use again.

Signed-off-by: Tobias Klauser <tobias@cilium.io>
  • Loading branch information
tklauser committed Dec 8, 2023
1 parent 332bc00 commit b973bf5
Show file tree
Hide file tree
Showing 12 changed files with 26 additions and 218 deletions.
24 changes: 0 additions & 24 deletions contrib/scripts/rand-check.sh

This file was deleted.

4 changes: 2 additions & 2 deletions daemon/cmd/status.go
Expand Up @@ -6,6 +6,7 @@ package cmd
import (
"context"
"fmt"
"math/rand"
"net/http"
"strings"

Expand Down Expand Up @@ -37,7 +38,6 @@ import (
nodeTypes "github.com/cilium/cilium/pkg/node/types"
"github.com/cilium/cilium/pkg/option"
"github.com/cilium/cilium/pkg/promise"
"github.com/cilium/cilium/pkg/rand"
"github.com/cilium/cilium/pkg/status"
"github.com/cilium/cilium/pkg/time"
"github.com/cilium/cilium/pkg/version"
Expand All @@ -54,7 +54,7 @@ const (
k8sMinimumEventHearbeat = time.Minute
)

var randGen = rand.NewSafeRand(time.Now().UnixNano())
var randGen = rand.New(rand.NewSource(time.Now().UnixNano()))

type k8sVersion struct {
version string
Expand Down
7 changes: 4 additions & 3 deletions daemon/cmd/status_test.go
Expand Up @@ -4,6 +4,7 @@
package cmd

import (
"math/rand"
"time"

. "github.com/cilium/checkmate"
Expand Down Expand Up @@ -44,9 +45,9 @@ func (g *GetNodesSuite) SetUpSuite(c *C) {
}

func (g *GetNodesSuite) Test_getNodesHandle(c *C) {
// Set seed so we can have the same pseudorandom client IDs.
// The seed is set to 0 for each unit test.
randGen.Seed(0)
// Create a PRNG source with a fixed seed so we can have the same pseudo-random client IDs
// for each test run.
randGen = rand.New(rand.NewSource(0))
const numberOfClients = 10

clientIDs := make([]int64, 0, numberOfClients)
Expand Down
10 changes: 3 additions & 7 deletions pkg/backoff/backoff.go
Expand Up @@ -7,21 +7,17 @@ import (
"context"
"fmt"
"math"
"math/rand"

"github.com/google/uuid"
"github.com/sirupsen/logrus"

"github.com/cilium/cilium/pkg/logging"
"github.com/cilium/cilium/pkg/logging/logfields"
"github.com/cilium/cilium/pkg/rand"
"github.com/cilium/cilium/pkg/time"
)

var (
log = logging.DefaultLogger.WithField(logfields.LogSubsys, "backoff")

randGen = rand.NewSafeRand(time.Now().UnixNano())
)
var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "backoff")

// NodeManager is the interface required to implement cluster size dependent
// intervals
Expand Down Expand Up @@ -98,7 +94,7 @@ func CalculateDuration(min, max time.Duration, factor float64, jitter bool, fail
}

if jitter {
t = randGen.Float64()*(t-minFloat) + minFloat
t = rand.Float64()*(t-minFloat) + minFloat
}

return time.Duration(t)
Expand Down
13 changes: 4 additions & 9 deletions pkg/ipam/service/allocator/bitmap.go
Expand Up @@ -7,10 +7,9 @@ package allocator
import (
"errors"
"math/big"
"math/rand"

"github.com/cilium/cilium/pkg/lock"
"github.com/cilium/cilium/pkg/rand"
"github.com/cilium/cilium/pkg/time"
)

// AllocationBitmap is a contiguous block of resources that can be allocated atomically.
Expand Down Expand Up @@ -50,9 +49,7 @@ type bitAllocator interface {
// NewAllocationMap creates an allocation bitmap using the random scan strategy.
func NewAllocationMap(max int, rangeSpec string) *AllocationBitmap {
a := AllocationBitmap{
strategy: randomScanStrategy{
rand: rand.NewSafeRand(time.Now().UnixNano()),
},
strategy: randomScanStrategy{},
allocated: big.NewInt(0),
count: 0,
max: max,
Expand Down Expand Up @@ -186,15 +183,13 @@ func (r *AllocationBitmap) Restore(rangeSpec string, data []byte) error {
// randomScanStrategy chooses a random address from the provided big.Int, and then
// scans forward looking for the next available address (it will wrap the range if
// necessary).
type randomScanStrategy struct {
rand *rand.SafeRand
}
type randomScanStrategy struct{}

func (rss randomScanStrategy) AllocateBit(allocated *big.Int, max, count int) (int, bool) {
if count >= max {
return 0, false
}
offset := rss.rand.Intn(max)
offset := rand.Intn(max)
for i := 0; i < max; i++ {
at := (offset + i) % max
if allocated.Bit(at) == 0 {
Expand Down
16 changes: 6 additions & 10 deletions pkg/kvstore/etcd.go
Expand Up @@ -9,6 +9,7 @@ import (
"crypto/tls"
"errors"
"fmt"
"math/rand"
"net/url"
"os"
"strconv"
Expand All @@ -32,7 +33,6 @@ import (
"github.com/cilium/cilium/pkg/inctimer"
"github.com/cilium/cilium/pkg/lock"
"github.com/cilium/cilium/pkg/option"
"github.com/cilium/cilium/pkg/rand"
ciliumrate "github.com/cilium/cilium/pkg/rate"
ciliumratemetrics "github.com/cilium/cilium/pkg/rate/metrics"
"github.com/cilium/cilium/pkg/spanstat"
Expand Down Expand Up @@ -63,13 +63,9 @@ const (
etcdMaxKeysPerLease = 1000
)

var (
// ErrLockLeaseExpired is an error whenever the lease of the lock does not
// exist or it was expired.
ErrLockLeaseExpired = errors.New("transaction did not succeed: lock lease expired")

randGen = rand.NewSafeRand(time.Now().UnixNano())
)
// ErrLockLeaseExpired is an error whenever the lease of the lock does not
// exist or it was expired.
var ErrLockLeaseExpired = errors.New("transaction did not succeed: lock lease expired")

type etcdModule struct {
opts backendOptions
Expand Down Expand Up @@ -181,7 +177,7 @@ func (e *etcdModule) getConfig() map[string]string {
}

func shuffleEndpoints(endpoints []string) {
randGen.Shuffle(len(endpoints), func(i, j int) {
rand.Shuffle(len(endpoints), func(i, j int) {
endpoints[i], endpoints[j] = endpoints[j], endpoints[i]
})
}
Expand Down Expand Up @@ -425,7 +421,7 @@ func (e *etcdClient) waitForInitLock(ctx context.Context) <-chan error {

// Generate a random number so that we can acquire a lock even
// if other agents are killed while locking this path.
randNumber := strconv.FormatUint(randGen.Uint64(), 16)
randNumber := strconv.FormatUint(rand.Uint64(), 16)
locker, err := e.LockPath(ctx, InitLockPath+"/"+randNumber)
if err == nil {
locker.Unlock(context.Background())
Expand Down
4 changes: 0 additions & 4 deletions pkg/lock/stoppable_waitgroup_test.go
Expand Up @@ -154,10 +154,6 @@ func (s *SemaphoredMutexSuite) TestWaitChannel(c *C) {
func (s *SemaphoredMutexSuite) TestParallelism(c *C) {
l := NewStoppableWaitGroup()

// Use math/rand instead of pkg/rand to avoid a test import cycle which
// go vet would complain about. Use the global default entropy source
// rather than creating a new source to avoid concurrency issues.
rand.Seed(time.Now().UnixNano())
in := make(chan int)
stop := make(chan struct{})
go func() {
Expand Down
5 changes: 2 additions & 3 deletions pkg/node/manager/manager.go
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"net"
"net/netip"

Expand Down Expand Up @@ -35,13 +36,11 @@ import (
"github.com/cilium/cilium/pkg/node/addressing"
nodeTypes "github.com/cilium/cilium/pkg/node/types"
"github.com/cilium/cilium/pkg/option"
"github.com/cilium/cilium/pkg/rand"
"github.com/cilium/cilium/pkg/source"
"github.com/cilium/cilium/pkg/time"
)

var (
randGen = rand.NewSafeRand(time.Now().UnixNano())
baseBackgroundSyncInterval = time.Minute

neighborTableRefreshControllerGroup = controller.NewGroup("neighbor-table-refresh")
Expand Down Expand Up @@ -836,7 +835,7 @@ func (m *manager) StartNeighborRefresh(nh datapath.NodeNeighbors) {
// To avoid flooding network with arping requests
// at the same time, spread them over the
// [0; ARPPingRefreshPeriod/2) period.
n := randGen.Int63n(int64(option.Config.ARPPingRefreshPeriod / 2))
n := rand.Int63n(int64(option.Config.ARPPingRefreshPeriod / 2))
time.Sleep(time.Duration(n))
nh.NodeNeighborRefresh(c, e)
}(ctx, entryNode)
Expand Down
10 changes: 3 additions & 7 deletions pkg/proxy/proxy.go
Expand Up @@ -6,6 +6,7 @@ package proxy
import (
"context"
"fmt"
"math/rand"
"net"

"github.com/sirupsen/logrus"
Expand All @@ -25,16 +26,11 @@ import (
"github.com/cilium/cilium/pkg/policy"
"github.com/cilium/cilium/pkg/proxy/endpoint"
"github.com/cilium/cilium/pkg/proxy/types"
"github.com/cilium/cilium/pkg/rand"
"github.com/cilium/cilium/pkg/revert"
"github.com/cilium/cilium/pkg/time"
)

var (
log = logging.DefaultLogger.WithField(logfields.LogSubsys, "proxy")

portRandomizer = rand.NewSafeRand(time.Now().UnixNano())
)
var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "proxy")

// field names used while logging
const (
Expand Down Expand Up @@ -201,7 +197,7 @@ func (p *Proxy) allocatePort(port, min, max uint16) (uint16, error) {
}

// TODO: Maybe not create a large permutation each time?
portRange := portRandomizer.Perm(int(max - min + 1))
portRange := rand.Perm(int(max - min + 1))

// Allow reuse of previously used ports only if no ports are otherwise availeble.
// This allows the same port to be used again by a listener being reconfigured
Expand Down
87 changes: 0 additions & 87 deletions pkg/rand/safe_rand.go

This file was deleted.

0 comments on commit b973bf5

Please sign in to comment.