Sfoglia il codice sorgente

Merge pull request #27519 from justincormack/proxy-build

Build docker-proxy from git checkout like other external binaries
Alexander Morozov 8 anni fa
parent
commit
36f47aa252

+ 2 - 2
Dockerfile

@@ -222,10 +222,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
 	hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
 
-# Install tomlv, runc, containerd and grimes
+# Install tomlv, runc, containerd, grimes, docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
 
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
 ENTRYPOINT ["hack/dind"]

+ 2 - 2
Dockerfile.aarch64

@@ -165,10 +165,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
 	aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
 
-# Install tomlv, runc, containerd and grimes
+# Install tomlv, runc, containerd, grimes, docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
 
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
 ENTRYPOINT ["hack/dind"]

+ 2 - 2
Dockerfile.armhf

@@ -164,10 +164,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
 	armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
 
-# Install tomlv, runc, containerd and grimes
+# Install tomlv, runc, containerd, grimes, docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
 
 ENTRYPOINT ["hack/dind"]
 

+ 2 - 2
Dockerfile.ppc64le

@@ -183,10 +183,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
 	ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
 
-# Install tomlv, runc, containerd and grimes
+# Install tomlv, runc, containerd, grimes, docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
 
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
 ENTRYPOINT ["hack/dind"]

+ 2 - 2
Dockerfile.s390x

@@ -175,10 +175,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
 	s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
 
-# Install tomlv, runc, containerd and grimes
+# Install tomlv, runc, containerd, grimes, docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
 
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
 ENTRYPOINT ["hack/dind"]

+ 2 - 2
Dockerfile.simple

@@ -56,10 +56,10 @@ ENV PATH /go/bin:/usr/local/go/bin:$PATH
 ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
 ENV CGO_LDFLAGS -L/lib
 
-# Install runc, containerd and grimes
+# Install runc, containerd, grimes and docker-proxy
 # Please edit hack/dockerfile/install-binaries.sh to update them.
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
-RUN /tmp/install-binaries.sh runc containerd grimes
+RUN /tmp/install-binaries.sh runc containerd grimes proxy
 
 ENV AUTO_GOPATH 1
 WORKDIR /usr/src/docker

+ 0 - 3
hack/.vendor-helpers.sh

@@ -124,9 +124,6 @@ clean() {
 		findArgs+=( -path "vendor/src/$import" )
 	done
 
-	# The docker proxy command is built from libnetwork
-	findArgs+=( -or -path vendor/src/github.com/docker/libnetwork/cmd/proxy )
-
 	local IFS=$'\n'
 	local prune=( $($find vendor -depth -type d -not '(' "${findArgs[@]}" ')') )
 	unset IFS

+ 10 - 1
hack/dockerfile/install-binaries.sh

@@ -6,6 +6,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
 RUNC_COMMIT=02f8fa7863dd3f82909a73e2061897828460d52f
 CONTAINERD_COMMIT=52ef1ceb4b660c42cf4ea9013180a5663968d4c7
 GRIMES_COMMIT=74341e923bdf06cfb6b70cf54089c4d3ac87ec2d
+LIBNETWORK_COMMIT=0f534354b813003a754606689722fe253101bc4e
 
 export GOPATH="$(mktemp -d)"
 
@@ -66,8 +67,16 @@ do
 			cp init /usr/local/bin/docker-init
 			;;
 
+		proxy)
+			echo "Install docker-proxy version $LIBNETWORK_COMMIT"
+			git clone https://github.com/docker/libnetwork.git "$GOPATH/src/github.com/docker/libnetwork"
+			cd "$GOPATH/src/github.com/docker/libnetwork"
+			git checkout -q "$LIBNETWORK_COMMIT"
+			CGO_ENABLED=0 go build -v -o /usr/local/bin/docker-proxy github.com/docker/libnetwork/cmd/proxy
+			;;
+
 		*)
