summaryrefslogtreecommitdiff
path: root/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
diff options
context:
space:
mode:
authorAkihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>2019-11-28 23:33:42 +0900
committerAkihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>2020-01-08 19:35:17 +0900
commitda7595a69fc15d131c9d8123d0a165bdde4232b6 (patch)
tree57985f4d9fbc903610f31f3076011cd413d82fdf /vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
parentc41fd09a8da3a96bc0e58f9f29f87b9bdf30264d (diff)
downloadpodman-da7595a69fc15d131c9d8123d0a165bdde4232b6.tar.gz
podman-da7595a69fc15d131c9d8123d0a165bdde4232b6.tar.bz2
podman-da7595a69fc15d131c9d8123d0a165bdde4232b6.zip
rootless: use RootlessKit port forwarder
RootlessKit port forwarder has a lot of advantages over the slirp4netns port forwarder: * Very high throughput. Benchmark result on Travis: socat: 5.2 Gbps, slirp4netns: 8.3 Gbps, RootlessKit: 27.3 Gbps (https://travis-ci.org/rootless-containers/rootlesskit/builds/597056377) * Connections from the host are treated as 127.0.0.1 rather than 10.0.2.2 in the namespace. No UDP issue (#4586) * No tcp_rmem issue (#4537) * Probably works with IPv6. Even if not, it is trivial to support IPv6. (#4311) * Easily extensible for future support of SCTP * Easily extensible for future support of `lxc-user-nic` SUID network RootlessKit port forwarder has been already adopted as the default port forwarder by Rootless Docker/Moby, and no issue has been reported AFAIK. As the port forwarder is imported as a Go package, no `rootlesskit` binary is required for Podman. Fix #4586 May-fix #4559 Fix #4537 May-fix #4311 See https://github.com/rootless-containers/rootlesskit/blob/v0.7.0/pkg/port/builtin/builtin.go Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Diffstat (limited to 'vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go')
-rw-r--r--vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go134
1 files changed, 134 insertions, 0 deletions
diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
new file mode 100644
index 000000000..5477dda51
--- /dev/null
+++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
@@ -0,0 +1,134 @@
+package child
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "os"
+
+ "github.com/pkg/errors"
+ "golang.org/x/sys/unix"
+
+ "github.com/rootless-containers/rootlesskit/pkg/msgutil"
+ "github.com/rootless-containers/rootlesskit/pkg/port"
+ "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
+ opaquepkg "github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque"
+)
+
+func NewDriver(logWriter io.Writer) port.ChildDriver {
+ return &childDriver{
+ logWriter: logWriter,
+ }
+}
+
+type childDriver struct {
+ logWriter io.Writer
+}
+
+func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error {
+ socketPath := opaque[opaquepkg.SocketPath]
+ if socketPath == "" {
+ return errors.New("socket path not set")
+ }
+ childReadyPipePath := opaque[opaquepkg.ChildReadyPipePath]
+ if childReadyPipePath == "" {
+ return errors.New("child ready pipe path not set")
+ }
+ childReadyPipeW, err := os.OpenFile(childReadyPipePath, os.O_WRONLY, os.ModeNamedPipe)
+ if err != nil {
+ return err
+ }
+ ln, err := net.ListenUnix("unix", &net.UnixAddr{
+ Name: socketPath,
+ Net: "unix",
+ })
+ if err != nil {
+ return err
+ }
+ // write nothing, just close
+ if err = childReadyPipeW.Close(); err != nil {
+ return err
+ }
+ stopAccept := make(chan struct{}, 1)
+ go func() {
+ <-quit
+ stopAccept <- struct{}{}
+ ln.Close()
+ }()
+ for {
+ c, err := ln.AcceptUnix()
+ if err != nil {
+ select {
+ case <-stopAccept:
+ return nil
+ default:
+ }
+ return err
+ }
+ go func() {
+ if rerr := d.routine(c); rerr != nil {
+ rep := msg.Reply{
+ Error: rerr.Error(),
+ }
+ msgutil.MarshalToWriter(c, &rep)
+ }
+ c.Close()
+ }()
+ }
+ return nil
+}
+
+func (d *childDriver) routine(c *net.UnixConn) error {
+ var req msg.Request
+ if _, err := msgutil.UnmarshalFromReader(c, &req); err != nil {
+ return err
+ }
+ switch req.Type {
+ case msg.RequestTypeInit:
+ return d.handleConnectInit(c, &req)
+ case msg.RequestTypeConnect:
+ return d.handleConnectRequest(c, &req)
+ default:
+ return errors.Errorf("unknown request type %q", req.Type)
+ }
+}
+
+func (d *childDriver) handleConnectInit(c *net.UnixConn, req *msg.Request) error {
+ _, err := msgutil.MarshalToWriter(c, nil)
+ return err
+}
+
+func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) error {
+ switch req.Proto {
+ case "tcp":
+ case "udp":
+ default:
+ return errors.Errorf("unknown proto: %q", req.Proto)
+ }
+ var dialer net.Dialer
+ targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port))
+ if err != nil {
+ return err
+ }
+ defer targetConn.Close() // no effect on duplicated FD
+ targetConnFiler, ok := targetConn.(filer)
+ if !ok {
+ return errors.Errorf("unknown target connection: %+v", targetConn)
+ }
+ targetConnFile, err := targetConnFiler.File()
+ if err != nil {
+ return err
+ }
+ oob := unix.UnixRights(int(targetConnFile.Fd()))
+ f, err := c.File()
+ if err != nil {
+ return err
+ }
+ err = unix.Sendmsg(int(f.Fd()), []byte("dummy"), oob, nil, 0)
+ return err
+}
+
+// filer is implemented by *net.TCPConn and *net.UDPConn
+type filer interface {
+ File() (f *os.File, err error)
+}