diff options
| author | Anton Lindqvist <anton@basename.se> | 2018-08-29 22:31:38 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-08-29 13:31:38 -0700 |
| commit | 14b78b9701cd103c1946aec8b6b1c9da0186a0b1 (patch) | |
| tree | 9b8860ce245b0c48de6b03bac305bb0c361b42c0 | |
| parent | 4937cb2bf08907e1d48044e6e53a22f62e3e8ac5 (diff) | |
vm/vmm: fix IP address detection
The IP address of a VM is calculated based on the formula 100.64.X.3 where X
being the ID of the VM, starting from 0. After starting 256 VMs 64 will flip
over to 65 and so on. A more robust solution to calculating the IP is to simply
read it from output during boot.
While here, stop using the VM ID as the identifier since the VM name also works.
| -rw-r--r-- | vm/vmm/vmm.go | 74 |
1 files changed, 38 insertions, 36 deletions
diff --git a/vm/vmm/vmm.go b/vm/vmm/vmm.go index acaf9b3b2..8d2ce5121 100644 --- a/vm/vmm/vmm.go +++ b/vm/vmm/vmm.go @@ -9,7 +9,7 @@ import ( "io" "os" "path/filepath" - "strconv" + "regexp" "strings" "time" @@ -48,11 +48,13 @@ type instance struct { sshhost string sshport int merger *vmimpl.OutputMerger - vmID int + vmName string stop chan bool diagnose chan string } +var ipRegex = regexp.MustCompile(`bound to (([0-9]+\.){3}3)`) + func ctor(env *vmimpl.Env) (vmimpl.Pool, error) { cfg := &Config{ Count: 1, @@ -106,6 +108,7 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { return nil, err } + name := fmt.Sprintf("syzkaller-%v-%v", pool.env.Name, index) inst := &instance{ cfg: pool.cfg, index: index, @@ -116,6 +119,7 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { sshkey: pool.env.SSHKey, sshuser: pool.env.SSHUser, sshport: 22, + vmName: name, stop: make(chan bool), diagnose: make(chan string), } @@ -135,25 +139,17 @@ func (pool *Pool) Create(workdir string, index int) (vmimpl.Instance, error) { } func (inst *instance) Boot() error { - name := fmt.Sprintf("syzkaller-%v", inst.index) mem := fmt.Sprintf("%vM", inst.cfg.Mem) startArgs := []string{ - "start", name, + "start", inst.vmName, "-t", inst.cfg.Template, "-b", inst.cfg.Kernel, "-d", inst.image, "-m", mem, } - startOut, err := inst.vmctl(startArgs...) - if err != nil { - return err - } - - inst.vmID, err = parseID(startOut) - if err != nil { + if _, err := inst.vmctl(startArgs...); err != nil { return err } - inst.sshhost = fmt.Sprintf("100.64.%v.3", inst.vmID) var tee io.Writer if inst.debug { @@ -167,7 +163,9 @@ func (inst *instance) Boot() error { var bootOutput []byte bootOutputStop := make(chan bool) + ipch := make(chan string, 1) go func() { + gotip := false for { select { case out := <-inst.merger.Output: @@ -176,9 +174,25 @@ func (inst *instance) Boot() error { bootOutputStop <- true return } + if gotip { + continue + } + if ip := parseIP(bootOutput); ip != "" { + ipch <- ip + gotip = true + } } }() + select { + case ip := <-ipch: + inst.sshhost = ip + case <-time.After(1 * time.Minute): + bootOutputStop <- true + <-bootOutputStop + return vmimpl.BootError{Title: "no IP found", Output: bootOutput} + } + if err := vmimpl.WaitForSSH(inst.debug, 2*time.Minute, inst.sshhost, inst.sshkey, inst.sshuser, inst.os, inst.sshport); err != nil { bootOutputStop <- true @@ -190,11 +204,15 @@ func (inst *instance) Boot() error { } func (inst *instance) Close() { - inst.vmctl("stop", inst.vmIdent(), "-f") + inst.vmctl("stop", inst.vmName, "-f") } func (inst *instance) Forward(port int) (string, error) { - addr := fmt.Sprintf("100.64.%v.2:%v", inst.vmID, port) + octets := strings.Split(inst.sshhost, ".") + if len(octets) < 3 { + return "", fmt.Errorf("too few octets in hostname %v", inst.sshhost) + } + addr := fmt.Sprintf("%v.%v.%v.2:%v", octets[0], octets[1], octets[2], port) return addr, nil } @@ -289,7 +307,7 @@ func (inst *instance) console() error { return err } - cmd := osutil.Command("vmctl", "console", inst.vmIdent()) + cmd := osutil.Command("vmctl", "console", inst.vmName) cmd.Stdin = inr cmd.Stdout = outw cmd.Stderr = outw @@ -351,26 +369,10 @@ func (inst *instance) vmctl(args ...string) (string, error) { return string(out), nil } -func (inst *instance) vmIdent() string { - return strconv.Itoa(inst.vmID) -} - -// Extract VM ID from vmctl start output. -func parseID(str string) (int, error) { - const prefix = "vmctl: started vm " - if !strings.HasPrefix(str, prefix) { - return 0, fmt.Errorf("could not extract ID from: %v", str) - } - fields := strings.Fields(str) - if len(fields) < 4 { - return 0, fmt.Errorf("could not extract ID from: %v", str) - } - i, err := strconv.Atoi(fields[3]) - if err != nil { - return 0, err - } - if i <= 0 { - return 0, fmt.Errorf("invalid ID: %v", i) +func parseIP(output []byte) string { + matches := ipRegex.FindSubmatch(output) + if len(matches) < 2 { + return "" } - return i, nil + return string(matches[1]) } |
