diff options
Diffstat (limited to 'bbot/agent/machine.cxx')
-rw-r--r-- | bbot/agent/machine.cxx | 148 |
1 files changed, 91 insertions, 57 deletions
diff --git a/bbot/agent/machine.cxx b/bbot/agent/machine.cxx index a7dc192..74c9b93 100644 --- a/bbot/agent/machine.cxx +++ b/bbot/agent/machine.cxx @@ -1,5 +1,5 @@ // file : bbot/agent/machine.cxx -*- C++ -*- -// license : TBC; see accompanying LICENSE file +// license : MIT; see accompanying LICENSE file #include <bbot/agent/machine.hxx> @@ -83,9 +83,9 @@ namespace bbot } static string - create_tap (const string& br, uint16_t port) + create_tap (const string& br, uint16_t machine_num, uint16_t port) { - string t ("tap" + to_string (offset)); + string t ("tap" + to_string (offset + machine_num)); tracer trace ("create_tap", t.c_str ()); @@ -126,8 +126,10 @@ namespace bbot string bridge; // Bridge interface to which this tap belongs uint16_t port; // UDP port to forward TFTP traffic to. - tap (string b, uint16_t p) - : iface (create_tap (b, p)), bridge (move (b)), port (p) {} + tap (string b, uint16_t machine_num, uint16_t p) + : iface (create_tap (b, machine_num, p)), + bridge (move (b)), + port (p) {} ~tap () { @@ -169,6 +171,9 @@ namespace bbot public: kvm_machine (const dir_path&, const machine_manifest&, + uint16_t machine_num, + size_t cpus, + size_t ram, const optional<string>& mac, const string& br_iface, uint16_t tftp_port, @@ -213,71 +218,69 @@ namespace bbot kvm_machine:: kvm_machine (const dir_path& md, const machine_manifest& mm, + uint16_t m_num, + size_t cpus, + size_t ram, const optional<string>& omac, const string& br, - uint16_t port, + uint16_t tftp_port, bool pub_vnc) : machine (mm.mac ? *mm.mac : // Fixed mac from machine manifest. omac ? *omac : // Generated mac from previous bootstrap. generate_mac ()), kvm ("kvm"), - net (br, port), - vnc (machine_vnc (pub_vnc)), + net (br, m_num, tftp_port), + vnc (machine_vnc (m_num, pub_vnc)), monitor ("/tmp/monitor-" + tc_name + '-' + to_string (inst)) { tracer trace ("kvm_machine", md.string ().c_str ()); + // Monitor path. + // + if (m_num != 0) + { + monitor += '-'; + monitor += to_string (m_num); + } + if (sizeof (sockaddr_un::sun_path) <= monitor.size ()) throw invalid_argument ("monitor unix socket path too long"); // Machine name. // // While we currently can only have one running machine per toolchain, add - // the instance number for debuggability. + // the instance number and non-0 machine number for debuggability. // string name (mm.name + '-' + tc_name + '-' + to_string (inst)); + if (m_num != 0) + { + name += '-'; + name += to_string (m_num); + } + // Machine log. Note that it is only removed with an explicit cleanup() // call. // log = path ("/tmp/" + path::traits_type::temp_name (name) + ".log"); - // Map logical CPUs to sockets/cores/threads keeping the number of and - // cores even. Failed that, QEMU just makes it a machine with that number - // of sockets and some operating systems (like Windows) can only do two. + // Map logical CPUs to sockets/cores/threads keeping the number of sockets + // and cores even. Failed that, QEMU just makes it a machine with that + // number of sockets and some operating systems (like Windows) can only do + // two. // // Note that for best results you may want to adjust (e.g., by over- // committing) the number of CPUs to be power of 2. // - size_t cpus (ops.cpu ()), cores (cpus); + size_t cores (cpus); - size_t sockets (cores >= 16 && cores % 4 == 0 ? 2 : - cores >= 64 && cores % 8 == 0 ? 4 : 1); + size_t sockets (cores >= 256 && cores % 8 == 0 ? 4 : + cores >= 128 && cores % 4 == 0 ? 2 : 1); cores /= sockets; - size_t threads (cores >= 8 && cores % 4 == 0 ? 2 : 1); + size_t threads (cores >= 16 && cores % 4 == 0 ? 2 : 1); cores /= threads; - // We probably don't want to commit all the available RAM to the VM since - // some of it could be used on the host side for caching, etc. So the - // heuristics that we will use is 4G or 1G per CPU, whichever is greater - // and the rest divide equally between the host and the VM. - // - // But the experience showed that we actually want to be able to precisely - // control the amount of RAM assigned to VMs (e.g., for tmpfs size) and - // without back-fudging for this heuristics. - // -#if 0 - size_t ram ((cpus < 4 ? 4 : cpus) * 1024 * 1024); // Kb. - - if (ram > ops.ram ()) - ram = ops.ram (); - else - ram += (ops.ram () - ram) / 2; -#else - size_t ram (ops.ram ()); -#endif - // If we have options, use that instead of the default network and // disk configuration. // @@ -309,11 +312,21 @@ namespace bbot } else { - auto add = [&os] (string o, string v) + // @@ TMP: libstud-optional issue #1. + // +#if 0 + auto add = [&os] (string o, optional<string> v = {}) { os.push_back (move (o)); - os.push_back (move (v)); + if (v) os.push_back (move (*v)); }; +#else + auto add = [&os] (string o, string v = {}) + { + os.push_back (move (o)); + if (!v.empty ()) os.push_back (move (v)); + }; +#endif // Network. // @@ -334,6 +347,17 @@ namespace bbot //"-drive", "if=none,id=disk0,format=raw,file=disk.img" //"-device", "virtio-scsi-pci,id=scsi" //"-device", "scsi-hd,drive=disk0" + + // USB settings. + // + // These options should make graphical VMs usable from VNC. + // + // Note that the "standard" USB bus may not be available on + // architectures other than x86 (e.g., aarch64). + // + add ("-usb"); + add ("-device", "usb-kbd"); + add ("-device", "usb-tablet"); } // Setup QMP (QEMU Machine Protocol) monitor to act as a log. @@ -373,6 +397,7 @@ namespace bbot 2, // 1>&2 (QMP goes to stdout) qmp_out, process_env (kvm, md, env), // Run from the machine's directory. + "-enable-kvm", "-name", name + ",debug-threads=on", "-S", // Start suspended. "-boot", "c", // Boot from disk. @@ -382,14 +407,10 @@ namespace bbot // RTC settings. // "-rtc", "clock=vm,driftfix=slew", +#ifdef __x86_64__ "-no-hpet", "-global", "kvm-pit.lost_tick_policy=discard", - - // USB settings. - // - // This option should make graphical VMs usable from VNC. - // - "-usb", "-device", "usb-tablet", +#endif // These can override the above but not below. // @@ -397,7 +418,7 @@ namespace bbot // RAM and CPU configuration. // - "-m", to_string (ram / 1024) + "M", + "-m", to_string (ram / 1024) + 'M', "-smp", (to_string (cpus) + ",sockets=" + to_string (sockets) + ",cores=" + to_string (cores) + @@ -413,7 +434,7 @@ namespace bbot // collision-wise with anything useful. // "-vnc", - (pub_vnc ? ":" : "127.0.0.1:") + to_string (offset), // 5900 + offset + (pub_vnc ? ":" : "127.0.0.1:") + to_string (offset + m_num), // 5900-base // QMP. // @@ -422,7 +443,7 @@ namespace bbot // Monitor. // - "-chardev", "socket,id=mon,path=" + monitor.string () + ",server,nowait", + "-chardev", "socket,id=mon,path=" + monitor.string () + ",server=on,wait=off", "-mon", "chardev=mon,mode=readline"); qmp_out.close (); @@ -441,7 +462,8 @@ namespace bbot } catch (const io_error& e) { - fail << "unable to initialize QMP: " << e; + fail << "unable to initialize QMP: " << e << + info << "see " << log; } // Start execution. @@ -452,7 +474,8 @@ namespace bbot } catch (const system_error& e) { - fail << "unable to communicate with qemu monitor: " << e; + fail << "unable to communicate with qemu monitor: " << e << + info << "see " << log; } } @@ -504,7 +527,8 @@ namespace bbot if (r) return true; - fail << "unable to communicate with qemu monitor: " << e; + fail << "unable to communicate with qemu monitor: " << e << + info << "see " << log; } return wait (seconds); @@ -525,7 +549,8 @@ namespace bbot if (wait (t, fh)) return; - fail (fh) << "unable to communicate with qemu monitor: " << e; + fail (fh) << "unable to communicate with qemu monitor: " << e << + info << "see " << log; } wait (fh); @@ -540,7 +565,8 @@ namespace bbot } catch (const system_error& e) { - fail (fh) << "unable to communicate with qemu monitor: " << e; + fail (fh) << "unable to communicate with qemu monitor: " << e << + info << "see " << log; } } @@ -575,7 +601,8 @@ namespace bbot } catch (const process_error& e) { - fail (fh) << "unable to wait for " << kvm << ": " << e << endf; + fail (fh) << "unable to wait for " << kvm << ": " << e << + info << "see " << log << endf; } } @@ -645,30 +672,37 @@ namespace bbot unique_ptr<machine> start_machine (const dir_path& md, const machine_manifest& mm, + uint16_t machine_num, + size_t cpus, + size_t ram, const optional<string>& mac, const string& br_iface, uint16_t tftp_port, bool pub_vnc) { + assert (machine_num < 10); + switch (mm.type) { case machine_type::kvm: return make_unique<kvm_machine> ( - md, mm, mac, br_iface, tftp_port, pub_vnc); + md, mm, machine_num, cpus, ram, mac, br_iface, tftp_port, pub_vnc); case machine_type::nspawn: - assert (false); //@@ TODO + assert (false); // @@ TODO } return nullptr; } string - machine_vnc (bool pub) + machine_vnc (uint16_t num, bool pub) { + assert (num < 10); + string r (pub ? hip : "127.0.0.1"); r += ':'; - r += to_string (5900 + offset); + r += to_string (5900 + offset + num); return r; } } |