libnetwork: check for netns leaks from prior tests
TestProxyNXDOMAIN has proven to be susceptible to failing as a
consequence of unlocked threads being set to the wrong network
namespace. As the failure mode looks a lot like a bug in the test
itself, it seems prudent to add a check for mismatched namespaces to the
test so we will know for next time that the root cause lies elsewhere.
Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 871cf72363
)
Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
992dc33fc5
commit
baf1fd1c3f
3 changed files with 61 additions and 0 deletions
|
@ -494,6 +494,13 @@ func TestProxyNXDOMAIN(t *testing.T) {
|
|||
<-serveDone
|
||||
}()
|
||||
|
||||
// This test, by virtue of running a server and client in different
|
||||
// not-locked-to-thread goroutines, happens to be a good canary for
|
||||
// whether we are leaking unlocked OS threads set to the wrong network
|
||||
// namespace. Make a best-effort attempt to detect that situation so we
|
||||
// are not left chasing ghosts next time.
|
||||
testutils.AssertSocketSameNetNS(t, srv.PacketConn.(*net.UDPConn))
|
||||
|
||||
srvAddr := srv.PacketConn.LocalAddr().(*net.UDPAddr)
|
||||
rsv := NewResolver("", true, noopDNSBackend{})
|
||||
rsv.SetExtServers([]extDNSEntry{
|
||||
|
|
43
libnetwork/testutils/sanity_linux.go
Normal file
43
libnetwork/testutils/sanity_linux.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package testutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/vishvananda/netns"
|
||||
"golang.org/x/sys/unix"
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
// AssertSocketSameNetNS makes a best-effort attempt to assert that conn is in
|
||||
// the same network namespace as the current goroutine's thread.
|
||||
func AssertSocketSameNetNS(t testing.TB, conn syscall.Conn) {
|
||||
t.Helper()
|
||||
|
||||
sc, err := conn.SyscallConn()
|
||||
assert.NilError(t, err)
|
||||
sc.Control(func(fd uintptr) {
|
||||
srvnsfd, err := unix.IoctlRetInt(int(fd), unix.SIOCGSKNS)
|
||||
if err != nil {
|
||||
if errors.Is(err, unix.EPERM) {
|
||||
t.Log("Cannot determine socket's network namespace. Do we have CAP_NET_ADMIN?")
|
||||
return
|
||||
}
|
||||
if errors.Is(err, unix.ENOSYS) {
|
||||
t.Log("Cannot query socket's network namespace due to missing kernel support.")
|
||||
return
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
srvns := netns.NsHandle(srvnsfd)
|
||||
defer srvns.Close()
|
||||
|
||||
curns, err := netns.Get()
|
||||
assert.NilError(t, err)
|
||||
defer curns.Close()
|
||||
if !srvns.Equal(curns) {
|
||||
t.Fatalf("Socket is in network namespace %s, but test goroutine is in %s", srvns, curns)
|
||||
}
|
||||
})
|
||||
}
|
11
libnetwork/testutils/sanity_notlinux.go
Normal file
11
libnetwork/testutils/sanity_notlinux.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
//go:build !linux
|
||||
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// AssertSocketSameNetNS is a no-op on platforms other than Linux.
|
||||
func AssertSocketSameNetNS(t testing.TB, conn syscall.Conn) {}
|
Loading…
Reference in a new issue