-			echo echo "Usage: $0 [tomlv|runc|containerd|grimes]"
+			echo echo "Usage: $0 [tomlv|runc|containerd|grimes|proxy]"
 			exit 1
 
 	esac

+ 1 - 1
hack/make.sh

@@ -257,7 +257,7 @@ copy_binaries() {
 	if [ "$(go env GOOS)/$(go env GOARCH)" == "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
 		if [ -x /usr/local/bin/docker-runc ]; then
 			echo "Copying nested executables into $dir"
-			for file in containerd containerd-shim containerd-ctr runc init; do
+			for file in containerd containerd-shim containerd-ctr runc init proxy; do
 				cp `which "docker-$file"` "$dir/"
 				if [ "$2" == "hash" ]; then
 					hash_files "$dir/docker-$file"

+ 2 - 1
hack/make/.build-deb/rules

@@ -24,11 +24,12 @@ override_dh_auto_install:
 	mkdir -p debian/docker-engine/usr/bin
 	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker
 	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd
-	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/docker-proxy)" debian/docker-engine/usr/bin/docker-proxy
+	cp -aT /usr/local/bin/docker-proxy debian/docker-engine/usr/bin/docker-proxy
 	cp -aT /usr/local/bin/docker-containerd debian/docker-engine/usr/bin/docker-containerd
 	cp -aT /usr/local/bin/docker-containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim
 	cp -aT /usr/local/bin/docker-containerd-ctr debian/docker-engine/usr/bin/docker-containerd-ctr
 	cp -aT /usr/local/bin/docker-runc debian/docker-engine/usr/bin/docker-runc
+	cp -aT /usr/local/bin/docker-init debian/docker-engine/usr/bin/docker-init
 	mkdir -p debian/docker-engine/usr/lib/docker
 
 override_dh_installinit:

+ 6 - 1
hack/make/.build-rpm/docker-engine.spec

@@ -126,7 +126,9 @@ export DOCKER_GITCOMMIT=%{_gitcommit}
 install -d $RPM_BUILD_ROOT/%{_bindir}
 install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker
 install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd
-install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/docker-proxy-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
+
+# install proxy
+install -p -m 755 /usr/local/bin/docker-proxy $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
 
 # install containerd
 install -p -m 755 /usr/local/bin/docker-containerd $RPM_BUILD_ROOT/%{_bindir}/docker-containerd
@@ -136,6 +138,9 @@ install -p -m 755 /usr/local/bin/docker-containerd-ctr $RPM_BUILD_ROOT/%{_bindir
 # install runc
 install -p -m 755 /usr/local/bin/docker-runc $RPM_BUILD_ROOT/%{_bindir}/docker-runc
 
+# install grimes
+install -p -m 755 /usr/local/bin/docker-init $RPM_BUILD_ROOT/%{_bindir}/docker-init
+
 # install udev rules
 install -d $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d
 install -p -m 644 contrib/udev/80-docker.rules $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d/80-docker.rules

+ 0 - 3
hack/make/binary-daemon

@@ -9,8 +9,5 @@ set -e
 	export BINARY_SHORT_NAME="$DOCKER_DAEMON_BINARY_NAME"
 	export SOURCE_PATH='./cmd/dockerd'
 	source "${MAKEDIR}/.binary"
-	export BINARY_SHORT_NAME="$DOCKER_PROXY_BINARY_NAME"
-	export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
-	source "${MAKEDIR}/.binary"
 	copy_binaries "$DEST" 'hash'
 )

+ 2 - 2
hack/make/build-deb

@@ -73,8 +73,8 @@ set -e
 		EOF
 
 		cat >> "$DEST/$version/Dockerfile.build" <<-EOF
-			# Install runc and containerd
-			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
+			# Install runc, containerd, proxy and grimes
+			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
 		EOF
 		cat >> "$DEST/$version/Dockerfile.build" <<-EOF
 			RUN cp -aL hack/make/.build-deb debian

+ 2 - 2
hack/make/build-rpm

@@ -93,8 +93,8 @@ set -e
 		EOF
 
 		cat >> "$DEST/$version/Dockerfile.build" <<-EOF
-			# Install runc and containerd
-			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
+			# Install runc, containerd, proxy and grimes
+			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
 		EOF
 		if [[ "$VERSION" == *-dev ]] || [ -n "$(git status --porcelain)" ]; then
 			echo 'ENV DOCKER_EXPERIMENTAL 1' >> "$DEST/$version/Dockerfile.build"

+ 0 - 4
hack/make/dynbinary-daemon

@@ -9,8 +9,4 @@ set -e
 	export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
 	export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
 	source "${MAKEDIR}/.binary"
-	export BINARY_SHORT_NAME='docker-proxy'
-	export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
-	export LDFLAGS_STATIC_DOCKER='-linkmode=external'
-	source "${MAKEDIR}/.binary"
 )

