Skip to content

Commit

Permalink
sandbox: Create a symbolic link to the networking namespace
Browse files Browse the repository at this point in the history
In order to workaround a bug introduced with runc commit bc84f833,
we create a symbolic link to our permanent networking namespace so
that runC realizes that this is not the host namespace.

Although this bug is now fixed upstream (See commit f33de5ab4), this
patch works with pre rc3 runC versions.
We may want to revert that patch once runC 1.0.0 is released.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Samuel Ortiz committed Dec 12, 2016
1 parent 8dfcccd commit 28e08d3
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 10 deletions.
107 changes: 101 additions & 6 deletions server/sandbox.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package server

import (
"crypto/rand"
"errors"
"fmt"
"os"
"path/filepath"
"sync"

"github.com/Sirupsen/logrus"
Expand All @@ -15,21 +18,98 @@ import (

type sandboxNetNs struct {
sync.Mutex
ns ns.NetNS
closed bool
ns ns.NetNS
symlink *os.File
closed bool
}

func netNsGet(nspath string) (*sandboxNetNs, error) {
func (ns *sandboxNetNs) symlinkCreate(name string) error {
b := make([]byte, 4)
_, randErr := rand.Reader.Read(b)
if randErr != nil {
return randErr
}

nsName := fmt.Sprintf("%s-%x", name, b)
symlinkPath := filepath.Join(nsRunDir, nsName)

if err := os.Symlink(ns.ns.Path(), symlinkPath); err != nil {
return err
}

fd, err := os.Open(symlinkPath)
if err != nil {
if removeErr := os.RemoveAll(symlinkPath); removeErr != nil {
return removeErr
}

return err
}

ns.symlink = fd

return nil
}

func (ns *sandboxNetNs) symlinkRemove() error {
if err := ns.symlink.Close(); err != nil {
return err
}

return os.RemoveAll(ns.symlink.Name())
}

func isSymbolicLink(path string) (bool, error) {
fi, err := os.Lstat(path)
if err != nil {
return false, err
}

return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil
}

func netNsGet(nspath, name string) (*sandboxNetNs, error) {
if err := ns.IsNSorErr(nspath); err != nil {
return nil, errSandboxClosedNetNS
}

netNS, err := ns.GetNS(nspath)
symlink, symlinkErr := isSymbolicLink(nspath)
if symlinkErr != nil {
return nil, symlinkErr
}

var resolvedNsPath string
if symlink {
path, err := os.Readlink(nspath)
if err != nil {
return nil, err
}
resolvedNsPath = path
} else {
resolvedNsPath = nspath
}

netNS, err := ns.GetNS(resolvedNsPath)
if err != nil {
return nil, err
}

return &sandboxNetNs{ns: netNS, closed: false,}, nil
netNs := &sandboxNetNs{ns: netNS, closed: false,}

if symlink {
fd, err := os.Open(nspath)
if err != nil {
return nil, err
}

netNs.symlink = fd
} else {
if err := netNs.symlinkCreate(name); err != nil {
return nil, err
}
}

return netNs, nil
}

func hostNetNsPath() (string, error) {
Expand Down Expand Up @@ -61,6 +141,7 @@ type sandbox struct {
const (
podDefaultNamespace = "default"
defaultShmSize = 64 * 1024 * 1024
nsRunDir = "/var/run/netns"
)

var (
Expand Down Expand Up @@ -93,7 +174,7 @@ func (s *sandbox) netNsPath() string {
return ""
}

return s.netns.ns.Path()
return s.netns.symlink.Name()
}

func (s *sandbox) netNsCreate() error {
Expand All @@ -111,6 +192,16 @@ func (s *sandbox) netNsCreate() error {
closed: false,
}

if err := s.netns.symlinkCreate(s.name); err != nil {
logrus.Warnf("Could not create nentns symlink %v", err)

if err := s.netns.ns.Close(); err != nil {
return err
}

return err
}

return nil
}

Expand All @@ -129,6 +220,10 @@ func (s *sandbox) netNsRemove() error {
return nil
}

if err := s.netns.symlinkRemove(); err != nil {
return err
}

if err := s.netns.ns.Close(); err != nil {
return err
}
Expand Down
7 changes: 4 additions & 3 deletions server/sandbox_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ func (s *Server) RemovePodSandbox(ctx context.Context, req *pb.RemovePodSandboxR
}
}

if err := sb.netNsRemove(); err != nil {
return nil, fmt.Errorf("failed to remove networking namespace for sandbox %s: %v", sb.id, err)
}

// Remove the files related to the sandbox
podSandboxDir := filepath.Join(s.config.SandboxDir, sb.id)
if err := os.RemoveAll(podSandboxDir); err != nil {
return nil, fmt.Errorf("failed to remove sandbox %s directory: %v", sb.id, err)
}
if err := sb.netNsRemove(); err != nil {
return nil, fmt.Errorf("failed to remove networking namespace for sandbox %s: %v", sb.id, err)
}
s.releaseContainerName(podInfraContainer.Name())
s.removeContainer(podInfraContainer)
sb.infraContainer = nil
Expand Down
2 changes: 1 addition & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func (s *Server) loadSandbox(id string) error {
// Otherwise, the sandbox will live in the host namespace.
netNsPath, err := configNetNsPath(m)
if err == nil {
netNS, nsErr := netNsGet(netNsPath)
netNS, nsErr := netNsGet(netNsPath, sb.name)
// If we can't load the networking namespace
// because it's closed, we just set the sb netns
// pointer to nil. Otherwise we return an error.
Expand Down

0 comments on commit 28e08d3

Please sign in to comment.