[libvirt] [PATCH 0/8] Enable NIC reporting to systemd

This series enables the QEMU and LXC drivers to report the network interface backends they use to systemd. This gets then shown to the user in # machinectl status lxc-shell lxc-shell(95449419f969d649d9962566ec42af7d) Since: Fri 2015-01-16 16:53:37 GMT; 3s ago Leader: 28085 (sh) Service: libvirt-lxc; class container Iface: vnet0 Address: fe80::216:3eff:fe00:c317%124 OS: Fedora 21 (Twenty One) Unit: machine-lxc\x2dshell.scope └─28085 /bin/sh but most fun is that if you add nss-mymachines to the /etc/nsswitch.conf, the machine names can now be used as hostnames. eg if your guest is 'lxc-shell' this lets you just do 'ssh lxc-shell' and it'll use the detected link local address to connect. Daniel P. Berrange (8): qemu: report TAP device indexes to systemd systemd: don't report an error if the guest is already terminated lxc: don't build pidfile string multiple times lxc: re-arrange startup synchronization sequence with controller lxc: only write XML once for lxc controller lxc: delay setup of cgroup until we have the init pid lxc: more logging during startup paths lxc: report veth device indexes to systemd src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 5 ++ src/lxc/lxc_cgroup.c | 15 +++--- src/lxc/lxc_cgroup.h | 5 +- src/lxc/lxc_container.c | 8 +++ src/lxc/lxc_controller.c | 116 ++++++++++++++++++++++++++++++++++++---- src/lxc/lxc_process.c | 134 +++++++++++++++++++++++++++-------------------- src/qemu/qemu_cgroup.c | 13 +++-- src/qemu/qemu_cgroup.h | 4 +- src/qemu/qemu_command.c | 27 ++++++++-- src/qemu/qemu_command.h | 7 ++- src/qemu/qemu_driver.c | 7 ++- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 9 +++- src/util/virsystemd.c | 25 +++++++-- tests/qemuxml2argvtest.c | 5 +- tests/qemuxmlnstest.c | 6 ++- 17 files changed, 288 insertions(+), 104 deletions(-) -- 2.1.0

