pkg/ns: consider PROCFS during NS verification
authorStefan Junker <mail@stefanjunker.de>
Wed, 25 May 2016 21:49:25 +0000 (23:49 +0200)
committerStefan Junker <mail@stefanjunker.de>
Thu, 26 May 2016 10:42:50 +0000 (12:42 +0200)
This is an attempt to bring compatibility with Kernel <3.19, where NSFS
where PROCFS was used for network namespaces.

pkg/ns/ns.go
pkg/ns/ns_test.go

index 328fff3..a03ee1e 100644 (file)
@@ -20,6 +20,7 @@ import (
        "os"
        "path"
        "runtime"
+       "strings"
        "sync"
        "syscall"
 
@@ -74,36 +75,56 @@ func GetCurrentNS() (NetNS, error) {
        return GetNS(getCurrentThreadNetNSPath())
 }
 
-// Returns an object representing the namespace referred to by @path
-func GetNS(nspath string) (NetNS, error) {
-       fd, err := os.Open(nspath)
-       if err != nil {
-               return nil, fmt.Errorf("Failed to open %v: %v", nspath, err)
+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
+}
 
-       isNSFS, err := IsNSFS(nspath)
+// Returns an object representing the namespace referred to by @path
+func GetNS(nspath string) (NetNS, error) {
+       isNS, msg, err := IsNS(nspath)
        if err != nil {
-               fd.Close()
                return nil, err
        }
-       if !isNSFS {
-               fd.Close()
-               return nil, fmt.Errorf("%v is not of type NSFS", nspath)
+       if !isNS {
+               return nil, fmt.Errorf("no network namespace detected on %s: %s", nspath, msg)
        }
 
-       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)
+       fd, err := os.Open(nspath)
+       if err != nil {
+               return nil, fmt.Errorf("Failed to open %v: %v", nspath, err)
        }
 
-       return stat.Type == NSFS_MAGIC, nil
+       return &netNS{file: fd}, nil
 }
 
 // Creates a new persistent network namespace and returns an object
index 82001ea..5b0b587 100644 (file)
@@ -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))
                })