+ 0 - 67
vendor/src/github.com/docker/libnetwork/cmd/proxy/main.go

@@ -1,67 +0,0 @@
-package main
-
-import (
-	"flag"
-	"fmt"
-	"log"
-	"net"
-	"os"
-	"os/signal"
-	"syscall"
-)
-
-func main() {
-	f := os.NewFile(3, "signal-parent")
-	host, container := parseHostContainerAddrs()
-
-	p, err := NewProxy(host, container)
-	if err != nil {
-		fmt.Fprintf(f, "1\n%s", err)
-		f.Close()
-		os.Exit(1)
-	}
-	go handleStopSignals(p)
-	fmt.Fprint(f, "0\n")
-	f.Close()
-
-	// Run will block until the proxy stops
-	p.Run()
-}
-
-// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
-// net.Addrs to map the host and container ports
-func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
-	var (
-		proto         = flag.String("proto", "tcp", "proxy protocol")
-		hostIP        = flag.String("host-ip", "", "host ip")
-		hostPort      = flag.Int("host-port", -1, "host port")
-		containerIP   = flag.String("container-ip", "", "container ip")
-		containerPort = flag.Int("container-port", -1, "container port")
-	)
-
-	flag.Parse()
-
-	switch *proto {
-	case "tcp":
-		host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
-		container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
-	case "udp":
-		host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
-		container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
-	default:
-		log.Fatalf("unsupported protocol %s", *proto)
-	}
-
-	return host, container
-}
-
-func handleStopSignals(p Proxy) {
-	s := make(chan os.Signal, 10)
-	signal.Notify(s, os.Interrupt, syscall.SIGTERM)
-
-	for range s {
-		p.Close()
-
-		os.Exit(0)
-	}
-}

+ 0 - 37
vendor/src/github.com/docker/libnetwork/cmd/proxy/proxy.go

@@ -1,37 +0,0 @@
-// docker-proxy provides a network Proxy interface and implementations for TCP
-// and UDP.
-package main
-
-import (
-	"fmt"
-	"net"
-)
-
-// Proxy defines the behavior of a proxy. It forwards traffic back and forth
-// between two endpoints : the frontend and the backend.
-// It can be used to do software port-mapping between two addresses.
-// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
-// to the backend (container) at 172.17.42.108:4000.
-type Proxy interface {
-	// Run starts forwarding traffic back and forth between the front
-	// and back-end addresses.
-	Run()
-	// Close stops forwarding traffic and close both ends of the Proxy.
-	Close()
-	// FrontendAddr returns the address on which the proxy is listening.
-	FrontendAddr() net.Addr
-	// BackendAddr returns the proxied address.
-	BackendAddr() net.Addr
-}
-
-// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
-func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
-	switch frontendAddr.(type) {
-	case *net.UDPAddr:
-		return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
-	case *net.TCPAddr:
-		return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
-	default:
-		panic(fmt.Errorf("Unsupported protocol"))
-	}
-}

+ 0 - 31
vendor/src/github.com/docker/libnetwork/cmd/proxy/stub_proxy.go

