aboutsummaryrefslogtreecommitdiffstats
path: root/vm
diff options
context:
space:
mode:
authorAnton Lindqvist <anton@basename.se>2018-08-29 22:31:38 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-08-29 13:31:38 -0700
commit14b78b9701cd103c1946aec8b6b1c9da0186a0b1 (patch)
tree9b8860ce245b0c48de6b03bac305bb0c361b42c0 /vm
parent4937cb2bf08907e1d48044e6e53a22f62e3e8ac5 (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.
Diffstat (limited to 'vm')
-rw-r--r--vm/vmm/vmm.go74
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])
}