Record the index of each TAP device created and report them to systemd, so they show up in machinectl status for the VM. --- src/qemu/qemu_cgroup.c | 13 ++++++++----- src/qemu/qemu_cgroup.h | 4 +++- src/qemu/qemu_command.c | 27 ++++++++++++++++++++++----- src/qemu/qemu_command.h | 7 +++++-- src/qemu/qemu_driver.c | 7 +++++-- src/qemu/qemu_hotplug.c | 4 +++- src/qemu/qemu_process.c | 9 +++++++-- tests/qemuxml2argvtest.c | 5 ++++- tests/qemuxmlnstest.c | 6 +++++- 9 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index d71ffbc..fc46450 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -727,7 +727,9 @@ qemuSetupCpuCgroup(virQEMUDriverPtr driver, static int qemuInitCgroup(virQEMUDriverPtr driver, - virDomainObjPtr vm) + virDomainObjPtr vm, + size_t nnicindexes, + int *nicindexes) { int ret = -1; qemuDomainObjPrivatePtr priv = vm->privateData; @@ -769,7 +771,7 @@ qemuInitCgroup(virQEMUDriverPtr driver, NULL, vm->pid, false, - 0, NULL, + nnicindexes, nicindexes, vm->def->resource->partition, cfg->cgroupControllers, &priv->cgroup) < 0) { @@ -855,7 +857,9 @@ qemuConnectCgroup(virQEMUDriverPtr driver, int qemuSetupCgroup(virQEMUDriverPtr driver, - virDomainObjPtr vm) + virDomainObjPtr vm, + size_t nnicindexes, + int *nicindexes) { qemuDomainObjPrivatePtr priv = vm->privateData; virCapsPtr caps = NULL; @@ -867,7 +871,7 @@ qemuSetupCgroup(virQEMUDriverPtr driver, return -1; } - if (qemuInitCgroup(driver, vm) < 0) + if (qemuInitCgroup(driver, vm, nnicindexes, nicindexes) < 0) return -1; if (!priv->cgroup) @@ -1023,7 +1027,6 @@ qemuSetupCgroupForVcpu(virDomainObjPtr vm) /* If we don't know VCPU<->PID mapping or all vcpu runs in the same * thread, we cannot control each vcpu. */ - VIR_WARN("Unable to get vcpus' pids."); return 0; } diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h index df7e3a1..a5d9c49 100644 --- a/src/qemu/qemu_cgroup.h +++ b/src/qemu/qemu_cgroup.h @@ -45,7 +45,9 @@ int qemuTeardownHostdevCgroup(virDomainObjPtr vm, int qemuConnectCgroup(virQEMUDriverPtr driver, virDomainObjPtr vm); int qemuSetupCgroup(virQEMUDriverPtr driver, - virDomainObjPtr vm); + virDomainObjPtr vm, + size_t nnicindexes, + int *nicindexes); int qemuSetupCpusetMems(virDomainObjPtr vm); int qemuSetupCgroupVcpuBW(virCgroupPtr cgroup, unsigned long long period, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index c041ee7..d50bec9 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -290,7 +290,8 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, virDomainNetDefPtr net, virQEMUCapsPtr qemuCaps, int *tapfd, - size_t *tapfdSize) + size_t *tapfdSize, + int *nicindex) { const char *brname; int ret = -1; @@ -331,6 +332,8 @@ qemuNetworkIfaceConnect(virDomainDefPtr def, virDomainAuditNetDevice(def, net, tunpath, false); goto cleanup; } + if (virNetDevGetIndex(net->ifname, nicindex) < 0) + goto cleanup; if (virDomainNetGetActualBridgeMACTableManager(net) == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) { /* libvirt is managing the FDB of the bridge this device @@ -7383,7 +7386,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, int vlan, int bootindex, virNetDevVPortProfileOp vmop, - bool standalone) + bool standalone, + int *nicindex) { int ret = -1; char *nic = NULL, *host = NULL; @@ -7397,6 +7401,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, virNetDevBandwidthPtr actualBandwidth; size_t i; + *nicindex = -1; + if (actualType == VIR_DOMAIN_NET_TYPE_VHOSTUSER) return qemuBuildVhostuserCommandLine(cmd, def, net, qemuCaps); @@ -7433,7 +7439,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd, memset(tapfd, -1, tapfdSize * sizeof(tapfd[0])); if (qemuNetworkIfaceConnect(def, conn, driver, net, - qemuCaps, tapfd, &tapfdSize) < 0) + qemuCaps, tapfd, + &tapfdSize, nicindex) < 0) goto cleanup; } else if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) { if (VIR_ALLOC(tapfd) < 0 || VIR_ALLOC(tapfdName) < 0) @@ -7788,7 +7795,9 @@ qemuBuildCommandLine(virConnectPtr conn, qemuBuildCommandLineCallbacksPtr callbacks, bool standalone, bool enableFips, - virBitmapPtr nodeset) + virBitmapPtr nodeset, + size_t *nnicindexes, + int **nicindexes) { virErrorPtr originalError = NULL; size_t i, j; @@ -7833,6 +7842,9 @@ qemuBuildCommandLine(virConnectPtr conn, virUUIDFormat(def->uuid, uuid); + *nnicindexes = 0; + *nicindexes = NULL; + emulator = def->emulator; if (!cfg->privileged) { @@ -8889,10 +8901,15 @@ qemuBuildCommandLine(virConnectPtr conn, else vlan = i; + if (VIR_EXPAND_N(*nicindexes, *nnicindexes, 1) < 0) + goto error; + if (qemuBuildInterfaceCommandLine(cmd, driver, conn, def, net, qemuCaps, vlan, bootNet, vmop, - standalone) < 0) + standalone, + &((*nicindexes)[*nnicindexes - 1])) < 0) goto error; + last_good_net = i; bootNet = 0; } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index dcc7127..7a670cc 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -82,7 +82,9 @@ virCommandPtr qemuBuildCommandLine(virConnectPtr conn, qemuBuildCommandLineCallbacksPtr callbacks, bool forXMLToArgv, bool enableFips, - virBitmapPtr nodeset) + virBitmapPtr nodeset, + size_t *nnicindexes, + int **nicindexes) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(11); /* Generate '-device' string for chardev device */ @@ -195,7 +197,8 @@ int qemuNetworkIfaceConnect(virDomainDefPtr def, virDomainNetDefPtr net, virQEMUCapsPtr qemuCaps, int *tapfd, - size_t *tapfdSize) + size_t *tapfdSize, + int *nicindex) ATTRIBUTE_NONNULL(2); int qemuPhysIfaceConnect(virDomainDefPtr def, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 9eed81d..b800555 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6310,6 +6310,8 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn, size_t i; virQEMUDriverConfigPtr cfg; virCapsPtr caps = NULL; + size_t nnicindexes = 0; + int *nicindexes = NULL; virCheckFlags(0, NULL); @@ -6495,13 +6497,14 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn, &buildCommandLineCallbacks, true, qemuCheckFips(), - NULL))) + NULL, + &nnicindexes, &nicindexes))) goto cleanup; ret = virCommandToString(cmd); cleanup: - + VIR_FREE(nicindexes); virObjectUnref(qemuCaps); virCommandFree(cmd); virDomainDefFree(def); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 6f62345..6b7d9b8 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -825,6 +825,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, qemuDomainObjPrivatePtr priv = vm->privateData; char **tapfdName = NULL; int *tapfd = NULL; + int nicindex = -1; size_t tapfdSize = 0; char **vhostfdName = NULL; int *vhostfd = NULL; @@ -894,7 +895,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, goto cleanup; memset(vhostfd, -1, sizeof(*vhostfd) * vhostfdSize); if (qemuNetworkIfaceConnect(vm->def, conn, driver, net, - priv->qemuCaps, tapfd, &tapfdSize) < 0) + priv->qemuCaps, tapfd, &tapfdSize, + &nicindex) < 0) goto cleanup; iface_connected = true; if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 2aa195f..da61e2b 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4270,6 +4270,8 @@ int qemuProcessStart(virConnectPtr conn, virQEMUDriverConfigPtr cfg; virCapsPtr caps = NULL; unsigned int hostdev_flags = 0; + size_t nnicindexes = 0; + int *nicindexes = NULL; VIR_DEBUG("vm=%p name=%s id=%d pid=%llu", vm, vm->def->name, vm->def->id, @@ -4589,7 +4591,8 @@ int qemuProcessStart(virConnectPtr conn, migrateFrom, stdin_fd, snapshot, vmop, &buildCommandLineCallbacks, false, qemuCheckFips(), - nodemask))) + nodemask, + &nnicindexes, &nicindexes))) goto cleanup; /* now that we know it is about to start call the hook if present */ @@ -4726,7 +4729,7 @@ int qemuProcessStart(virConnectPtr conn, } VIR_DEBUG("Setting up domain cgroup (if required)"); - if (qemuSetupCgroup(driver, vm) < 0) + if (qemuSetupCgroup(driver, vm, nnicindexes, nicindexes) < 0) goto cleanup; /* This must be done after cgroup placement to avoid resetting CPU @@ -4943,6 +4946,7 @@ int qemuProcessStart(virConnectPtr conn, VIR_FORCE_CLOSE(logfile); virObjectUnref(cfg); virObjectUnref(caps); + VIR_FREE(nicindexes); return 0; @@ -4958,6 +4962,7 @@ int qemuProcessStart(virConnectPtr conn, qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, stop_flags); virObjectUnref(cfg); virObjectUnref(caps); + VIR_FREE(nicindexes); return -1; } diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d1a95c5..8ef2173 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -279,6 +279,8 @@ static int testCompareXMLToArgvFiles(const char *xml, char *log = NULL; virCommandPtr cmd = NULL; size_t i; + size_t nnicindexes = 0; + int *nicindexes = NULL; if (!(conn = virGetConnect())) goto out; @@ -363,7 +365,7 @@ static int testCompareXMLToArgvFiles(const char *xml, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP, &testCallbacks, false, (flags & FLAG_FIPS), - NULL))) { + NULL, &nnicindexes, &nicindexes))) { if (!virtTestOOMActive() && (flags & FLAG_EXPECT_FAILURE)) { ret = 0; @@ -410,6 +412,7 @@ static int testCompareXMLToArgvFiles(const char *xml, ret = 0; out: + VIR_FREE(nicindexes); VIR_FREE(log); VIR_FREE(expectargv); VIR_FREE(actualargv); diff --git a/tests/qemuxmlnstest.c b/tests/qemuxmlnstest.c index 947aa9c..d76f078 100644 --- a/tests/qemuxmlnstest.c +++ b/tests/qemuxmlnstest.c @@ -44,6 +44,8 @@ static int testCompareXMLToArgvFiles(const char *xml, char *log = NULL; char *emulator = NULL; virCommandPtr cmd = NULL; + size_t nnicindexes = 0; + int *nicindexes = NULL; if (!(conn = virGetConnect())) goto fail; @@ -119,7 +121,8 @@ static int testCompareXMLToArgvFiles(const char *xml, vmdef, &monitor_chr, json, extraFlags, migrateFrom, migrateFd, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP, - &testCallbacks, false, false, NULL))) + &testCallbacks, false, false, NULL, + &nnicindexes, &nicindexes))) goto fail; if (!virtTestOOMActive()) { @@ -155,6 +158,7 @@ static int testCompareXMLToArgvFiles(const char *xml, ret = 0; fail: + VIR_FREE(nicindexes); VIR_FREE(log); VIR_FREE(emulator); VIR_FREE(expectargv); -- 2.1.0

In many cases where we invoke virSystemdTerminateMachine the process(es) will have already gone away on their own accord. In these cases we log an error message that the machine does not exist. We should catch this particular error and simply ignore it, so we don't pollute the logs. --- src/util/virsystemd.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c index 3eea5c2..29a2e63 100644 --- a/src/util/virsystemd.c +++ b/src/util/virsystemd.c @@ -340,18 +340,22 @@ int virSystemdTerminateMachine(const char *name, int ret; DBusConnection *conn; char *machinename = NULL; + DBusError error; + + dbus_error_init(&error); ret = virDBusIsServiceEnabled("org.freedesktop.machine1"); if (ret < 0) - return ret; + goto cleanup; if ((ret = virDBusIsServiceRegistered("org.freedesktop.systemd1")) < 0) - return ret; + goto cleanup; + + ret = -1; if (!(conn = virDBusGetSystemBus())) - return -1; + goto cleanup; - ret = -1; if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged))) goto cleanup; @@ -368,7 +372,7 @@ int virSystemdTerminateMachine(const char *name, VIR_DEBUG("Attempting to terminate machine via systemd"); if (virDBusCallMethod(conn, NULL, - NULL, + &error, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", @@ -377,9 +381,20 @@ int virSystemdTerminateMachine(const char *name, machinename) < 0) goto cleanup; + if (dbus_error_is_set(&error) && + !STREQ_NULLABLE("org.freedesktop.machine1.NoSuchMachine", + error.name)) { + virReportError(VIR_ERR_DBUS_SERVICE, + _("TerminateMachine: %s"), + error.message ? error.message : _("unknown error")); + goto cleanup; + } + ret = 0; cleanup: + dbus_error_free(&error); + VIR_FREE(machinename); return ret; } -- 2.1.0

On 16.01.2015 18:36, Daniel P. Berrange wrote:
In many cases where we invoke virSystemdTerminateMachine the process(es) will have already gone away on their own accord. In these cases we log an error message that the machine does not exist. We should catch this particular error and simply ignore it, so we don't pollute the logs. --- src/util/virsystemd.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c index 3eea5c2..29a2e63 100644 --- a/src/util/virsystemd.c +++ b/src/util/virsystemd.c @@ -340,18 +340,22 @@ int virSystemdTerminateMachine(const char *name, int ret; DBusConnection *conn; char *machinename = NULL; + DBusError error; + + dbus_error_init(&error);
This will suffer the same issue we already have in the code in virSystemdCreateMachine if libvirt is built without DBUS.
ret = virDBusIsServiceEnabled("org.freedesktop.machine1"); if (ret < 0) - return ret; + goto cleanup;
if ((ret = virDBusIsServiceRegistered("org.freedesktop.systemd1")) < 0) - return ret; + goto cleanup; + + ret = -1;
if (!(conn = virDBusGetSystemBus())) - return -1; + goto cleanup;
- ret = -1; if (!(machinename = virSystemdMakeMachineName(name, drivername, privileged))) goto cleanup;
@@ -368,7 +372,7 @@ int virSystemdTerminateMachine(const char *name, VIR_DEBUG("Attempting to terminate machine via systemd"); if (virDBusCallMethod(conn, NULL, - NULL, + &error, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", @@ -377,9 +381,20 @@ int virSystemdTerminateMachine(const char *name, machinename) < 0) goto cleanup;
+ if (dbus_error_is_set(&error) && + !STREQ_NULLABLE("org.freedesktop.machine1.NoSuchMachine", + error.name)) { + virReportError(VIR_ERR_DBUS_SERVICE, + _("TerminateMachine: %s"), + error.message ? error.message : _("unknown error")); + goto cleanup; + } + ret = 0;
cleanup: + dbus_error_free(&error); + VIR_FREE(machinename); return ret; }
Michal

On Thu, Jan 22, 2015 at 04:22:36PM +0100, Michal Privoznik wrote:
On 16.01.2015 18:36, Daniel P. Berrange wrote:
In many cases where we invoke virSystemdTerminateMachine the process(es) will have already gone away on their own accord. In these cases we log an error message that the machine does not exist. We should catch this particular error and simply ignore it, so we don't pollute the logs. --- src/util/virsystemd.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c index 3eea5c2..29a2e63 100644 --- a/src/util/virsystemd.c +++ b/src/util/virsystemd.c @@ -340,18 +340,22 @@ int virSystemdTerminateMachine(const char *name, int ret; DBusConnection *conn; char *machinename = NULL; + DBusError error; + + dbus_error_init(&error);
This will suffer the same issue we already have in the code in virSystemdCreateMachine if libvirt is built without DBUS.
Yep, this patch will need re-working once my other patch to change virDBusCallMethod to take a virErrorPtr is merged. I'll not push this series until after the release now, since it is a feature rather than bugfix Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Build the pidfile string once when starting a guest and then use the same string thereafter. This will benefit following patches which need the pidfile string in more situations. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_process.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 89e9249..6bdfe3d 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * Copyright IBM Corp. 2008 * * lxc_process.c: LXC process lifecycle management @@ -1015,6 +1015,7 @@ int virLXCProcessStart(virConnectPtr conn, virLXCDriverConfigPtr cfg = virLXCDriverGetConfig(driver); virCgroupPtr selfcgroup; int status; + char *pidfile = NULL; if (virCgroupNewSelf(&selfcgroup) < 0) return -1; @@ -1065,7 +1066,10 @@ int virLXCProcessStart(virConnectPtr conn, if (virAsprintf(&logfile, "%s/%s.log", cfg->logDir, vm->def->name) < 0) - return -1; + goto cleanup; + + if (!(pidfile = virPidFileBuildPath(cfg->stateDir, vm->def->name))) + goto cleanup; if (!(caps = virLXCDriverGetCapabilities(driver, false))) goto cleanup; @@ -1263,14 +1267,14 @@ int virLXCProcessStart(virConnectPtr conn, } /* And get its pid */ - if ((r = virPidFileRead(cfg->stateDir, vm->def->name, &vm->pid)) < 0) { + if ((r = virPidFileReadPath(pidfile, &vm->pid)) < 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) virReportError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), ebuf); else virReportSystemError(-r, - _("Failed to read pid file %s/%s.pid"), - cfg->stateDir, vm->def->name); + _("Failed to read pid file %s"), + pidfile); goto cleanup; } @@ -1389,6 +1393,7 @@ int virLXCProcessStart(virConnectPtr conn, VIR_FREE(ttyFDs); VIR_FORCE_CLOSE(handshakefds[0]); VIR_FORCE_CLOSE(handshakefds[1]); + VIR_FREE(pidfile); VIR_FREE(logfile); virObjectUnref(cfg); virObjectUnref(caps); -- 2.1.0

Currently the lxc controller process itself is responsible for daemonizing itself into the background and writing out its pid file. The lxc driver would fork the controller and then attempt to connect to the lxc monitor. This connection would only succeed after the controller has backgrounded itself, setup cgroups and written its pid file, so startup was race free. The problem is that we need to delay create of the cgroups to much later, such that we can tell systemd the container init pid when we create the cgroups. If we delay cgroup creation though the current synchronization won't work. A second problem is that the controller needs the XML config of the guest. Currently we write out the plain virDomainDefPtr XML before starting the controller, and then later replace it with the full virDomainObjPtr status XML. This is kind of gross and also means that the controller doesn't get a record of the live XML config right away. This means it doesn't have a record of the veth device names either and so can't give that info to systemd when creating the cgroups. To address this we change the startup sequencing. The goal is that we want to get the PID as soon as possible, before the LXC controller even starts. So we stop letting the LXC controller daemonize itself, and instead use virCommand's built-in capabilities. This daemonizes and writes the PID before LXC controller is exec'd. So the driver can read the PID as soon as virCommandRun returns. It is no longer safe to connect to the monitor or detect the cgroups though. Fortunately the LXC controller already has a second point of synchronization. Immediately before its event loop starts running, it performs a handshake with the driver. So we move the opening of the monitor connection and cgroup detection after this synchronization point. --- src/lxc/lxc_process.c | 88 +++++++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 6bdfe3d..764cdab 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -750,7 +750,9 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, size_t nttyFDs, int *files, size_t nfiles, - int handshakefd) + int handshakefd, + int logfd, + const char *pidfile) { size_t i; char *filterstr; @@ -812,12 +814,15 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virCommandAddArg(cmd, "--handshake"); virCommandAddArgFormat(cmd, "%d", handshakefd); - virCommandAddArg(cmd, "--background"); for (i = 0; i < nveths; i++) virCommandAddArgList(cmd, "--veth", veths[i], NULL); virCommandPassFD(cmd, handshakefd, 0); + virCommandDaemonize(cmd); + virCommandSetPidFile(cmd, pidfile); + virCommandSetOutputFD(cmd, &logfd); + virCommandSetErrorFD(cmd, &logfd); return cmd; cleanup: @@ -1189,10 +1194,10 @@ int virLXCProcessStart(virConnectPtr conn, nveths, veths, ttyFDs, nttyFDs, files, nfiles, - handshakefds[1]))) + handshakefds[1], + logfd, + pidfile))) goto cleanup; - virCommandSetOutputFD(cmd, &logfd); - virCommandSetErrorFD(cmd, &logfd); /* now that we know it is about to start call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { @@ -1245,28 +1250,7 @@ int virLXCProcessStart(virConnectPtr conn, goto cleanup; } - - if (VIR_CLOSE(handshakefds[1]) < 0) { - virReportSystemError(errno, "%s", _("could not close handshake fd")); - goto cleanup; - } - - /* Connect to the controller as a client *first* because - * this will block until the child has written their - * pid file out to disk & created their cgroup */ - if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) { - /* Intentionally overwrite the real monitor error message, - * since a better one is almost always found in the logs - */ - if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) { - virResetLastError(); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("guest failed to start: %s"), ebuf); - } - goto cleanup; - } - - /* And get its pid */ + /* It has started running, so get its pid */ if ((r = virPidFileReadPath(pidfile, &vm->pid)) < 0) { if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1278,26 +1262,17 @@ int virLXCProcessStart(virConnectPtr conn, goto cleanup; } - if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid, - vm->def->resource ? - vm->def->resource->partition : - NULL, - -1, &priv->cgroup) < 0) - goto error; - - if (!priv->cgroup) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("No valid cgroup for machine %s"), - vm->def->name); - goto error; - } - priv->stopReason = VIR_DOMAIN_EVENT_STOPPED_FAILED; priv->wantReboot = false; vm->def->id = vm->pid; virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); priv->doneStopEvent = false; + if (VIR_CLOSE(handshakefds[1]) < 0) { + virReportSystemError(errno, "%s", _("could not close handshake fd")); + goto error; + } + if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); @@ -1312,6 +1287,37 @@ int virLXCProcessStart(virConnectPtr conn, goto error; } + /* We know the cgroup must exist by this synchronization + * point so lets detect that first, since it gives us a + * more reliable way to kill everything off if something + * goes wrong from here onwards ... */ + if (virCgroupNewDetectMachine(vm->def->name, "lxc", vm->pid, + vm->def->resource ? + vm->def->resource->partition : + NULL, + -1, &priv->cgroup) < 0) + goto error; + + if (!priv->cgroup) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No valid cgroup for machine %s"), + vm->def->name); + goto error; + } + + /* And we can get the first monitor connection now too */ + if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) { + /* Intentionally overwrite the real monitor error message, + * since a better one is almost always found in the logs + */ + if (virLXCProcessReadLogOutput(vm, logfile, pos, ebuf, sizeof(ebuf)) > 0) { + virResetLastError(); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("guest failed to start: %s"), ebuf); + } + goto error; + } + if (autoDestroy && virCloseCallbacksSet(driver->closeCallbacks, vm, conn, lxcProcessAutoDestroy) < 0) -- 2.1.0

