From 6ebc17276e0e54626823d1982cccdb4eb8ec3c44 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 18 Dec 2019 18:36:41 +0900 Subject: [PATCH] slirp4netns: wait for ready FD to be written Signed-off-by: Akihiro Suda --- pkg/network/slirp4netns/slirp4netns.go | 50 +++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/pkg/network/slirp4netns/slirp4netns.go b/pkg/network/slirp4netns/slirp4netns.go index b13b2692..b31e0cfe 100644 --- a/pkg/network/slirp4netns/slirp4netns.go +++ b/pkg/network/slirp4netns/slirp4netns.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -116,7 +117,14 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. return nil, common.Seq(cleanups), errors.Wrapf(err, "setting up tap %s", tap) } ctx, cancel := context.WithCancel(context.Background()) - opts := []string{"--mtu", strconv.Itoa(d.mtu)} + readyR, readyW, err := os.Pipe() + if err != nil { + return nil, common.Seq(cleanups), err + } + defer readyR.Close() + defer readyW.Close() + // -r: readyFD + opts := []string{"--mtu", strconv.Itoa(d.mtu), "-r", "3"} if d.disableHostLoopback { opts = append(opts, "--disable-host-loopback") } @@ -136,6 +144,7 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGKILL, } + cmd.ExtraFiles = append(cmd.ExtraFiles, readyW) cleanups = append(cleanups, func() error { logrus.Debugf("killing slirp4netns") cancel() @@ -146,6 +155,10 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. if err := cmd.Start(); err != nil { return nil, common.Seq(cleanups), errors.Wrapf(err, "executing %v", cmd) } + + if err := waitForReadyFD(cmd.Process.Pid, readyR); err != nil { + return nil, common.Seq(cleanups), errors.Wrapf(err, "waiting for ready fd (%v)", cmd) + } netmsg := common.NetworkMessage{ Dev: tap, MTU: d.mtu, @@ -177,6 +190,41 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. return &netmsg, common.Seq(cleanups), nil } +// waitForReady is from libpod +// https://github.com/containers/libpod/blob/e6b843312b93ddaf99d0ef94a7e60ff66bc0eac8/libpod/networking_linux.go#L272-L308 +func waitForReadyFD(cmdPid int, r *os.File) error { + b := make([]byte, 16) + for { + if err := r.SetDeadline(time.Now().Add(1 * time.Second)); err != nil { + return errors.Wrapf(err, "error setting slirp4netns pipe timeout") + } + if _, err := r.Read(b); err == nil { + break + } else { + if os.IsTimeout(err) { + // Check if the process is still running. + var status syscall.WaitStatus + pid, err := syscall.Wait4(cmdPid, &status, syscall.WNOHANG, nil) + if err != nil { + return errors.Wrapf(err, "failed to read slirp4netns process status") + } + if pid != cmdPid { + continue + } + if status.Exited() { + return errors.New("slirp4netns failed") + } + if status.Signaled() { + return errors.New("slirp4netns killed by signal") + } + continue + } + return errors.Wrapf(err, "failed to read from slirp4netns sync pipe") + } + } + return nil +} + func NewChildDriver() network.ChildDriver { return &childDriver{} }