151 lines
2.8 KiB
Go
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
|
|
}
|