diff options
author | Giuseppe Scrivano <gscrivan@redhat.com> | 2018-04-20 18:59:19 +0200 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-05-04 17:15:55 +0000 |
commit | 73078fabcfd2420c47e41843da71dd993f9a0a3e (patch) | |
tree | 1c98d8ae433c5f148c7af5184777d2348b5b2540 /libpod | |
parent | b51d7379987581da82902027fe91cdf298047bc0 (diff) | |
download | podman-73078fabcfd2420c47e41843da71dd993f9a0a3e.tar.gz podman-73078fabcfd2420c47e41843da71dd993f9a0a3e.tar.bz2 podman-73078fabcfd2420c47e41843da71dd993f9a0a3e.zip |
networking, userNS: configure the network namespace after create
so that the OCI runtime creates the network namespace from the correct
userNS.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Closes: #690
Approved by: mheon
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container.go | 2 | ||||
-rw-r--r-- | libpod/container_internal.go | 24 | ||||
-rw-r--r-- | libpod/networking.go | 73 | ||||
-rw-r--r-- | libpod/options.go | 3 |
4 files changed, 83 insertions, 19 deletions
diff --git a/libpod/container.go b/libpod/container.go index fb1f83c29..5fa27af58 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -285,6 +285,8 @@ type ContainerConfig struct { // File containing the conmon PID ConmonPidFile string `json:"conmonPidFile,omitempty"` // TODO log options for log drivers + + PostConfigureNetNS bool `json:"postConfigureNetNS"` } // ContainerStatus returns a string representation for users diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 73095316e..18b56e23c 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -416,6 +416,16 @@ func (c *Container) checkDependenciesRunningLocked(depCtrs map[string]*Container return notRunning, nil } +func (c *Container) completeNetworkSetup() error { + if !c.config.PostConfigureNetNS { + return nil + } + if err := c.syncContainer(); err != nil { + return err + } + return c.runtime.setupNetNS(c) +} + // Initialize a container, creating it in the runtime func (c *Container) init(ctx context.Context) error { if err := c.makeBindMounts(); err != nil { @@ -442,7 +452,11 @@ func (c *Container) init(ctx context.Context) error { c.state.State = ContainerStateCreated - return c.save() + if err := c.save(); err != nil { + return err + } + + return c.completeNetworkSetup() } // Reinitialize a container @@ -626,7 +640,7 @@ func (c *Container) prepare() (err error) { } // Set up network namespace if not already set up - if c.config.CreateNetNS && c.state.NetNS == nil { + if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS { if err := c.runtime.createNetNS(c); err != nil { // Tear down storage before exiting to make sure we // don't leak mounts @@ -913,7 +927,11 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { // If network namespace was requested, add it now if c.config.CreateNetNS { - g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()) + if c.config.PostConfigureNetNS { + g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "") + } else { + g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path()) + } } // Remove the default /dev/shm mount to ensure we overwrite it diff --git a/libpod/networking.go b/libpod/networking.go index cceeb18d6..54a1c78de 100644 --- a/libpod/networking.go +++ b/libpod/networking.go @@ -1,7 +1,12 @@ package libpod import ( + "crypto/rand" + "fmt" "net" + "os" + "path/filepath" + "strings" cnitypes "github.com/containernetworking/cni/pkg/types/current" "github.com/containernetworking/plugins/pkg/ns" @@ -9,7 +14,7 @@ import ( "github.com/pkg/errors" "github.com/projectatomic/libpod/utils" "github.com/sirupsen/logrus" - "strings" + "golang.org/x/sys/unix" ) // Get an OCICNI network config @@ -24,20 +29,7 @@ func getPodNetwork(id, name, nsPath string, ports []ocicni.PortMapping) ocicni.P } // Create and configure a new network namespace for a container -func (r *Runtime) createNetNS(ctr *Container) (err error) { - ctrNS, err := ns.NewNS() - if err != nil { - return errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID()) - } - defer func() { - if err != nil { - if err2 := ctrNS.Close(); err2 != nil { - logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err2) - } - } - }() - - logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID()) +func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) { podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.PortMappings) result, err := r.netPlugin.SetUpPod(podNetwork) @@ -74,6 +66,57 @@ func (r *Runtime) createNetNS(ctr *Container) (err error) { return nil } +// Create and configure a new network namespace for a container +func (r *Runtime) createNetNS(ctr *Container) (err error) { + ctrNS, err := ns.NewNS() + if err != nil { + return errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID()) + } + defer func() { + if err != nil { + if err2 := ctrNS.Close(); err2 != nil { + logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err2) + } + } + }() + + logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID()) + return r.configureNetNS(ctr, ctrNS) +} + +// Configure the network namespace using the container process +func (r *Runtime) setupNetNS(ctr *Container) (err error) { + nsProcess := fmt.Sprintf("/proc/%d/ns/net", ctr.state.PID) + + b := make([]byte, 16) + + if _, err := rand.Reader.Read(b); err != nil { + return errors.Wrapf(err, "failed to generate random netns name") + } + + nsPath := fmt.Sprintf("/var/run/netns/cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) + + if err := os.MkdirAll(filepath.Dir(nsPath), 0711); err != nil { + return errors.Wrapf(err, "cannot create %s", filepath.Dir(nsPath)) + } + + mountPointFd, err := os.Create(nsPath) + if err != nil { + return errors.Wrapf(err, "cannot open %s", nsPath) + } + mountPointFd.Close() + + if err := unix.Mount(nsProcess, nsPath, "none", unix.MS_BIND, ""); err != nil { + return errors.Wrapf(err, "cannot mount %s", nsPath) + } + + netNS, err := ns.GetNS(nsPath) + if err != nil { + return err + } + return r.configureNetNS(ctr, netNS) +} + // iptablesDNS accepts an arg (-I|-D) and IP address of the container and then // generates an iptables command to either add or subtract the needed rule func iptablesDNS(arg, ip string) error { diff --git a/libpod/options.go b/libpod/options.go index eaca70afc..2b3ad2eb4 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -707,7 +707,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption { // namespace with a minimal configuration. // An optional array of port mappings can be provided. // Conflicts with WithNetNSFrom(). -func WithNetNS(portMappings []ocicni.PortMapping) CtrCreateOption { +func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { return ErrCtrFinalized @@ -717,6 +717,7 @@ func WithNetNS(portMappings []ocicni.PortMapping) CtrCreateOption { return errors.Wrapf(ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns") } + ctr.config.PostConfigureNetNS = postConfigureNetNS ctr.config.CreateNetNS = true ctr.config.PortMappings = portMappings |