mirror of
https://github.com/containers/podman.git
synced 2025-06-20 17:13:43 +08:00
rootless cni without infra container
Instead of creating an extra container create a network and mount namespace inside the podman user namespace. This ns is used to for rootless cni operations. This helps to align the rootless and rootful network code path. If we run as rootless we just have to set up a extra net ns and initialize slirp4netns in it. The ocicni lib will be called in that net ns. This design allows allows easier maintenance, no extra container with pause processes, support for rootless cni with --uidmap and possibly more. The biggest problem is backwards compatibility. I don't think live migration can be possible. If the user reboots or restart all cni containers everything should work as expected again. The user is left with the rootless-cni-infa container and image but this can safely be removed. To make the existing cni configs work we need execute the cni plugins in a extra mount namespace. This ensures that we can safely mount over /run and /var which have to be writeable for the cni plugins without removing access to these files by the main podman process. One caveat is that we need to keep the netns files at `XDG_RUNTIME_DIR/netns` accessible. `XDG_RUNTIME_DIR/rootless-cni/{run,var}` will be mounted to `/{run,var}`. To ensure that we keep the netns directory we bind mount this relative to the new root location, e.g. XDG_RUNTIME_DIR/rootless-cni/run/user/1000/netns before we mount the run directory. The run directory is mounted recursive, this makes the netns directory at the same path accessible as before. This also allows iptables-legacy to work because /run/xtables.lock is now writeable. Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
This commit is contained in:
@ -92,11 +92,7 @@ func (c *Container) prepare() error {
|
|||||||
// Set up network namespace if not already set up
|
// Set up network namespace if not already set up
|
||||||
noNetNS := c.state.NetNS == nil
|
noNetNS := c.state.NetNS == nil
|
||||||
if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
|
if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
|
||||||
if rootless.IsRootless() && len(c.config.Networks) > 0 {
|
|
||||||
netNS, networkStatus, createNetNSErr = AllocRootlessCNI(context.Background(), c)
|
|
||||||
} else {
|
|
||||||
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
|
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
|
||||||
}
|
|
||||||
if createNetNSErr != nil {
|
if createNetNSErr != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/containernetworking/cni/pkg/version"
|
"github.com/containernetworking/cni/pkg/version"
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/podman/v3/pkg/domain/entities"
|
"github.com/containers/podman/v3/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v3/pkg/rootless"
|
|
||||||
"github.com/containers/podman/v3/pkg/util"
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -223,9 +222,8 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon
|
|||||||
plugins = append(plugins, NewPortMapPlugin())
|
plugins = append(plugins, NewPortMapPlugin())
|
||||||
plugins = append(plugins, NewFirewallPlugin())
|
plugins = append(plugins, NewFirewallPlugin())
|
||||||
plugins = append(plugins, NewTuningPlugin())
|
plugins = append(plugins, NewTuningPlugin())
|
||||||
// if we find the dnsname plugin or are rootless, we add configuration for it
|
// if we find the dnsname plugin we add configuration for it
|
||||||
// the rootless-cni-infra container has the dnsname plugin always installed
|
if HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) && !options.DisableDNS {
|
||||||
if (HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) || rootless.IsRootless()) && !options.DisableDNS {
|
|
||||||
if options.Internal {
|
if options.Internal {
|
||||||
logrus.Warnf("dnsname and --internal networks are incompatible. dnsname plugin not configured for network %s", name)
|
logrus.Warnf("dnsname and --internal networks are incompatible. dnsname plugin not configured for network %s", name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,7 +4,6 @@ package libpod
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -29,7 +28,9 @@ import (
|
|||||||
"github.com/containers/podman/v3/pkg/netns"
|
"github.com/containers/podman/v3/pkg/netns"
|
||||||
"github.com/containers/podman/v3/pkg/rootless"
|
"github.com/containers/podman/v3/pkg/rootless"
|
||||||
"github.com/containers/podman/v3/pkg/rootlessport"
|
"github.com/containers/podman/v3/pkg/rootlessport"
|
||||||
|
"github.com/containers/podman/v3/pkg/util"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
@ -46,6 +47,9 @@ const (
|
|||||||
|
|
||||||
// slirp4netnsMTU the default MTU override
|
// slirp4netnsMTU the default MTU override
|
||||||
slirp4netnsMTU = 65520
|
slirp4netnsMTU = 65520
|
||||||
|
|
||||||
|
// rootlessCNINSName is the file name for the rootless network namespace bind mount
|
||||||
|
rootlessCNINSName = "rootless-cni-ns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get an OCICNI network config
|
// Get an OCICNI network config
|
||||||
@ -102,8 +106,222 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
|
|||||||
return ctrNetwork
|
return ctrNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rootlessCNI struct {
|
||||||
|
ns ns.NetNS
|
||||||
|
dir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rootlessCNI) Do(toRun func() error) error {
|
||||||
|
err := r.ns.Do(func(_ ns.NetNS) error {
|
||||||
|
// before we can run the given function
|
||||||
|
// we have to setup all mounts correctly
|
||||||
|
|
||||||
|
// create a new mount namespace
|
||||||
|
// this should happen inside the netns thread
|
||||||
|
err := unix.Unshare(unix.CLONE_NEWNS)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot create a new mount namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
netNsDir, err := netns.GetNSRunDir()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "could not get network namespace directory")
|
||||||
|
}
|
||||||
|
newNetNsDir := filepath.Join(r.dir, netNsDir)
|
||||||
|
// mount the netns into the new run to keep them accessible
|
||||||
|
// otherwise cni setup will fail because it cannot access the netns files
|
||||||
|
err = unix.Mount(netNsDir, newNetNsDir, "none", unix.MS_BIND|unix.MS_SHARED|unix.MS_REC, "")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to mount netns directory for rootless cni")
|
||||||
|
}
|
||||||
|
|
||||||
|
// also keep /run/systemd if it exists
|
||||||
|
// many files are symlinked into this dir, for example systemd-resolved links
|
||||||
|
// /etc/resolv.conf but the dnsname plugin needs access to this file
|
||||||
|
runSystemd := "/run/systemd"
|
||||||
|
_, err = os.Stat(runSystemd)
|
||||||
|
if err == nil {
|
||||||
|
newRunSystemd := filepath.Join(r.dir, runSystemd[1:])
|
||||||
|
err = unix.Mount(runSystemd, newRunSystemd, "none", unix.MS_BIND|unix.MS_REC, "")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to mount /run/systemd directory for rootless cni")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cni plugins need access to /var and /run
|
||||||
|
runDir := filepath.Join(r.dir, "run")
|
||||||
|
varDir := filepath.Join(r.dir, "var")
|
||||||
|
// make sure to mount var first
|
||||||
|
err = unix.Mount(varDir, "/var", "none", unix.MS_BIND, "")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to mount /var for rootless cni")
|
||||||
|
}
|
||||||
|
// recursive mount to keep the netns mount
|
||||||
|
err = unix.Mount(runDir, "/run", "none", unix.MS_BIND|unix.MS_REC, "")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to mount /run for rootless cni")
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the given function in the correct namespace
|
||||||
|
err = toRun()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRootlessCNINetNs returns the rootless cni object. If create is set to true
|
||||||
|
// the rootless cni namespace will be created if it does not exists already.
|
||||||
|
func (r *Runtime) getRootlessCNINetNs(new bool) (*rootlessCNI, error) {
|
||||||
|
var rootlessCNINS *rootlessCNI
|
||||||
|
if rootless.IsRootless() {
|
||||||
|
runDir, err := util.GetRuntimeDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cniDir := filepath.Join(runDir, "rootless-cni")
|
||||||
|
|
||||||
|
nsDir, err := netns.GetNSRunDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
path := filepath.Join(nsDir, rootlessCNINSName)
|
||||||
|
ns, err := ns.GetNS(path)
|
||||||
|
if err != nil {
|
||||||
|
if new {
|
||||||
|
// create a new namespace
|
||||||
|
logrus.Debug("creating rootless cni network namespace")
|
||||||
|
ns, err = netns.NewNSWithName(rootlessCNINSName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error creating rootless cni network namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup slirp4netns here
|
||||||
|
path := r.config.Engine.NetworkCmdPath
|
||||||
|
if path == "" {
|
||||||
|
var err error
|
||||||
|
path, err = exec.LookPath("slirp4netns")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncR, syncW, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to open pipe")
|
||||||
|
}
|
||||||
|
defer errorhandling.CloseQuiet(syncR)
|
||||||
|
defer errorhandling.CloseQuiet(syncW)
|
||||||
|
|
||||||
|
netOptions, err := parseSlirp4netnsNetworkOptions(r, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
slirpFeatures, err := checkSlirpFlags(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error checking slirp4netns binary %s: %q", path, err)
|
||||||
|
}
|
||||||
|
cmdArgs, err := createBasicSlirp4netnsCmdArgs(netOptions, slirpFeatures)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// the slirp4netns arguments being passed are describes as follows:
|
||||||
|
// from the slirp4netns documentation: https://github.com/rootless-containers/slirp4netns
|
||||||
|
// -c, --configure Brings up the tap interface
|
||||||
|
// -e, --exit-fd=FD specify the FD for terminating slirp4netns
|
||||||
|
// -r, --ready-fd=FD specify the FD to write to when the initialization steps are finished
|
||||||
|
cmdArgs = append(cmdArgs, "-c", "-r", "3")
|
||||||
|
cmdArgs = append(cmdArgs, "--netns-type=path", ns.Path(), "tap0")
|
||||||
|
|
||||||
|
cmd := exec.Command(path, cmdArgs...)
|
||||||
|
logrus.Debugf("slirp4netns command: %s", strings.Join(cmd.Args, " "))
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Setpgid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround for https://github.com/rootless-containers/slirp4netns/pull/153
|
||||||
|
if !netOptions.noPivotRoot && slirpFeatures.HasEnableSandbox {
|
||||||
|
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
|
||||||
|
cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leak one end of the pipe in slirp4netns
|
||||||
|
cmd.ExtraFiles = append(cmd.ExtraFiles, syncW)
|
||||||
|
|
||||||
|
logPath := filepath.Join(r.config.Engine.TmpDir, "slirp4netns-rootless-cni.log")
|
||||||
|
logFile, err := os.Create(logPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to open slirp4netns log file %s", logPath)
|
||||||
|
}
|
||||||
|
defer logFile.Close()
|
||||||
|
// Unlink immediately the file so we won't need to worry about cleaning it up later.
|
||||||
|
// It is still accessible through the open fd logFile.
|
||||||
|
if err := os.Remove(logPath); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "delete file %s", logPath)
|
||||||
|
}
|
||||||
|
cmd.Stdout = logFile
|
||||||
|
cmd.Stderr = logFile
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to start slirp4netns process")
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := cmd.Process.Release(); err != nil {
|
||||||
|
logrus.Errorf("unable to release command process: %q", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := waitForSync(syncR, cmd, logFile, 1*time.Second); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create cni directories to store files
|
||||||
|
// they will be bind mounted to the correct location in a extra mount ns
|
||||||
|
err = os.MkdirAll(filepath.Join(cniDir, "var"), 0700)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create rootless-cni var directory")
|
||||||
|
}
|
||||||
|
runDir := filepath.Join(cniDir, "run")
|
||||||
|
err = os.MkdirAll(runDir, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create rootless-cni run directory")
|
||||||
|
}
|
||||||
|
// relabel the new run directory to the iptables /run label
|
||||||
|
// this is important, otherwise the iptables command will fail
|
||||||
|
err = label.Relabel(runDir, "system_u:object_r:iptables_var_run_t:s0", false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create relabel rootless-cni run directory")
|
||||||
|
}
|
||||||
|
// create systemd run directory
|
||||||
|
err = os.MkdirAll(filepath.Join(runDir, "systemd"), 0700)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create rootless-cni systemd directory")
|
||||||
|
}
|
||||||
|
// create the directory for the netns files at the same location
|
||||||
|
// relative to the rootless-cni location
|
||||||
|
err = os.MkdirAll(filepath.Join(cniDir, nsDir), 0700)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not create rootless-cni netns directory")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// return a error if we could not get the namespace and should no create one
|
||||||
|
return nil, errors.Wrap(err, "error getting rootless cni network namespace")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootlessCNINS = &rootlessCNI{
|
||||||
|
ns: ns,
|
||||||
|
dir: cniDir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rootlessCNINS, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Create and configure a new network namespace for a container
|
// Create and configure a new network namespace for a container
|
||||||
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Result, error) {
|
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Result, error) {
|
||||||
|
rootlessCNINS, err := r.getRootlessCNINetNs(true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var requestedIP net.IP
|
var requestedIP net.IP
|
||||||
if ctr.requestedIP != nil {
|
if ctr.requestedIP != nil {
|
||||||
requestedIP = ctr.requestedIP
|
requestedIP = ctr.requestedIP
|
||||||
@ -147,9 +365,11 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
|||||||
podNetwork.Aliases = aliases
|
podNetwork.Aliases = aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
results, err := r.netPlugin.SetUpPod(podNetwork)
|
var results []ocicni.NetResult
|
||||||
|
setUpPod := func() error {
|
||||||
|
results, err = r.netPlugin.SetUpPod(podNetwork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "error configuring network namespace for container %s", ctr.ID())
|
return errors.Wrapf(err, "error configuring network namespace for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -158,6 +378,18 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// rootlessCNINS is nil if we are root
|
||||||
|
if rootlessCNINS != nil {
|
||||||
|
// execute the cni setup in the rootless net ns
|
||||||
|
err = rootlessCNINS.Do(setUpPod)
|
||||||
|
} else {
|
||||||
|
err = setUpPod()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
networkStatus := make([]*cnitypes.Result, 0)
|
networkStatus := make([]*cnitypes.Result, 0)
|
||||||
for idx, r := range results {
|
for idx, r := range results {
|
||||||
@ -192,7 +424,7 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result,
|
|||||||
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
|
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
|
||||||
|
|
||||||
networkStatus := []*cnitypes.Result{}
|
networkStatus := []*cnitypes.Result{}
|
||||||
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
|
if !ctr.config.NetMode.IsSlirp4netns() {
|
||||||
networkStatus, err = r.configureNetNS(ctr, ctrNS)
|
networkStatus, err = r.configureNetNS(ctr, ctrNS)
|
||||||
}
|
}
|
||||||
return ctrNS, networkStatus, err
|
return ctrNS, networkStatus, err
|
||||||
@ -221,6 +453,17 @@ type slirp4netnsCmd struct {
|
|||||||
Args slirp4netnsCmdArg `json:"arguments"`
|
Args slirp4netnsCmdArg `json:"arguments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type slirp4netnsNetworkOptions struct {
|
||||||
|
cidr string
|
||||||
|
disableHostLoopback bool
|
||||||
|
enableIPv6 bool
|
||||||
|
isSlirpHostForward bool
|
||||||
|
noPivotRoot bool
|
||||||
|
mtu int
|
||||||
|
outboundAddr string
|
||||||
|
outboundAddr6 string
|
||||||
|
}
|
||||||
|
|
||||||
func checkSlirpFlags(path string) (*slirpFeatures, error) {
|
func checkSlirpFlags(path string) (*slirpFeatures, error) {
|
||||||
cmd := exec.Command(path, "--help")
|
cmd := exec.Command(path, "--help")
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
@ -256,11 +499,137 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseSlirp4netnsNetworkOptions(r *Runtime, extraOptions []string) (*slirp4netnsNetworkOptions, error) {
|
||||||
|
slirpOptions := append(r.config.Engine.NetworkCmdOptions, extraOptions...)
|
||||||
|
slirp4netnsOpts := &slirp4netnsNetworkOptions{
|
||||||
|
// overwrite defaults
|
||||||
|
disableHostLoopback: true,
|
||||||
|
mtu: slirp4netnsMTU,
|
||||||
|
noPivotRoot: r.config.Engine.NoPivotRoot,
|
||||||
|
}
|
||||||
|
for _, o := range slirpOptions {
|
||||||
|
parts := strings.SplitN(o, "=", 2)
|
||||||
|
if len(parts) < 2 {
|
||||||
|
return nil, errors.Errorf("unknown option for slirp4netns: %q", o)
|
||||||
|
}
|
||||||
|
option, value := parts[0], parts[1]
|
||||||
|
switch option {
|
||||||
|
case "cidr":
|
||||||
|
ipv4, _, err := net.ParseCIDR(value)
|
||||||
|
if err != nil || ipv4.To4() == nil {
|
||||||
|
return nil, errors.Errorf("invalid cidr %q", value)
|
||||||
|
}
|
||||||
|
slirp4netnsOpts.cidr = value
|
||||||
|
case "port_handler":
|
||||||
|
switch value {
|
||||||
|
case "slirp4netns":
|
||||||
|
slirp4netnsOpts.isSlirpHostForward = true
|
||||||
|
case "rootlesskit":
|
||||||
|
slirp4netnsOpts.isSlirpHostForward = false
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("unknown port_handler for slirp4netns: %q", value)
|
||||||
|
}
|
||||||
|
case "allow_host_loopback":
|
||||||
|
switch value {
|
||||||
|
case "true":
|
||||||
|
slirp4netnsOpts.disableHostLoopback = false
|
||||||
|
case "false":
|
||||||
|
slirp4netnsOpts.disableHostLoopback = true
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("invalid value of allow_host_loopback for slirp4netns: %q", value)
|
||||||
|
}
|
||||||
|
case "enable_ipv6":
|
||||||
|
switch value {
|
||||||
|
case "true":
|
||||||
|
slirp4netnsOpts.enableIPv6 = true
|
||||||
|
case "false":
|
||||||
|
slirp4netnsOpts.enableIPv6 = false
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("invalid value of enable_ipv6 for slirp4netns: %q", value)
|
||||||
|
}
|
||||||
|
case "outbound_addr":
|
||||||
|
ipv4 := net.ParseIP(value)
|
||||||
|
if ipv4 == nil || ipv4.To4() == nil {
|
||||||
|
_, err := net.InterfaceByName(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("invalid outbound_addr %q", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slirp4netnsOpts.outboundAddr = value
|
||||||
|
case "outbound_addr6":
|
||||||
|
ipv6 := net.ParseIP(value)
|
||||||
|
if ipv6 == nil || ipv6.To4() != nil {
|
||||||
|
_, err := net.InterfaceByName(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("invalid outbound_addr6: %q", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slirp4netnsOpts.outboundAddr6 = value
|
||||||
|
case "mtu":
|
||||||
|
var err error
|
||||||
|
slirp4netnsOpts.mtu, err = strconv.Atoi(value)
|
||||||
|
if slirp4netnsOpts.mtu < 68 || err != nil {
|
||||||
|
return nil, errors.Errorf("invalid mtu %q", value)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("unknown option for slirp4netns: %q", o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slirp4netnsOpts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBasicSlirp4netnsCmdArgs(options *slirp4netnsNetworkOptions, features *slirpFeatures) ([]string, error) {
|
||||||
|
cmdArgs := []string{}
|
||||||
|
if options.disableHostLoopback && features.HasDisableHostLoopback {
|
||||||
|
cmdArgs = append(cmdArgs, "--disable-host-loopback")
|
||||||
|
}
|
||||||
|
if options.mtu > -1 && features.HasMTU {
|
||||||
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--mtu=%d", options.mtu))
|
||||||
|
}
|
||||||
|
if !options.noPivotRoot && features.HasEnableSandbox {
|
||||||
|
cmdArgs = append(cmdArgs, "--enable-sandbox")
|
||||||
|
}
|
||||||
|
if features.HasEnableSeccomp {
|
||||||
|
cmdArgs = append(cmdArgs, "--enable-seccomp")
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.cidr != "" {
|
||||||
|
if !features.HasCIDR {
|
||||||
|
return nil, errors.Errorf("cidr not supported")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--cidr=%s", options.cidr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.enableIPv6 {
|
||||||
|
if !features.HasIPv6 {
|
||||||
|
return nil, errors.Errorf("enable_ipv6 not supported")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, "--enable-ipv6")
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.outboundAddr != "" {
|
||||||
|
if !features.HasOutboundAddr {
|
||||||
|
return nil, errors.Errorf("outbound_addr not supported")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr=%s", options.outboundAddr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.outboundAddr6 != "" {
|
||||||
|
if !features.HasOutboundAddr || !features.HasIPv6 {
|
||||||
|
return nil, errors.Errorf("outbound_addr6 not supported")
|
||||||
|
}
|
||||||
|
if !options.enableIPv6 {
|
||||||
|
return nil, errors.Errorf("enable_ipv6=true is required for outbound_addr6")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr6=%s", options.outboundAddr6))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdArgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// setupSlirp4netns can be called in rootful as well as in rootless
|
// setupSlirp4netns can be called in rootful as well as in rootless
|
||||||
func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
||||||
path := r.config.Engine.NetworkCmdPath
|
path := r.config.Engine.NetworkCmdPath
|
||||||
slirpOptions := r.config.Engine.NetworkCmdOptions
|
|
||||||
noPivotRoot := r.config.Engine.NoPivotRoot
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
var err error
|
var err error
|
||||||
path, err = exec.LookPath("slirp4netns")
|
path, err = exec.LookPath("slirp4netns")
|
||||||
@ -280,139 +649,21 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
|||||||
havePortMapping := len(ctr.Config().PortMappings) > 0
|
havePortMapping := len(ctr.Config().PortMappings) > 0
|
||||||
logPath := filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("slirp4netns-%s.log", ctr.config.ID))
|
logPath := filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("slirp4netns-%s.log", ctr.config.ID))
|
||||||
|
|
||||||
cidr := ""
|
ctrNetworkSlipOpts := []string{}
|
||||||
isSlirpHostForward := false
|
|
||||||
disableHostLoopback := true
|
|
||||||
enableIPv6 := false
|
|
||||||
outboundAddr := ""
|
|
||||||
outboundAddr6 := ""
|
|
||||||
mtu := slirp4netnsMTU
|
|
||||||
|
|
||||||
if ctr.config.NetworkOptions != nil {
|
if ctr.config.NetworkOptions != nil {
|
||||||
slirpOptions = append(slirpOptions, ctr.config.NetworkOptions["slirp4netns"]...)
|
ctrNetworkSlipOpts = append(ctrNetworkSlipOpts, ctr.config.NetworkOptions["slirp4netns"]...)
|
||||||
}
|
}
|
||||||
|
netOptions, err := parseSlirp4netnsNetworkOptions(r, ctrNetworkSlipOpts)
|
||||||
for _, o := range slirpOptions {
|
|
||||||
parts := strings.SplitN(o, "=", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return errors.Errorf("unknown option for slirp4netns: %q", o)
|
|
||||||
}
|
|
||||||
option, value := parts[0], parts[1]
|
|
||||||
switch option {
|
|
||||||
case "cidr":
|
|
||||||
ipv4, _, err := net.ParseCIDR(value)
|
|
||||||
if err != nil || ipv4.To4() == nil {
|
|
||||||
return errors.Errorf("invalid cidr %q", value)
|
|
||||||
}
|
|
||||||
cidr = value
|
|
||||||
case "port_handler":
|
|
||||||
switch value {
|
|
||||||
case "slirp4netns":
|
|
||||||
isSlirpHostForward = true
|
|
||||||
case "rootlesskit":
|
|
||||||
isSlirpHostForward = false
|
|
||||||
default:
|
|
||||||
return errors.Errorf("unknown port_handler for slirp4netns: %q", value)
|
|
||||||
}
|
|
||||||
case "allow_host_loopback":
|
|
||||||
switch value {
|
|
||||||
case "true":
|
|
||||||
disableHostLoopback = false
|
|
||||||
case "false":
|
|
||||||
disableHostLoopback = true
|
|
||||||
default:
|
|
||||||
return errors.Errorf("invalid value of allow_host_loopback for slirp4netns: %q", value)
|
|
||||||
}
|
|
||||||
case "enable_ipv6":
|
|
||||||
switch value {
|
|
||||||
case "true":
|
|
||||||
enableIPv6 = true
|
|
||||||
case "false":
|
|
||||||
enableIPv6 = false
|
|
||||||
default:
|
|
||||||
return errors.Errorf("invalid value of enable_ipv6 for slirp4netns: %q", value)
|
|
||||||
}
|
|
||||||
case "outbound_addr":
|
|
||||||
ipv4 := net.ParseIP(value)
|
|
||||||
if ipv4 == nil || ipv4.To4() == nil {
|
|
||||||
_, err := net.InterfaceByName(value)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("invalid outbound_addr %q", value)
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
outboundAddr = value
|
|
||||||
case "outbound_addr6":
|
|
||||||
ipv6 := net.ParseIP(value)
|
|
||||||
if ipv6 == nil || ipv6.To4() != nil {
|
|
||||||
_, err := net.InterfaceByName(value)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Errorf("invalid outbound_addr6: %q", value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outboundAddr6 = value
|
|
||||||
case "mtu":
|
|
||||||
mtu, err = strconv.Atoi(value)
|
|
||||||
if mtu < 68 || err != nil {
|
|
||||||
return errors.Errorf("invalid mtu %q", value)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.Errorf("unknown option for slirp4netns: %q", o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdArgs := []string{}
|
|
||||||
slirpFeatures, err := checkSlirpFlags(path)
|
slirpFeatures, err := checkSlirpFlags(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error checking slirp4netns binary %s: %q", path, err)
|
return errors.Wrapf(err, "error checking slirp4netns binary %s: %q", path, err)
|
||||||
}
|
}
|
||||||
if disableHostLoopback && slirpFeatures.HasDisableHostLoopback {
|
cmdArgs, err := createBasicSlirp4netnsCmdArgs(netOptions, slirpFeatures)
|
||||||
cmdArgs = append(cmdArgs, "--disable-host-loopback")
|
if err != nil {
|
||||||
}
|
return err
|
||||||
if mtu > -1 && slirpFeatures.HasMTU {
|
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--mtu=%d", mtu))
|
|
||||||
}
|
|
||||||
if !noPivotRoot && slirpFeatures.HasEnableSandbox {
|
|
||||||
cmdArgs = append(cmdArgs, "--enable-sandbox")
|
|
||||||
}
|
|
||||||
if slirpFeatures.HasEnableSeccomp {
|
|
||||||
cmdArgs = append(cmdArgs, "--enable-seccomp")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cidr != "" {
|
|
||||||
if !slirpFeatures.HasCIDR {
|
|
||||||
return errors.Errorf("cidr not supported")
|
|
||||||
}
|
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--cidr=%s", cidr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if enableIPv6 {
|
|
||||||
if !slirpFeatures.HasIPv6 {
|
|
||||||
return errors.Errorf("enable_ipv6 not supported")
|
|
||||||
}
|
|
||||||
cmdArgs = append(cmdArgs, "--enable-ipv6")
|
|
||||||
}
|
|
||||||
|
|
||||||
if outboundAddr != "" {
|
|
||||||
if !slirpFeatures.HasOutboundAddr {
|
|
||||||
return errors.Errorf("outbound_addr not supported")
|
|
||||||
}
|
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr=%s", outboundAddr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if outboundAddr6 != "" {
|
|
||||||
if !slirpFeatures.HasOutboundAddr || !slirpFeatures.HasIPv6 {
|
|
||||||
return errors.Errorf("outbound_addr6 not supported")
|
|
||||||
}
|
|
||||||
if !enableIPv6 {
|
|
||||||
return errors.Errorf("enable_ipv6=true is required for outbound_addr6")
|
|
||||||
}
|
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--outbound-addr6=%s", outboundAddr6))
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiSocket string
|
|
||||||
if havePortMapping && isSlirpHostForward {
|
|
||||||
apiSocket = filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("%s.net", ctr.config.ID))
|
|
||||||
cmdArgs = append(cmdArgs, "--api-socket", apiSocket)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the slirp4netns arguments being passed are describes as follows:
|
// the slirp4netns arguments being passed are describes as follows:
|
||||||
@ -421,6 +672,12 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
|||||||
// -e, --exit-fd=FD specify the FD for terminating slirp4netns
|
// -e, --exit-fd=FD specify the FD for terminating slirp4netns
|
||||||
// -r, --ready-fd=FD specify the FD to write to when the initialization steps are finished
|
// -r, --ready-fd=FD specify the FD to write to when the initialization steps are finished
|
||||||
cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4")
|
cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4")
|
||||||
|
|
||||||
|
var apiSocket string
|
||||||
|
if havePortMapping && netOptions.isSlirpHostForward {
|
||||||
|
apiSocket = filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("%s.net", ctr.config.ID))
|
||||||
|
cmdArgs = append(cmdArgs, "--api-socket", apiSocket)
|
||||||
|
}
|
||||||
netnsPath := ""
|
netnsPath := ""
|
||||||
if !ctr.config.PostConfigureNetNS {
|
if !ctr.config.PostConfigureNetNS {
|
||||||
ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
|
ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
|
||||||
@ -444,7 +701,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// workaround for https://github.com/rootless-containers/slirp4netns/pull/153
|
// workaround for https://github.com/rootless-containers/slirp4netns/pull/153
|
||||||
if !noPivotRoot && slirpFeatures.HasEnableSandbox {
|
if !netOptions.noPivotRoot && slirpFeatures.HasEnableSandbox {
|
||||||
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
|
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
|
||||||
cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
|
cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
|
||||||
}
|
}
|
||||||
@ -478,7 +735,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if havePortMapping {
|
if havePortMapping {
|
||||||
if isSlirpHostForward {
|
if netOptions.isSlirpHostForward {
|
||||||
return r.setupRootlessPortMappingViaSlirp(ctr, cmd, apiSocket)
|
return r.setupRootlessPortMappingViaSlirp(ctr, cmd, apiSocket)
|
||||||
}
|
}
|
||||||
return r.setupRootlessPortMappingViaRLK(ctr, netnsPath)
|
return r.setupRootlessPortMappingViaRLK(ctr, netnsPath)
|
||||||
@ -789,8 +1046,11 @@ func (r *Runtime) teardownCNI(ctr *Container) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// rootless containers do not use the CNI plugin directly
|
if !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
|
||||||
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
|
rootlessCNINS, err := r.getRootlessCNINetNs(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var requestedIP net.IP
|
var requestedIP net.IP
|
||||||
if ctr.requestedIP != nil {
|
if ctr.requestedIP != nil {
|
||||||
requestedIP = ctr.requestedIP
|
requestedIP = ctr.requestedIP
|
||||||
@ -811,9 +1071,21 @@ func (r *Runtime) teardownCNI(ctr *Container) error {
|
|||||||
|
|
||||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC, ctr.state.NetInterfaceDescriptions)
|
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC, ctr.state.NetInterfaceDescriptions)
|
||||||
|
|
||||||
|
tearDownPod := func() error {
|
||||||
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
||||||
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rootlessCNINS is nil if we are root
|
||||||
|
if rootlessCNINS != nil {
|
||||||
|
// execute the cni setup in the rootless net ns
|
||||||
|
err = rootlessCNINS.Do(tearDownPod)
|
||||||
|
} else {
|
||||||
|
err = tearDownPod()
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -824,18 +1096,6 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
networks, _, err := ctr.networks()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CNI-in-slirp4netns
|
|
||||||
if rootless.IsRootless() && len(networks) != 0 {
|
|
||||||
if err := DeallocRootlessCNI(context.Background(), ctr); err != nil {
|
|
||||||
return errors.Wrapf(err, "error tearing down CNI-in-slirp4netns for container %s", ctr.ID())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// First unmount the namespace
|
// First unmount the namespace
|
||||||
if err := netns.UnmountNS(ctr.state.NetNS); err != nil {
|
if err := netns.UnmountNS(ctr.state.NetNS); err != nil {
|
||||||
return errors.Wrapf(err, "error unmounting network namespace for container %s", ctr.ID())
|
return errors.Wrapf(err, "error unmounting network namespace for container %s", ctr.ID())
|
||||||
|
@ -436,13 +436,11 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up the CNI net plugin
|
// Set up the CNI net plugin
|
||||||
if !rootless.IsRootless() {
|
|
||||||
netPlugin, err := ocicni.InitCNI(runtime.config.Network.DefaultNetwork, runtime.config.Network.NetworkConfigDir, runtime.config.Network.CNIPluginDirs...)
|
netPlugin, err := ocicni.InitCNI(runtime.config.Network.DefaultNetwork, runtime.config.Network.NetworkConfigDir, runtime.config.Network.CNIPluginDirs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error configuring CNI network plugin")
|
return errors.Wrapf(err, "error configuring CNI network plugin")
|
||||||
}
|
}
|
||||||
runtime.netPlugin = netPlugin
|
runtime.netPlugin = netPlugin
|
||||||
}
|
|
||||||
|
|
||||||
// We now need to see if the system has restarted
|
// We now need to see if the system has restarted
|
||||||
// We check for the presence of a file in our tmp directory to verify this
|
// We check for the presence of a file in our tmp directory to verify this
|
||||||
|
@ -35,9 +35,9 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// get NSRunDir returns the dir of where to create the netNS. When running
|
// GetNSRunDir returns the dir of where to create the netNS. When running
|
||||||
// rootless, it needs to be at a location writable by user.
|
// rootless, it needs to be at a location writable by user.
|
||||||
func getNSRunDir() (string, error) {
|
func GetNSRunDir() (string, error) {
|
||||||
if rootless.IsRootless() {
|
if rootless.IsRootless() {
|
||||||
rootlessDir, err := util.GetRuntimeDir()
|
rootlessDir, err := util.GetRuntimeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -51,16 +51,22 @@ func getNSRunDir() (string, error) {
|
|||||||
// NewNS creates a new persistent (bind-mounted) network namespace and returns
|
// NewNS creates a new persistent (bind-mounted) network namespace and returns
|
||||||
// an object representing that namespace, without switching to it.
|
// an object representing that namespace, without switching to it.
|
||||||
func NewNS() (ns.NetNS, error) {
|
func NewNS() (ns.NetNS, error) {
|
||||||
nsRunDir, err := getNSRunDir()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
_, err = rand.Reader.Read(b)
|
_, err := rand.Reader.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate random netns name: %v", err)
|
return nil, fmt.Errorf("failed to generate random netns name: %v", err)
|
||||||
}
|
}
|
||||||
|
nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||||
|
return NewNSWithName(nsName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNSWithName creates a new persistent (bind-mounted) network namespace and returns
|
||||||
|
// an object representing that namespace, without switching to it.
|
||||||
|
func NewNSWithName(name string) (ns.NetNS, error) {
|
||||||
|
nsRunDir, err := GetNSRunDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Create the directory for mounting network namespaces
|
// Create the directory for mounting network namespaces
|
||||||
// This needs to be a shared mountpoint in case it is mounted in to
|
// This needs to be a shared mountpoint in case it is mounted in to
|
||||||
@ -93,10 +99,8 @@ func NewNS() (ns.NetNS, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
|
||||||
|
|
||||||
// create an empty file at the mount point
|
// create an empty file at the mount point
|
||||||
nsPath := path.Join(nsRunDir, nsName)
|
nsPath := path.Join(nsRunDir, name)
|
||||||
mountPointFd, err := os.Create(nsPath)
|
mountPointFd, err := os.Create(nsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -177,7 +181,7 @@ func NewNS() (ns.NetNS, error) {
|
|||||||
|
|
||||||
// UnmountNS unmounts the NS held by the netns object
|
// UnmountNS unmounts the NS held by the netns object
|
||||||
func UnmountNS(ns ns.NetNS) error {
|
func UnmountNS(ns ns.NetNS) error {
|
||||||
nsRunDir, err := getNSRunDir()
|
nsRunDir, err := GetNSRunDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -143,13 +143,6 @@ load helpers
|
|||||||
|
|
||||||
run_podman network rm $mynetname
|
run_podman network rm $mynetname
|
||||||
run_podman 1 network rm $mynetname
|
run_podman 1 network rm $mynetname
|
||||||
|
|
||||||
# rootless CNI leaves behind an image pulled by SHA, hence with no tag.
|
|
||||||
# Remove it if present; we can only remove it by ID.
|
|
||||||
run_podman images --format '{{.Id}}' rootless-cni-infra
|
|
||||||
if [ -n "$output" ]; then
|
|
||||||
run_podman rmi $output
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "podman network reload" {
|
@test "podman network reload" {
|
||||||
|
Reference in New Issue
Block a user