Currently when launching the LXC controller we first write out the plain, inactive XML configuration, then launch the controller, then replace the file with the live status XML configuration. By good fortune this hasn't caused any problems other than some misleading error messages during failure scenarios. This simplifies the code so it only writes out the XML once and always writes the live status XML. To do this we need to handshake with the child process, to make execution pause just before exec() so we can write the XML status with the child PID present. --- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 5 +++++ src/lxc/lxc_controller.c | 12 +++++++----- src/lxc/lxc_process.c | 33 ++++++++++++++++++++------------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8792f5e..aaea685 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -14634,7 +14634,7 @@ virDomainObjParseNode(xmlDocPtr xml, } -static virDomainObjPtr +virDomainObjPtr virDomainObjParseFile(const char *filename, virCapsPtr caps, virDomainXMLOptionPtr xmlopt, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 09ab194..563c18b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2489,6 +2489,11 @@ virDomainDefPtr virDomainDefParseNode(xmlDocPtr doc, virDomainXMLOptionPtr xmlopt, unsigned int expectedVirtTypes, unsigned int flags); +virDomainObjPtr virDomainObjParseFile(const char *filename, + virCapsPtr caps, + virDomainXMLOptionPtr xmlopt, + unsigned int expectedVirtTypes, + unsigned int flags); bool virDomainDefCheckABIStability(virDomainDefPtr src, virDomainDefPtr dst); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 53a2c8d..f2c0b57 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -100,6 +100,7 @@ typedef struct _virLXCController virLXCController; typedef virLXCController *virLXCControllerPtr; struct _virLXCController { char *name; + virDomainObjPtr vm; virDomainDefPtr def; int handshakeFd; @@ -175,11 +176,12 @@ static virLXCControllerPtr virLXCControllerNew(const char *name) ctrl->name)) == NULL) goto error; - if ((ctrl->def = virDomainDefParseFile(configFile, - caps, xmlopt, - 1 << VIR_DOMAIN_VIRT_LXC, - 0)) == NULL) + if ((ctrl->vm = virDomainObjParseFile(configFile, + caps, xmlopt, + 1 << VIR_DOMAIN_VIRT_LXC, + 0)) == NULL) goto error; + ctrl->def = ctrl->vm->def; if ((ctrl->timerShutdown = virEventAddTimeout(-1, virLXCControllerQuitTimer, ctrl, @@ -269,7 +271,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl) VIR_FREE(ctrl->devptmx); - virDomainDefFree(ctrl->def); + virObjectUnref(ctrl->vm); VIR_FREE(ctrl->name); if (ctrl->timerShutdown != -1) diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 764cdab..e2b2d30 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -823,6 +823,9 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virCommandSetPidFile(cmd, pidfile); virCommandSetOutputFD(cmd, &logfd); virCommandSetErrorFD(cmd, &logfd); + /* So we can pause before exec'ing the controller to + * write the live domain status XML with the PID */ + virCommandRequireHandshake(cmd); return cmd; cleanup: @@ -1171,10 +1174,6 @@ int virLXCProcessStart(virConnectPtr conn, if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) < 0) goto cleanup; - /* Save the configuration for the controller */ - if (virDomainSaveConfig(cfg->stateDir, vm->def) < 0) - goto cleanup; - if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { virReportSystemError(errno, @@ -1273,6 +1272,23 @@ int virLXCProcessStart(virConnectPtr conn, goto error; } + if (VIR_CLOSE(handshakefds[1]) < 0) { + virReportSystemError(errno, "%s", _("could not close handshake fd")); + goto error; + } + + if (virCommandHandshakeWait(cmd) < 0) + goto error; + + /* Write domain status to disk for the controller to + * read when it starts */ + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto error; + + /* Allow the child to exec the controller */ + if (virCommandHandshakeNotify(cmd) < 0) + goto error; + if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) driver->inhibitCallback(true, driver->inhibitOpaque); @@ -1330,15 +1346,6 @@ int virLXCProcessStart(virConnectPtr conn, /* We don't need the temporary NIC names anymore, clear them */ virLXCProcessCleanInterfaces(vm->def); - /* Write domain status to disk. - * - * XXX: Earlier we wrote the plain "live" domain XML to this - * location for the benefit of libvirt_lxc. We're now overwriting - * it with the live status XML instead. This is a (currently - * harmless) inconsistency we should fix one day */ - if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) - goto error; - /* finally we can call the 'started' hook script if any */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { char *xml = virDomainDefFormat(vm->def, 0); -- 2.1.0

Don't create the cgroups ahead of launching the container since there is no need for the limits to apply during initial bootstrap. Create the cgroup after the container PID is known and tell systemd the initpid is the leader, instead of the controller pid. --- src/lxc/lxc_cgroup.c | 11 +++-------- src/lxc/lxc_cgroup.h | 3 ++- src/lxc/lxc_controller.c | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 728e8e5..0987050 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -462,7 +462,8 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, } -virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def) +virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, + pid_t initpid) { virCgroupPtr cgroup = NULL; @@ -473,18 +474,12 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def) goto cleanup; } - /* - * XXX - * We should pass the PID of the LXC init process - * not ourselves, but this requires some more - * refactoring. We should also pass the root dir - */ if (virCgroupNewMachine(def->name, "lxc", true, def->uuid, NULL, - getpid(), + initpid, true, 0, NULL, def->resource->partition, diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h index 0e78126..31d6800 100644 --- a/src/lxc/lxc_cgroup.h +++ b/src/lxc/lxc_cgroup.h @@ -27,7 +27,8 @@ # include "lxc_fuse.h" # include "virusb.h" -virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def); +virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, + pid_t initpid); virCgroupPtr virLXCCgroupJoin(virDomainDefPtr def); int virLXCCgroupSetup(virDomainDefPtr def, virCgroupPtr cgroup, diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index f2c0b57..00d0e23 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -680,8 +680,9 @@ static int virLXCControllerGetNumadAdvice(virLXCControllerPtr ctrl, * virLXCControllerSetupResourceLimits * @ctrl: the controller state * - * Creates a cgroup for the container, moves the task inside, - * and sets resource limits + * Sets up the non-cgroup based resource limits that need + * to be inherited by the child process across clone()/exec(). + * The cgroup limits are setup later * * Returns 0 on success or -1 in case of error */ @@ -704,6 +705,37 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) if (virLXCControllerSetupCpuAffinity(ctrl) < 0) goto cleanup; + ret = 0; + cleanup: + virBitmapFree(auto_nodeset); + return ret; +} + + +/* + * Creates the cgroup and sets up the various limits associated + * with it + */ +static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr ctrl) +{ + virBitmapPtr auto_nodeset = NULL; + int ret = -1; + virBitmapPtr nodeset = NULL; + + VIR_DEBUG("Setting up cgroup resource limits"); + + if (virLXCControllerGetNumadAdvice(ctrl, &auto_nodeset) < 0) + goto cleanup; + + nodeset = virDomainNumatuneGetNodeset(ctrl->def->numatune, auto_nodeset, -1); + + if (!(ctrl->cgroup = virLXCCgroupCreate(ctrl->def, + ctrl->initpid))) + goto cleanup; + + if (virCgroupAddTask(ctrl->cgroup, getpid()) < 0) + goto cleanup; + if (virLXCCgroupSetup(ctrl->def, ctrl->cgroup, nodeset) < 0) goto cleanup; @@ -2224,6 +2256,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) for (i = 0; i < ctrl->npassFDs; i++) VIR_FORCE_CLOSE(ctrl->passFDs[i]); + if (virLXCControllerSetupCgroupLimits(ctrl) < 0) + goto cleanup; + if (virLXCControllerSetupUserns(ctrl) < 0) goto cleanup; @@ -2454,9 +2489,6 @@ int main(int argc, char *argv[]) if (virLXCControllerValidateConsoles(ctrl) < 0) goto cleanup; - if (!(ctrl->cgroup = virLXCCgroupCreate(ctrl->def))) - goto cleanup; - if (virLXCControllerSetupServer(ctrl) < 0) goto cleanup; -- 2.1.0

Add more logging to the lxc controller and container files to facilitate debugging startup problems. Also make it clear when the container is going to close stdout and thus no longer do any logging. --- src/lxc/lxc_container.c | 8 ++++++++ src/lxc/lxc_controller.c | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index e848e8e..cc20b6d 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -274,6 +274,10 @@ static int lxcContainerSetupFDs(int *ttyfd, size_t i; size_t j; + VIR_DEBUG("Logging from the container init will now cease " + "as the FDs are about to be closed for exec of " + "the container init process"); + if (setsid() < 0) { virReportSystemError(errno, "%s", _("setsid failed")); @@ -2250,6 +2254,7 @@ static int lxcContainerChild(void *data) if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0) goto cleanup; + VIR_DEBUG("Setting up inherited FDs"); VIR_FORCE_CLOSE(argv->handshakefd); VIR_FORCE_CLOSE(argv->monitor); if (lxcContainerSetupFDs(&ttyfd, @@ -2264,11 +2269,13 @@ static int lxcContainerChild(void *data) VIR_FORCE_CLOSE(argv->handshakefd); if (ret == 0) { + VIR_DEBUG("Executing init binary"); /* this function will only return if an error occurred */ ret = virCommandExec(cmd); } if (ret != 0) { + VIR_DEBUG("Tearing down container"); virErrorPtr err = virGetLastError(); if (err && err->message) fprintf(stderr, "%s\n", err->message); @@ -2379,6 +2386,7 @@ int lxcContainerStart(virDomainDefPtr def, cflags |= CLONE_NEWNET; } + VIR_DEBUG("Cloning container init process"); pid = clone(lxcContainerChild, stacktop, cflags, &args); VIR_FREE(stack); VIR_DEBUG("clone() completed, new container PID is %d", pid); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 00d0e23..03dff29 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -693,6 +693,8 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) virBitmapPtr nodeset = NULL; virDomainNumatuneMemMode mode; + VIR_DEBUG("Setting up process resource limits"); + if (virLXCControllerGetNumadAdvice(ctrl, &auto_nodeset) < 0) goto cleanup; @@ -1263,9 +1265,12 @@ static int virLXCControllerSetupUserns(virLXCControllerPtr ctrl) int ret = -1; /* User namespace is disabled for container */ - if (ctrl->def->idmap.nuidmap == 0) + if (ctrl->def->idmap.nuidmap == 0) { + VIR_DEBUG("No uid map, skipping userns setup"); return 0; + } + VIR_DEBUG("Setting up userns maps"); if (virAsprintf(&uid_map, "/proc/%d/uid_map", ctrl->initpid) < 0) goto cleanup; @@ -1866,9 +1871,12 @@ static int lxcSetPersonality(virDomainDefPtr def) { virArch altArch; + VIR_DEBUG("Checking for 32-bit personality"); altArch = lxcContainerGetAlt32bitArch(virArchFromHost()); if (altArch && (def->os.arch == altArch)) { + VIR_DEBUG("Setting personality to %s", + virArchToString(altArch)); if (personality(PER_LINUX32) < 0) { virReportSystemError(errno, _("Unable to request personality for %s on %s"), virArchToString(altArch), -- 2.1.0

Record the index of each host-side veth device created and report them to systemd, so they show up in machinectl status for the VM. lxc-shell(95449419f969d649d9962566ec42af7d) Since: Fri 2015-01-16 16:53:37 GMT; 3s ago Leader: 28085 (sh) Service: libvirt-lxc; class container Iface: vnet0 Address: fe80::216:3eff:fe00:c317%124 OS: Fedora 21 (Twenty One) Unit: machine-lxc\x2dshell.scope └─28085 /bin/sh --- src/lxc/lxc_cgroup.c | 6 ++++-- src/lxc/lxc_cgroup.h | 4 +++- src/lxc/lxc_controller.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 0987050..1dfa9a4 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -463,7 +463,9 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, - pid_t initpid) + pid_t initpid, + size_t nnicindexes, + int *nicindexes) { virCgroupPtr cgroup = NULL; @@ -481,7 +483,7 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, NULL, initpid, true, - 0, NULL, + nnicindexes, nicindexes, def->resource->partition, -1, &cgroup) < 0) diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h index 31d6800..e85f21c 100644 --- a/src/lxc/lxc_cgroup.h +++ b/src/lxc/lxc_cgroup.h @@ -28,7 +28,9 @@ # include "virusb.h" virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, - pid_t initpid); + pid_t initpid, + size_t nnicindexes, + int *nicindexes); virCgroupPtr virLXCCgroupJoin(virDomainDefPtr def); int virLXCCgroupSetup(virDomainDefPtr def, virCgroupPtr cgroup, diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 03dff29..8a7c7e8 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -110,6 +110,9 @@ struct _virLXCController { size_t nveths; char **veths; + size_t nnicindexes; + int *nicindexes; + size_t npassFDs; int *passFDs; @@ -260,6 +263,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl) for (i = 0; i < ctrl->nveths; i++) VIR_FREE(ctrl->veths[i]); VIR_FREE(ctrl->veths); + VIR_FREE(ctrl->nicindexes); for (i = 0; i < ctrl->npassFDs; i++) VIR_FORCE_CLOSE(ctrl->passFDs[i]); @@ -344,6 +348,51 @@ static int virLXCControllerValidateNICs(virLXCControllerPtr ctrl) } +static int virLXCControllerGetNICIndexes(virLXCControllerPtr ctrl) +{ + size_t i; + int ret = -1; + + VIR_DEBUG("Getting nic indexes"); + for (i = 0; i < ctrl->def->nnets; i++) { + int nicindex = -1; + switch (ctrl->def->nets[i]->type) { + case VIR_DOMAIN_NET_TYPE_BRIDGE: + case VIR_DOMAIN_NET_TYPE_NETWORK: + if (ctrl->def->nets[i]->ifname == NULL) + continue; + if (virNetDevGetIndex(ctrl->def->nets[i]->ifname, + &nicindex) < 0) + goto cleanup; + if (VIR_EXPAND_N(ctrl->nicindexes, + ctrl->nnicindexes, + 1) < 0) + goto cleanup; + VIR_DEBUG("Index %d for %s", nicindex, + ctrl->def->nets[i]->ifname); + ctrl->nicindexes[ctrl->nnicindexes-1] = nicindex; + break; + + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_VHOSTUSER: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_DIRECT: + case VIR_DOMAIN_NET_TYPE_HOSTDEV: + default: + break; + } + } + + ret = 0; + cleanup: + return ret; +} + + static int virLXCControllerValidateConsoles(virLXCControllerPtr ctrl) { if (ctrl->def->nconsoles != ctrl->nconsoles) { @@ -732,7 +781,9 @@ static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr ctrl) nodeset = virDomainNumatuneGetNodeset(ctrl->def->numatune, auto_nodeset, -1); if (!(ctrl->cgroup = virLXCCgroupCreate(ctrl->def, - ctrl->initpid))) + ctrl->initpid, + ctrl->nnicindexes, + ctrl->nicindexes))) goto cleanup; if (virCgroupAddTask(ctrl->cgroup, getpid()) < 0) @@ -2494,6 +2545,9 @@ int main(int argc, char *argv[]) if (virLXCControllerValidateNICs(ctrl) < 0) goto cleanup; + if (virLXCControllerGetNICIndexes(ctrl) < 0) + goto cleanup; + if (virLXCControllerValidateConsoles(ctrl) < 0) goto cleanup; -- 2.1.0

On 16.01.2015 18:36, Daniel P. Berrange wrote:
This series enables the QEMU and LXC drivers to report the network interface backends they use to systemd. This gets then shown to the user in
# machinectl status lxc-shell lxc-shell(95449419f969d649d9962566ec42af7d) Since: Fri 2015-01-16 16:53:37 GMT; 3s ago Leader: 28085 (sh) Service: libvirt-lxc; class container Iface: vnet0 Address: fe80::216:3eff:fe00:c317%124 OS: Fedora 21 (Twenty One) Unit: machine-lxc\x2dshell.scope └─28085 /bin/sh
but most fun is that if you add nss-mymachines to the /etc/nsswitch.conf, the machine names can now be used as hostnames.
eg if your guest is 'lxc-shell' this lets you just do 'ssh lxc-shell' and it'll use the detected link local address to connect.
Daniel P. Berrange (8): qemu: report TAP device indexes to systemd systemd: don't report an error if the guest is already terminated lxc: don't build pidfile string multiple times lxc: re-arrange startup synchronization sequence with controller lxc: only write XML once for lxc controller lxc: delay setup of cgroup until we have the init pid lxc: more logging during startup paths lxc: report veth device indexes to systemd
src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 5 ++ src/lxc/lxc_cgroup.c | 15 +++--- src/lxc/lxc_cgroup.h | 5 +- src/lxc/lxc_container.c | 8 +++ src/lxc/lxc_controller.c | 116 ++++++++++++++++++++++++++++++++++++---- src/lxc/lxc_process.c | 134 +++++++++++++++++++++++++++-------------------- src/qemu/qemu_cgroup.c | 13 +++-- src/qemu/qemu_cgroup.h | 4 +- src/qemu/qemu_command.c | 27 ++++++++-- src/qemu/qemu_command.h | 7 ++- src/qemu/qemu_driver.c | 7 ++- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 9 +++- src/util/virsystemd.c | 25 +++++++-- tests/qemuxml2argvtest.c | 5 +- tests/qemuxmlnstest.c | 6 ++- 17 files changed, 288 insertions(+), 104 deletions(-)
Looking good. ACK to all, but before pushing we should fix the issue I've raised in 2/8. Michal
participants (2)
-
Daniel P. Berrange
-
Michal Privoznik