summaryrefslogtreecommitdiff
path: root/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp
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/parent/tcp
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/parent/tcp')
-rw-r--r--vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go104
1 files changed, 104 insertions, 0 deletions
diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go
new file mode 100644
index 000000000..b9f2d1802
--- /dev/null
+++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go
@@ -0,0 +1,104 @@
+package tcp
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "sync"
+
+ "github.com/rootless-containers/rootlesskit/pkg/port"
+ "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
+)
+
+func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
+ ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort))
+ if err != nil {
+ fmt.Fprintf(logWriter, "listen: %v\n", err)
+ return err
+ }
+ newConns := make(chan net.Conn)
+ go func() {
+ for {
+ c, err := ln.Accept()
+ if err != nil {
+ fmt.Fprintf(logWriter, "accept: %v\n", err)
+ close(newConns)
+ return
+ }
+ newConns <- c
+ }
+ }()
+ go func() {
+ defer ln.Close()
+ for {
+ select {
+ case c, ok := <-newConns:
+ if !ok {
+ return
+ }
+ go func() {
+ if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil {
+ fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err)
+ return
+ }
+ }()
+ case <-stopCh:
+ return
+ }
+ }
+ }()
+ // no wait
+ return nil
+}
+
+func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error {
+ defer c.Close()
+ // get fd from the child as an SCM_RIGHTS cmsg
+ fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10)
+ if err != nil {
+ return err
+ }
+ f := os.NewFile(uintptr(fd), "")
+ defer f.Close()
+ fc, err := net.FileConn(f)
+ if err != nil {
+ return err
+ }
+ defer fc.Close()
+ bicopy(c, fc, stopCh)
+ return nil
+}
+
+// bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go .
+// NOTE: sendfile(2) cannot be used for sockets
+func bicopy(x, y net.Conn, quit <-chan struct{}) {
+ var wg sync.WaitGroup
+ var broker = func(to, from net.Conn) {
+ io.Copy(to, from)
+ if fromTCP, ok := from.(*net.TCPConn); ok {
+ fromTCP.CloseRead()
+ }
+ if toTCP, ok := to.(*net.TCPConn); ok {
+ toTCP.CloseWrite()
+ }
+ wg.Done()
+ }
+
+ wg.Add(2)
+ go broker(x, y)
+ go broker(y, x)
+ finish := make(chan struct{})
+ go func() {
+ wg.Wait()
+ close(finish)
+ }()
+
+ select {
+ case <-quit:
+ case <-finish:
+ }
+ x.Close()
+ y.Close()
+ <-finish
+}