diff --git a/nshandle_linux.go b/nshandle_linux.go index 1baffb6..c6b3c83 100644 --- a/nshandle_linux.go +++ b/nshandle_linux.go @@ -2,6 +2,8 @@ package netns import ( "fmt" + "os" + "path/filepath" "golang.org/x/sys/unix" ) @@ -27,6 +29,42 @@ func (ns NsHandle) Equal(other NsHandle) bool { return (s1.Dev == s2.Dev) && (s1.Ino == s2.Ino) } +// Name returns the name of the network namespace associated with the +// handle. +func (ns NsHandle) Name() (string, error) { + if ns == -1 { + return "", nil + } + + var target unix.Stat_t + if err := unix.Fstat(int(ns), &target); err != nil { + return "", err + } + + // Loop through all the named network namespaces to find the target + entries, err := os.ReadDir(bindMountPath) + if err != nil { + return "", err + } + + for _, entry := range entries { + name := entry.Name() + path := filepath.Join(bindMountPath, name) + + var stat unix.Stat_t + if err := unix.Stat(path, &stat); err != nil { + continue + } + + if stat.Dev == target.Dev && stat.Ino == target.Ino { + return name, nil + } + } + + // The target ns doesn't have a name + return "", nil +} + // String shows the file descriptor number and its dev and inode. func (ns NsHandle) String() string { if ns == -1 { diff --git a/nshandle_linux_test.go b/nshandle_linux_test.go new file mode 100644 index 0000000..9c9d3d0 --- /dev/null +++ b/nshandle_linux_test.go @@ -0,0 +1,35 @@ +package netns_test + +import ( + "testing" + + "github.com/vishvananda/netns" +) + +func TestNsHandle_Name(t *testing.T) { + const expectedName = "some-ns-no-one-will-ever-use" + + // Create a new network namespace + ns, err := netns.NewNamed(expectedName) + if err != nil { + t.Fatalf("Failed to create network namespace: %v", err) + } + + t.Cleanup(func() { + if err := ns.Close(); err != nil { + t.Fatalf("Failed to close network namespace: %v", err) + } + if err := netns.DeleteNamed(expectedName); err != nil { + t.Fatalf("Failed to delete network namespace: %v", err) + } + }) + + // Get the name of the network namespace + name, err := ns.Name() + if err != nil { + t.Fatalf("Failed to get network namespace name: %v", err) + } + if name != expectedName { + t.Fatalf("Expected name %q, got %q", expectedName, name) + } +} diff --git a/nshandle_others.go b/nshandle_others.go index af727bc..db81df2 100644 --- a/nshandle_others.go +++ b/nshandle_others.go @@ -13,6 +13,12 @@ func (ns NsHandle) Equal(_ NsHandle) bool { return false } +// Name returns the name of the network namespace associated with the +// handle. It is only implemented on Linux. +func (ns NsHandle) Name() (string, error) { + return "", nil +} + // String shows the file descriptor number and its dev and inode. // It is only implemented on Linux, and returns "NS(none)" on other // platforms.