summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/networking_linux.go35
-rw-r--r--libpod/networking_slirp4netns.go91
2 files changed, 102 insertions, 24 deletions
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
+}