From 6e89b036e2f4b99e64f34c49a4f62ccb1c124beb Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 23 Jul 2015 10:58:42 +0100 Subject: [PATCH] Wait for ethwe via netlink, not via polling or signals ('docker kill' breaks restart policy) --- Makefile | 3 +- net/if.go | 60 ++++++++++++++++++++++---------- prog/weaver/main.go | 4 +-- prog/weavewait/main.go | 17 ++------- proxy/create_exec_interceptor.go | 2 +- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index bd856c57..4950d11c 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,8 @@ $(NETCHECK_EXE): prog/netcheck/netcheck.go # Sigproxy and weavewait need separate rules as they fail the netgo check in # the main build stanza due to not importing net package $(SIGPROXY_EXE): prog/sigproxy/main.go -$(WEAVEWAIT_EXE): prog/weavewait/main.go +$(WEAVEWAIT_EXE): prog/weavewait/main.go net/*.go +$(WEAVEHOSTS_EXE): prog/weavehosts/weavehosts.go $(COVER_EXE): testing/cover/cover.go $(RUNNER_EXE): testing/runner/runner.go diff --git a/net/if.go b/net/if.go index 3cf3baab..1319dea7 100644 --- a/net/if.go +++ b/net/if.go @@ -2,30 +2,24 @@ package net import ( "fmt" - "math" "net" - "time" + "syscall" + + "github.com/vishvananda/netlink/nl" ) -const ( - sleepTime = 100 * time.Millisecond -) - -// Wait `wait` seconds for an interface to come up. Pass zero to check once -// and return immediately, or a negative value to wait indefinitely. -func EnsureInterface(ifaceName string, wait int) (iface *net.Interface, err error) { - if iface, err = findInterface(ifaceName); err == nil || wait == 0 { - return +// Wait for an interface to come up. +func EnsureInterface(ifaceName string) (*net.Interface, error) { + s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK) + if err != nil { + return nil, err } - i := int64(math.MaxInt64) - if wait > 0 { - i = int64(time.Duration(wait) * time.Second / sleepTime) + defer s.Close() + if iface, err := findInterface(ifaceName); err == nil { + return iface, nil } - for ; err != nil && i > 0; i-- { - time.Sleep(sleepTime) - iface, err = findInterface(ifaceName) - } - return + waitForIfUp(s, ifaceName) + return findInterface(ifaceName) } func findInterface(ifaceName string) (iface *net.Interface, err error) { @@ -37,3 +31,31 @@ func findInterface(ifaceName string) (iface *net.Interface, err error) { } return } + +func waitForIfUp(s *nl.NetlinkSocket, ifaceName string) error { + for { + msgs, err := s.Receive() + if err != nil { + return err + } + for _, m := range msgs { + switch m.Header.Type { + case syscall.RTM_NEWLINK: // receive this type for link 'up' + ifmsg := nl.DeserializeIfInfomsg(m.Data) + attrs, err := syscall.ParseNetlinkRouteAttr(&m) + if err != nil { + return err + } + name := "" + for _, attr := range attrs { + if attr.Attr.Type == syscall.IFA_LABEL { + name = string(attr.Value[:len(attr.Value)-1]) + } + } + if ifaceName == name && ifmsg.Flags&syscall.IFF_UP != 0 { + return nil + } + } + } + } +} diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 7c6c6f28..1ac9c315 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -43,7 +43,6 @@ func main() { routerName string nickName string password string - wait int pktdebug bool logLevel string prof string @@ -71,7 +70,6 @@ func main() { mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)") mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)") mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password") - mflag.IntVar(&wait, []string{"#wait", "-wait"}, -1, "number of seconds to wait for interface to come up (0=don't wait, -1=wait forever)") mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)") mflag.BoolVar(&pktdebug, []string{"#pktdebug", "#-pktdebug", "-pkt-debug"}, false, "enable per-packet debug logging") mflag.StringVar(&prof, []string{"#profile", "-profile"}, "", "enable profiling and write profiles to given path") @@ -118,7 +116,7 @@ func main() { var err error if ifaceName != "" { - config.Iface, err = weavenet.EnsureInterface(ifaceName, wait) + config.Iface, err = weavenet.EnsureInterface(ifaceName) if err != nil { Log.Fatal(err) } diff --git a/prog/weavewait/main.go b/prog/weavewait/main.go index c3adfafc..69315bb1 100644 --- a/prog/weavewait/main.go +++ b/prog/weavewait/main.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "os/exec" - "os/signal" "syscall" weavenet "github.com/weaveworks/weave/net" @@ -17,22 +16,10 @@ var ( func main() { var ( - args = os.Args[1:] - notInExec = true + args = os.Args[1:] ) - if len(args) > 0 && args[0] == "-s" { - notInExec = false - args = args[1:] - } - - if notInExec { - usr2 := make(chan os.Signal) - signal.Notify(usr2, syscall.SIGUSR2) - <-usr2 - } - - _, err := weavenet.EnsureInterface("ethwe", -1) + _, err := weavenet.EnsureInterface("ethwe") checkErr(err) if len(args) == 0 { diff --git a/proxy/create_exec_interceptor.go b/proxy/create_exec_interceptor.go index 9e7ea475..99bacafc 100644 --- a/proxy/create_exec_interceptor.go +++ b/proxy/create_exec_interceptor.go @@ -35,7 +35,7 @@ func (i *createExecInterceptor) InterceptRequest(r *http.Request) error { Log.Infof("Leaving container %s alone because %s", container.ID, err) } else if hasWeaveWait { Log.Infof("Exec in container %s with WEAVE_CIDR \"%s\"", container.ID, strings.Join(cidrs, " ")) - cmd := append(weaveWaitEntrypoint, "-s") + cmd := weaveWaitEntrypoint options.Cmd = append(cmd, options.Cmd...) }