cri-o/lib/sandbox/sandbox_linux.go
Vincent Batts fb87c2f68b *: abstract out netns for multiple platforms
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
2018-03-08 11:56:32 -05:00

151 lines
2.8 KiB
Go

// +build linux
package sandbox
import (
"crypto/rand"
"fmt"
"os"
"path/filepath"
"sync"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/symlink"
"golang.org/x/sys/unix"
)
func isNSorErr(nspath string) error {
return ns.IsNSorErr(nspath)
}
func newNetNs() (*NetNs, error) {
netNS, err := ns.NewNS()
if err != nil {
return nil, err
}
return &NetNs{nn: netNS, closed: false}, nil
}
func getNetNs(path string) (*NetNs, error) {
return &NetNs{}, nil
netNS, err := ns.GetNS(path)
if err != nil {
return nil, err
}
return &NetNs{nn: netNS, closed: false, restored: true}, nil
}
// NetNs handles data pertaining a network namespace
type NetNs struct {
sync.Mutex
nn ns.NetNS
symlink *os.File
closed bool
restored bool
}
func (nns *NetNs) Path() string {
return nns.nn.Path()
}
func (nns *NetNs) Close() error {
return nns.nn.Close()
}
func (nns *NetNs) Remove() error {
nns.Lock()
defer nns.Unlock()
if nns.closed {
// netNsRemove() can be called multiple
// times without returning an error.
return nil
}
if err := nns.symlinkRemove(); err != nil {
return err
}
if err := nns.Close(); err != nil {
return err
}
nns.closed = true
if nns.restored {
// we got namespaces in the form of
// /var/run/netns/cni-0d08effa-06eb-a963-f51a-e2b0eceffc5d
// but /var/run on most system is symlinked to /run so we first resolve
// the symlink and then try and see if it's mounted
fp, err := symlink.FollowSymlinkInScope(nns.Path(), "/")
if err != nil {
return err
}
if mounted, err := mount.Mounted(fp); err == nil && mounted {
if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil {
return err
}
}
if nns.Path() != "" {
if err := os.RemoveAll(nns.Path()); err != nil {
return err
}
}
}
return nil
}
func (nns *NetNs) 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(nns.nn.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
}
nns.symlink = fd
return nil
}
func (nns *NetNs) symlinkRemove() error {
if err := nns.symlink.Close(); err != nil {
return fmt.Errorf("failed to close net ns symlink: %v", err)
}
if err := os.RemoveAll(nns.symlink.Name()); err != nil {
return fmt.Errorf("failed to remove net ns symlink: %v", err)
}
return nil
}
func hostNetNsPath() (string, error) {
netNS, err := ns.GetCurrentNS()
if err != nil {
return "", err
}
defer netNS.Close()
return netNS.Path(), nil
}