@@ -1,31 +0,0 @@
-package main
-
-import (
-	"net"
-)
-
-// StubProxy is a proxy that is a stub (does nothing).
-type StubProxy struct {
-	frontendAddr net.Addr
-	backendAddr  net.Addr
-}
-
-// Run does nothing.
-func (p *StubProxy) Run() {}
-
-// Close does nothing.
-func (p *StubProxy) Close() {}
-
-// FrontendAddr returns the frontend address.
-func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
-
-// BackendAddr returns the backend address.
-func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
-
-// NewStubProxy creates a new StubProxy
-func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
-	return &StubProxy{
-		frontendAddr: frontendAddr,
-		backendAddr:  backendAddr,
-	}, nil
-}

+ 0 - 95
vendor/src/github.com/docker/libnetwork/cmd/proxy/tcp_proxy.go

@@ -1,95 +0,0 @@
-package main
-
-import (
-	"io"
-	"log"
-	"net"
-	"sync"
-	"syscall"
-)
-
-// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
-// handle TCP traffic forwarding between the frontend and backend addresses.
-type TCPProxy struct {
-	listener     *net.TCPListener
-	frontendAddr *net.TCPAddr
-	backendAddr  *net.TCPAddr
-}
-
-// NewTCPProxy creates a new TCPProxy.
-func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
-	listener, err := net.ListenTCP("tcp", frontendAddr)
-	if err != nil {
-		return nil, err
-	}
-	// If the port in frontendAddr was 0 then ListenTCP will have a picked
-	// a port to listen on, hence the call to Addr to get that actual port:
-	return &TCPProxy{
-		listener:     listener,
-		frontendAddr: listener.Addr().(*net.TCPAddr),
-		backendAddr:  backendAddr,
-	}, nil
-}
-
-func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
-	backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
-	if err != nil {
-		log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
-		client.Close()
-		return
-	}
-
-	var wg sync.WaitGroup
-	var broker = func(to, from *net.TCPConn) {
-		if _, err := io.Copy(to, from); err != nil {
-			// If the socket we are writing to is shutdown with
-			// SHUT_WR, forward it to the other end of the pipe:
-			if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE {
-				from.CloseWrite()
-			}
-		}
-		to.CloseRead()
-		wg.Done()
-	}
-
-	wg.Add(2)
-	go broker(client, backend)
-	go broker(backend, client)
-
-	finish := make(chan struct{})
-	go func() {
-		wg.Wait()
-		close(finish)
-	}()
-
-	select {
-	case <-quit:
-	case <-finish:
-	}
-	client.Close()
-	backend.Close()
-	<-finish
-}
-
-// Run starts forwarding the traffic using TCP.
-func (proxy *TCPProxy) Run() {
-	quit := make(chan bool)
-	defer close(quit)
-	for {
-		client, err := proxy.listener.Accept()
-		if err != nil {
-			log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
-			return
-		}
-		go proxy.clientLoop(client.(*net.TCPConn), quit)
-	}
-}
-
-// Close stops forwarding the traffic.
-func (proxy *TCPProxy) Close() { proxy.listener.Close() }
-
-// FrontendAddr returns the TCP address on which the proxy is listening.
-func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
-
-// BackendAddr returns the TCP proxied address.
-func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }

+ 0 - 168
vendor/src/github.com/docker/libnetwork/cmd/proxy/udp_proxy.go

