mirror of
https://github.com/moby/moby.git
synced 2026-08-03 22:51:03 +00:00
daemon/libnetwork/ns: use sync.OnceValues
This avoids depending on global state in the package, and "forces" consumers to go through the initHandles() func to get the handles. A slight change in behavior is that `ResetHandles()` may now initialize a new namespace only to reset it, but this is likely an "OK" trade-off. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -14,48 +14,55 @@ import (
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
var (
|
||||
initNs = netns.None()
|
||||
initNl nlwrap.Handle
|
||||
initOnce sync.Once
|
||||
// NetlinkSocketsTimeout represents the default timeout duration for the sockets
|
||||
NetlinkSocketsTimeout = 3 * time.Second
|
||||
)
|
||||
// NetlinkSocketsTimeout represents the default timeout duration for the sockets.
|
||||
var NetlinkSocketsTimeout = 3 * time.Second
|
||||
|
||||
// initNamespace initializes a new network namespace.
|
||||
var initNamespace = sync.OnceValues(initHandles)
|
||||
|
||||
// initHandles initializes a new network namespace
|
||||
func initHandles() {
|
||||
var err error
|
||||
initNs, err = netns.Get()
|
||||
func initHandles() (netns.NsHandle, nlwrap.Handle) {
|
||||
initNs, err := netns.Get()
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Errorf("could not get initial namespace: %v", err)
|
||||
log.G(context.Background()).WithError(err).Error("could not get initial namespace: falling back to using netns.None")
|
||||
initNs = netns.None()
|
||||
}
|
||||
initNl, err = nlwrap.NewHandle(getSupportedNlFamilies()...)
|
||||
initNl, err := nlwrap.NewHandle(getSupportedNlFamilies()...)
|
||||
if err != nil {
|
||||
// Fail fast to keep the invariant: NlHandle must be a valid handle
|
||||
panic(fmt.Errorf("could not create netlink handle on initial (host) namespace: %w", err))
|
||||
}
|
||||
err = initNl.SetSocketTimeout(NetlinkSocketsTimeout)
|
||||
if err != nil {
|
||||
log.G(context.TODO()).Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err)
|
||||
log.G(context.Background()).WithError(err).Warn("failed to set the timeout on the default netlink handle sockets")
|
||||
}
|
||||
|
||||
return initNs, initNl
|
||||
}
|
||||
|
||||
// ResetHandles resets the initial namespace and netlink handles.
|
||||
// This is useful for testing to ensure a clean state. It will
|
||||
// panic if called outside a test.
|
||||
//
|
||||
// Note: This function is not safe for concurrent use with callers
|
||||
// that are using handles obtained from this package. It may close
|
||||
// handles while they are still in use.
|
||||
func ResetHandles() {
|
||||
if !testing.Testing() {
|
||||
panic("ResetHandles should only be called from tests")
|
||||
}
|
||||
initNs, initNl := initNamespace()
|
||||
// Reset the initNamespace sync.OnceValues. This may race with
|
||||
// concurrent callers still calling the old initNamespace (and
|
||||
// values), but adding a [sync.RWMutex] only for the test-case
|
||||
// is probably too much (unless things are racy).
|
||||
initNamespace = sync.OnceValues(initHandles)
|
||||
if initNs.IsOpen() {
|
||||
_ = initNs.Close()
|
||||
initNs = netns.None()
|
||||
}
|
||||
if initNl.Handle != nil {
|
||||
initNl.Close()
|
||||
initNl = nlwrap.Handle{}
|
||||
}
|
||||
initOnce = sync.Once{}
|
||||
}
|
||||
|
||||
// ParseHandlerInt transforms the namespace handler into an integer
|
||||
@@ -65,14 +72,14 @@ func ParseHandlerInt() int {
|
||||
|
||||
// GetHandler returns the namespace handler
|
||||
func getHandler() netns.NsHandle {
|
||||
initOnce.Do(initHandles)
|
||||
return initNs
|
||||
ns, _ := initNamespace()
|
||||
return ns
|
||||
}
|
||||
|
||||
// NlHandle returns the netlink handler
|
||||
func NlHandle() nlwrap.Handle {
|
||||
initOnce.Do(initHandles)
|
||||
return initNl
|
||||
_, nl := initNamespace()
|
||||
return nl
|
||||
}
|
||||
|
||||
func getSupportedNlFamilies() []int {
|
||||
|
||||
Reference in New Issue
Block a user