aboutsummaryrefslogtreecommitdiff
path: root/bbot/agent/machine.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bbot/agent/machine.cxx')
-rw-r--r--bbot/agent/machine.cxx148
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;
}
}