summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal.go36
-rw-r--r--libpod/networking_linux.go35
-rw-r--r--libpod/networking_slirp4netns.go91
-rw-r--r--libpod/util.go39
4 files changed, 139 insertions, 62 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index e7694227a..8ffcccf4c 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -472,20 +472,10 @@ func (c *Container) setupStorage(ctx context.Context) error {
c.config.IDMappings.UIDMap = containerInfo.UIDMap
c.config.IDMappings.GIDMap = containerInfo.GIDMap
- processLabel := containerInfo.ProcessLabel
- switch {
- case c.ociRuntime.SupportsKVM():
- processLabel, err = selinux.KVMLabel(processLabel)
- if err != nil {
- return err
- }
- case c.config.Systemd:
- processLabel, err = selinux.InitLabel(processLabel)
- if err != nil {
- return err
- }
+ processLabel, err := c.processLabel(containerInfo.ProcessLabel)
+ if err != nil {
+ return err
}
-
c.config.ProcessLabel = processLabel
c.config.MountLabel = containerInfo.MountLabel
c.config.StaticDir = containerInfo.Dir
@@ -520,6 +510,26 @@ func (c *Container) setupStorage(ctx context.Context) error {
return nil
}
+func (c *Container) processLabel(processLabel string) (string, error) {
+ if !c.config.Systemd && !c.ociRuntime.SupportsKVM() {
+ return processLabel, nil
+ }
+ ctrSpec, err := c.specFromState()
+ if err != nil {
+ return "", err
+ }
+ label, ok := ctrSpec.Annotations[define.InspectAnnotationLabel]
+ if !ok || !strings.Contains(label, "type:") {
+ switch {
+ case c.ociRuntime.SupportsKVM():
+ return selinux.KVMLabel(processLabel)
+ case c.config.Systemd:
+ return selinux.InitLabel(processLabel)
+ }
+ }
+ return processLabel, nil
+}
+
// Tear down a container's storage prior to removal
func (c *Container) teardownStorage() error {
if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 0f3e03e06..8e9b5997c 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -1214,7 +1214,29 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
}
}
c.state.NetworkStatus = tmpNetworkStatus
- return c.save()
+ err = c.save()
+ if err != nil {
+ return err
+ }
+
+ // OCICNI will set the loopback adpter down on teardown so we should set it up again
+ err = c.state.NetNS.Do(func(_ ns.NetNS) error {
+ link, err := netlink.LinkByName("lo")
+ if err != nil {
+ return err
+ }
+ err = netlink.LinkSetUp(link)
+ return err
+ })
+ if err != nil {
+ logrus.Warnf("failed to set loopback adpter up in the container: %v", err)
+ }
+ // Reload ports when there are still connected networks, maybe we removed the network interface with the child ip.
+ // Reloading without connected networks does not make sense, so we can skip this step.
+ if rootless.IsRootless() && len(tmpNetworkStatus) > 0 {
+ return c.reloadRootlessRLKPortMapping()
+ }
+ return nil
}
// ConnectNetwork connects a container to a given network
@@ -1306,7 +1328,16 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
networkStatus[index] = networkResults[0]
c.state.NetworkStatus = networkStatus
}
- return c.save()
+ err = c.save()
+ if err != nil {
+ return err
+ }
+ // The first network needs a port reload to set the correct child ip for the rootlessport process.
+ // Adding a second network does not require a port reload because the child ip is still valid.
+ if rootless.IsRootless() && len(networks) == 0 {
+ return c.reloadRootlessRLKPortMapping()
+ }
+ return nil
}
// DisconnectContainerFromNetwork removes a container from its CNI network
diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go
index 410b377ec..5858364ff 100644
--- a/libpod/networking_slirp4netns.go
+++ b/libpod/networking_slirp4netns.go
@@ -17,6 +17,7 @@ import (
"time"
"github.com/containers/podman/v3/pkg/errorhandling"
+ "github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/rootlessport"
"github.com/containers/podman/v3/pkg/servicereaper"
"github.com/pkg/errors"
@@ -466,29 +467,16 @@ func (r *Runtime) setupRootlessPortMappingViaRLK(ctr *Container, netnsPath strin
}
}
- slirp4netnsIP, err := GetSlirp4netnsIP(ctr.slirp4netnsSubnet)
- if err != nil {
- return errors.Wrapf(err, "failed to get slirp4ns ip")
- }
- childIP := slirp4netnsIP.String()
-outer:
- for _, r := range ctr.state.NetworkStatus {
- for _, i := range r.IPs {
- ipv4 := i.Address.IP.To4()
- if ipv4 != nil {
- childIP = ipv4.String()
- break outer
- }
- }
- }
-
+ childIP := getRootlessPortChildIP(ctr)
cfg := rootlessport.Config{
- Mappings: ctr.config.PortMappings,
- NetNSPath: netnsPath,
- ExitFD: 3,
- ReadyFD: 4,
- TmpDir: ctr.runtime.config.Engine.TmpDir,
- ChildIP: childIP,
+ Mappings: ctr.config.PortMappings,
+ NetNSPath: netnsPath,
+ ExitFD: 3,
+ ReadyFD: 4,
+ TmpDir: ctr.runtime.config.Engine.TmpDir,
+ ChildIP: childIP,
+ ContainerID: ctr.config.ID,
+ RootlessCNI: ctr.config.NetMode.IsBridge() && rootless.IsRootless(),
}
cfgJSON, err := json.Marshal(cfg)
if err != nil {
@@ -617,3 +605,62 @@ func (r *Runtime) setupRootlessPortMappingViaSlirp(ctr *Container, cmd *exec.Cmd
logrus.Debug("slirp4netns port-forwarding setup via add_hostfwd is ready")
return nil
}
+
+func getRootlessPortChildIP(c *Container) string {
+ if c.config.NetMode.IsSlirp4netns() {
+ slirp4netnsIP, err := GetSlirp4netnsIP(c.slirp4netnsSubnet)
+ if err != nil {
+ return ""
+ }
+ return slirp4netnsIP.String()
+ }
+
+ for _, r := range c.state.NetworkStatus {
+ for _, i := range r.IPs {
+ ipv4 := i.Address.IP.To4()
+ if ipv4 != nil {
+ return ipv4.String()
+ }
+ }
+ }
+ return ""
+}
+
+// reloadRootlessRLKPortMapping will trigger a reload for the port mappings in the rootlessport process.
+// This should only be called by network connect/disconnect and only as rootless.
+func (c *Container) reloadRootlessRLKPortMapping() error {
+ childIP := getRootlessPortChildIP(c)
+ logrus.Debugf("reloading rootless ports for container %s, childIP is %s", c.config.ID, childIP)
+
+ var conn net.Conn
+ var err error
+ // try three times to connect to the socket, maybe it is not ready yet
+ for i := 0; i < 3; i++ {
+ conn, err = net.Dial("unix", filepath.Join(c.runtime.config.Engine.TmpDir, "rp", c.config.ID))
+ if err == nil {
+ break
+ }
+ time.Sleep(250 * time.Millisecond)
+ }
+ if err != nil {
+ // This is not a hard error for backwards compatibility. A container started
+ // with an old version did not created the rootlessport socket.
+ logrus.Warnf("Could not reload rootless port mappings, port forwarding may no longer work correctly: %v", err)
+ return nil
+ }
+ defer conn.Close()
+ enc := json.NewEncoder(conn)
+ err = enc.Encode(childIP)
+ if err != nil {
+ return errors.Wrap(err, "port reloading failed")
+ }
+ b, err := ioutil.ReadAll(conn)
+ if err != nil {
+ return errors.Wrap(err, "port reloading failed")
+ }
+ data := string(b)
+ if data != "OK" {
+ return errors.Errorf("port reloading failed: %s", data)
+ }
+ return nil
+}
diff --git a/libpod/util.go b/libpod/util.go
index 7f4a01f28..3b32fb264 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -153,33 +153,22 @@ func queryPackageVersion(cmdArg ...string) string {
return strings.Trim(output, "\n")
}
-func equeryVersion(path string) string {
- return queryPackageVersion("/usr/bin/equery", "b", path)
-}
-
-func pacmanVersion(path string) string {
- return queryPackageVersion("/usr/bin/pacman", "-Qo", path)
-}
-
-func dpkgVersion(path string) string {
- return queryPackageVersion("/usr/bin/dpkg", "-S", path)
-}
-
-func rpmVersion(path string) string {
- return queryPackageVersion("/usr/bin/rpm", "-q", "-f", path)
-}
-
-func packageVersion(program string) string {
- if out := rpmVersion(program); out != unknownPackage {
- return out
- }
- if out := dpkgVersion(program); out != unknownPackage {
- return out
+func packageVersion(program string) string { // program is full path
+ packagers := [][]string{
+ {"/usr/bin/rpm", "-q", "-f"},
+ {"/usr/bin/dpkg", "-S"}, // Debian, Ubuntu
+ {"/usr/bin/pacman", "-Qo"}, // Arch
+ {"/usr/bin/qfile", "-qv"}, // Gentoo (quick)
+ {"/usr/bin/equery", "b"}, // Gentoo (slow)
}
- if out := pacmanVersion(program); out != unknownPackage {
- return out
+
+ for _, cmd := range packagers {
+ cmd = append(cmd, program)
+ if out := queryPackageVersion(cmd...); out != unknownPackage {
+ return out
+ }
}
- return equeryVersion(program)
+ return unknownPackage
}
func programVersion(mountProgram string) (string, error) {