@@ -1,168 +0,0 @@
-package main
-
-import (
-	"encoding/binary"
-	"log"
-	"net"
-	"strings"
-	"sync"
-	"syscall"
-	"time"
-)
-
-const (
-	// UDPConnTrackTimeout is the timeout used for UDP connection tracking
-	UDPConnTrackTimeout = 90 * time.Second
-	// UDPBufSize is the buffer size for the UDP proxy
-	UDPBufSize = 65507
-)
-
-// A net.Addr where the IP is split into two fields so you can use it as a key
-// in a map:
-type connTrackKey struct {
-	IPHigh uint64
-	IPLow  uint64
-	Port   int
-}
-
-func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
-	if len(addr.IP) == net.IPv4len {
-		return &connTrackKey{
-			IPHigh: 0,
-			IPLow:  uint64(binary.BigEndian.Uint32(addr.IP)),
-			Port:   addr.Port,
-		}
-	}
-	return &connTrackKey{
-		IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
-		IPLow:  binary.BigEndian.Uint64(addr.IP[8:]),
-		Port:   addr.Port,
-	}
-}
-
-type connTrackMap map[connTrackKey]*net.UDPConn
-
-// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
-// interface to handle UDP traffic forwarding between the frontend and backend
-// addresses.
-type UDPProxy struct {
-	listener       *net.UDPConn
-	frontendAddr   *net.UDPAddr
-	backendAddr    *net.UDPAddr
-	connTrackTable connTrackMap
-	connTrackLock  sync.Mutex
-}
-
-// NewUDPProxy creates a new UDPProxy.
-func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
-	listener, err := net.ListenUDP("udp", frontendAddr)
-	if err != nil {
-		return nil, err
-	}
-	return &UDPProxy{
-		listener:       listener,
-		frontendAddr:   listener.LocalAddr().(*net.UDPAddr),
-		backendAddr:    backendAddr,
-		connTrackTable: make(connTrackMap),
-	}, nil
-}
-
-func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
-	defer func() {
-		proxy.connTrackLock.Lock()
-		delete(proxy.connTrackTable, *clientKey)
-		proxy.connTrackLock.Unlock()
-		proxyConn.Close()
-	}()
-
-	readBuf := make([]byte, UDPBufSize)
-	for {
-		proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
-	again:
-		read, err := proxyConn.Read(readBuf)
-		if err != nil {
-			if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
-				// This will happen if the last write failed
-				// (e.g: nothing is actually listening on the
-				// proxied port on the container), ignore it
-				// and continue until UDPConnTrackTimeout
-				// expires:
-				goto again
-			}
-			return
-		}
-		for i := 0; i != read; {
-			written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
-			if err != nil {
-				return
-			}
-			i += written
-		}
-	}
-}
-
-// Run starts forwarding the traffic using UDP.
-func (proxy *UDPProxy) Run() {
-	readBuf := make([]byte, UDPBufSize)
-	for {
-		read, from, err := proxy.listener.ReadFromUDP(readBuf)
-		if err != nil {
-			// NOTE: Apparently ReadFrom doesn't return
-			// ECONNREFUSED like Read do (see comment in
-			// UDPProxy.replyLoop)
-			if !isClosedError(err) {
-				log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
-			}
-			break
-		}
-
-		fromKey := newConnTrackKey(from)
-		proxy.connTrackLock.Lock()
-		proxyConn, hit := proxy.connTrackTable[*fromKey]
-		if !hit {
-			proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
-			if err != nil {
-				log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
-				proxy.connTrackLock.Unlock()
-				continue
-			}
-			proxy.connTrackTable[*fromKey] = proxyConn
-			go proxy.replyLoop(proxyConn, from, fromKey)
-		}
-		proxy.connTrackLock.Unlock()
-		for i := 0; i != read; {
-			written, err := proxyConn.Write(readBuf[i:read])
-			if err != nil {
-				log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
-				break
-			}
-			i += written
-		}
-	}
-}
-
-// Close stops forwarding the traffic.
-func (proxy *UDPProxy) Close() {
-	proxy.listener.Close()
-	proxy.connTrackLock.Lock()
-	defer proxy.connTrackLock.Unlock()
-	for _, conn := range proxy.connTrackTable {
-		conn.Close()
-	}
-}
-
-// FrontendAddr returns the UDP address on which the proxy is listening.
-func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
-
-// BackendAddr returns the proxied UDP address.
-func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
-
-func isClosedError(err error) bool {
-	/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
-	 * See:
-	 * http://golang.org/src/pkg/net/net.go
-	 * https://code.google.com/p/go/issues/detail?id=4337
-	 * https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
-	 */
-	return strings.HasSuffix(err.Error(), "use of closed network connection")
-}