From 2d47b0396d4b9d6483461ef93b665427f083c33d Mon Sep 17 00:00:00 2001 From: Stefan Junker Date: Wed, 25 May 2016 23:49:25 +0200 Subject: [PATCH] pkg/ns: consider PROCFS during NS verification This is an attempt to bring compatibility with Kernel <3.19, where NSFS where PROCFS was used for network namespaces. --- ns/ns.go | 65 ++++++++++++++++++++++++++++++++++----------------- ns/ns_test.go | 11 +++++---- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/ns/ns.go b/ns/ns.go index 328fff34..a03ee1e0 100644 --- a/ns/ns.go +++ b/ns/ns.go @@ -20,6 +20,7 @@ import ( "os" "path" "runtime" + "strings" "sync" "syscall" @@ -74,38 +75,58 @@ func GetCurrentNS() (NetNS, error) { return GetNS(getCurrentThreadNetNSPath()) } +const ( + // https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h + NSFS_MAGIC = 0x6e736673 + PROCFS_MAGIC = 0x9fa0 +) + +func IsNS(nspath string) (isNS bool, msg string, err error) { + stat := syscall.Statfs_t{} + if err = syscall.Statfs(nspath, &stat); err != nil { + err = fmt.Errorf("failed to Statfs %s: %v", nspath, err) + return + } + + switch stat.Type { + case PROCFS_MAGIC: + // Kernel < 3.19 + + validPathContent := "ns/" + validName := strings.Contains(nspath, validPathContent) + if !validName { + msg = fmt.Sprintf("path doesn't contain %q", validPathContent) + return + } + isNS = true + case NSFS_MAGIC: + // Kernel >= 3.19 + + isNS = true + default: + msg = fmt.Sprintf("unknown FS magic: %x", stat.Type) + } + return +} + // Returns an object representing the namespace referred to by @path func GetNS(nspath string) (NetNS, error) { + isNS, msg, err := IsNS(nspath) + if err != nil { + return nil, err + } + if !isNS { + return nil, fmt.Errorf("no network namespace detected on %s: %s", nspath, msg) + } + fd, err := os.Open(nspath) if err != nil { return nil, fmt.Errorf("Failed to open %v: %v", nspath, err) } - isNSFS, err := IsNSFS(nspath) - if err != nil { - fd.Close() - return nil, err - } - if !isNSFS { - fd.Close() - return nil, fmt.Errorf("%v is not of type NSFS", nspath) - } - return &netNS{file: fd}, nil } -// Returns whether or not the nspath argument points to a network namespace -func IsNSFS(nspath string) (bool, error) { - const NSFS_MAGIC = 0x6e736673 - - stat := syscall.Statfs_t{} - if err := syscall.Statfs(nspath, &stat); err != nil { - return false, fmt.Errorf("failed to Statfs %q: %v", nspath, err) - } - - return stat.Type == NSFS_MAGIC, nil -} - // Creates a new persistent network namespace and returns an object // representing that namespace, without switching to it func NewNS() (NetNS, error) { diff --git a/ns/ns_test.go b/ns/ns_test.go index 82001ea0..5b0b587d 100644 --- a/ns/ns_test.go +++ b/ns/ns_test.go @@ -180,7 +180,9 @@ var _ = Describe("Linux namespace operations", func() { defer os.Remove(nspath) _, err = ns.GetNS(nspath) - Expect(err).To(MatchError(fmt.Sprintf("%v is not of type NSFS", nspath))) + Expect(err).To(HaveOccurred()) + errString := fmt.Sprintf("%v", err) + Expect(errString).To(HavePrefix("no network namespace detected on %s", nspath)) }) }) @@ -212,11 +214,12 @@ var _ = Describe("Linux namespace operations", func() { }) }) - Describe("IsNSFS", func() { + Describe("IsNS", func() { It("should detect a namespace", func() { createdNetNS, err := ns.NewNS() - isNSFS, err := ns.IsNSFS(createdNetNS.Path()) + isNSFS, msg, err := ns.IsNS(createdNetNS.Path()) Expect(err).NotTo(HaveOccurred()) + Expect(msg).To(Equal("")) Expect(isNSFS).To(Equal(true)) }) @@ -228,7 +231,7 @@ var _ = Describe("Linux namespace operations", func() { nspath := tempFile.Name() defer os.Remove(nspath) - isNSFS, err := ns.IsNSFS(nspath) + isNSFS, _, err := ns.IsNS(nspath) Expect(err).NotTo(HaveOccurred()) Expect(isNSFS).To(Equal(false)) })