[libvirt] [[PATCH v6] autocreate tap device for VIR_DOMAIN_NET_TYPE_ETHERNET] autocreate tap device for VIR_DOMAIN_NET_TYPE_ETHERNET
by Vasiliy Tolstov
If a user specify ehernet device create it via libvirt and run
script if it provided. After this commit user does not need to
run external script to create tap device or add root to qemu
process.
Signed-off-by: Vasiliy Tolstov <v.tolstov(a)selfip.ru>
---
src/qemu/qemu_command.c | 142 +++++++++++++++++++++++++++++++-----------------
src/qemu/qemu_hotplug.c | 13 ++---
src/qemu/qemu_process.c | 6 ++
3 files changed, 101 insertions(+), 60 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3886b4f..6d26d28 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -332,10 +332,39 @@ static int qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
return *tapfd < 0 ? -1 : 0;
}
+/**
+ * qemuExecuteEthernetScript:
+ * @ifname: the interface name
+ * @script: the script name
+ *
+ * This function executes script for new tap device created by libvirt.
+ * Returns 0 in case of success or -1 on failure
+ */
+static int
+qemuExecuteEthernetScript(const char *ifname, const char *script)
+{
+ virCommandPtr cmd;
+ int ret;
+
+ cmd = virCommandNew(script);
+ virCommandAddArgFormat(cmd, "%s", ifname);
+ virCommandClearCaps(cmd);
+#ifdef CAP_NET_ADMIN
+ virCommandAllowCap(cmd, CAP_NET_ADMIN);
+#endif
+ virCommandAddEnvPassCommon(cmd);
+
+ ret = virCommandRun(cmd, NULL);
+
+ virCommandFree(cmd);
+ return ret;
+}
+
/* qemuNetworkIfaceConnect - *only* called if actualType is
- * VIR_DOMAIN_NET_TYPE_NETWORK or VIR_DOMAIN_NET_TYPE_BRIDGE (i.e. if
- * the connection is made with a tap device connecting to a bridge
- * device)
+ * VIR_DOMAIN_NET_TYPE_NETWORK, VIR_DOMAIN_NET_TYPE_BRIDGE
+ * VIR_DOMAIN_NET_TYPE_ETHERNET (i.e. if the connection is
+ * made with a tap device connecting to a bridge device or
+ * use plain tap device)
*/
int
qemuNetworkIfaceConnect(virDomainDefPtr def,
@@ -351,6 +380,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
bool template_ifname = false;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
const char *tunpath = "/dev/net/tun";
+ virMacAddr tapmac;
if (net->backend.tap) {
tunpath = net->backend.tap;
@@ -361,11 +391,6 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
}
}
- if (!(brname = virDomainNetGetActualBridgeName(net))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
- goto cleanup;
- }
-
if (!net->ifname ||
STRPREFIX(net->ifname, VIR_NET_GENERATED_PREFIX) ||
strchr(net->ifname, '%')) {
@@ -381,40 +406,65 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
tap_create_flags |= VIR_NETDEV_TAP_CREATE_VNET_HDR;
}
- if (cfg->privileged) {
- if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
- def->uuid, tunpath, tapfd, *tapfdSize,
- virDomainNetGetActualVirtPortProfile(net),
- virDomainNetGetActualVlan(net),
- tap_create_flags) < 0) {
+ if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_ETHERNET) {
+ if (virNetDevTapCreate(&net->ifname, tunpath, tapfd, *tapfdSize,
+ tap_create_flags) < 0) {
virDomainAuditNetDevice(def, net, tunpath, false);
goto cleanup;
}
- if (virDomainNetGetActualBridgeMACTableManager(net)
- == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
- /* libvirt is managing the FDB of the bridge this device
- * is attaching to, so we need to turn off learning and
- * unicast_flood on the device to prevent the kernel from
- * adding any FDB entries for it. We will add add an fdb
- * entry ourselves (during qemuInterfaceStartDevices(),
- * using the MAC address from the interface config.
- */
- if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
- goto cleanup;
- if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
+ virMacAddrSet(&tapmac, &net->mac);
+
+ if (virNetDevSetMAC(net->ifname, &tapmac) < 0)
+ goto cleanup;
+
+ if (virNetDevSetOnline(net->ifname, true) < 0)
+ goto cleanup;
+
+ if (net->script) {
+ if (qemuExecuteEthernetScript(net->ifname, net->script) < 0)
goto cleanup;
}
} else {
- if (qemuCreateInBridgePortWithHelper(cfg, brname,
- &net->ifname,
- tapfd, tap_create_flags) < 0) {
- virDomainAuditNetDevice(def, net, tunpath, false);
+ if (!(brname = virDomainNetGetActualBridgeName(net))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing bridge name"));
goto cleanup;
}
- /* qemuCreateInBridgePortWithHelper can only create a single FD */
- if (*tapfdSize > 1) {
- VIR_WARN("Ignoring multiqueue network request");
- *tapfdSize = 1;
+
+ if (cfg->privileged) {
+ if (virNetDevTapCreateInBridgePort(brname, &net->ifname, &net->mac,
+ def->uuid, tunpath, tapfd, *tapfdSize,
+ virDomainNetGetActualVirtPortProfile(net),
+ virDomainNetGetActualVlan(net),
+ tap_create_flags) < 0) {
+ virDomainAuditNetDevice(def, net, tunpath, false);
+ goto cleanup;
+ }
+ if (virDomainNetGetActualBridgeMACTableManager(net)
+ == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
+ /* libvirt is managing the FDB of the bridge this device
+ * is attaching to, so we need to turn off learning and
+ * unicast_flood on the device to prevent the kernel from
+ * adding any FDB entries for it. We will add add an fdb
+ * entry ourselves (during qemuInterfaceStartDevices(),
+ * using the MAC address from the interface config.
+ */
+ if (virNetDevBridgePortSetLearning(brname, net->ifname, false) < 0)
+ goto cleanup;
+ if (virNetDevBridgePortSetUnicastFlood(brname, net->ifname, false) < 0)
+ goto cleanup;
+ }
+ } else {
+ if (qemuCreateInBridgePortWithHelper(cfg, brname,
+ &net->ifname,
+ tapfd, tap_create_flags) < 0) {
+ virDomainAuditNetDevice(def, net, tunpath, false);
+ goto cleanup;
+ }
+ /* qemuCreateInBridgePortWithHelper can only create a single FD */
+ if (*tapfdSize > 1) {
+ VIR_WARN("Ignoring multiqueue network request");
+ *tapfdSize = 1;
+ }
}
}
@@ -5221,6 +5271,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
case VIR_DOMAIN_NET_TYPE_DIRECT:
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
virBufferAsprintf(&buf, "tap%c", type_sep);
/* for one tapfd 'fd=' shall be used,
* for more than one 'fds=' is the right choice */
@@ -5238,20 +5289,6 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
is_tap = true;
break;
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- virBufferAddLit(&buf, "tap");
- if (net->ifname) {
- virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
- type_sep = ',';
- }
- if (net->script) {
- virBufferAsprintf(&buf, "%cscript=%s", type_sep,
- net->script);
- type_sep = ',';
- }
- is_tap = true;
- break;
-
case VIR_DOMAIN_NET_TYPE_CLIENT:
virBufferAsprintf(&buf, "socket%cconnect=%s:%d",
type_sep,
@@ -8226,7 +8263,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
/* Currently nothing besides TAP devices supports multiqueue. */
if (net->driver.virtio.queues > 0 &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Multiqueue network is not supported for: %s"),
virDomainNetTypeToString(actualType));
@@ -8235,7 +8273,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
if (net->backend.tap &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Custom tap device path is not supported for: %s"),
virDomainNetTypeToString(actualType));
@@ -8245,7 +8284,8 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
cfg = virQEMUDriverGetConfig(driver);
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
tapfdSize = net->driver.virtio.queues;
if (!tapfdSize)
tapfdSize = 1;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index cc86a3b..21ea3fd 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -908,7 +908,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
/* Currently nothing besides TAP devices supports multiqueue. */
if (net->driver.virtio.queues > 0 &&
!(actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
- actualType == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+ actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Multiqueue network is not supported for: %s"),
virDomainNetTypeToString(actualType));
@@ -916,7 +917,8 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
}
if (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE ||
- actualType == VIR_DOMAIN_NET_TYPE_NETWORK) {
+ actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
+ actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
tapfdSize = vhostfdSize = net->driver.virtio.queues;
if (!tapfdSize)
tapfdSize = vhostfdSize = 1;
@@ -947,13 +949,6 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
iface_connected = true;
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
goto cleanup;
- } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET) {
- vhostfdSize = 1;
- if (VIR_ALLOC(vhostfd) < 0)
- goto cleanup;
- *vhostfd = -1;
- if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, vhostfd, &vhostfdSize) < 0)
- goto cleanup;
}
/* Set device online immediately */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 64ee049..d866e44 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -5205,6 +5205,12 @@ void qemuProcessStop(virQEMUDriverPtr driver,
cfg->stateDir));
VIR_FREE(net->ifname);
break;
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (net->ifname) {
+ ignore_value(virNetDevTapDelete(net->ifname, net->backend.tap));
+ VIR_FREE(net->ifname);
+ }
+ break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
#ifdef VIR_NETDEV_TAP_REQUIRE_MANUAL_CLEANUP
--
2.3.3
9 years
[libvirt] [PATCH] [RFC] virSetUIDGID: Don't leak supplementary groups
by Richard Weinberger
The LXC driver uses virSetUIDGID() to become UID/GID 0.
It passes an empty groups list to virSetUIDGID()
to get rid of all supplementary groups from the host side.
But virSetUIDGID() calls setgroups() only if the supplied list
is larger than 0.
This leads to a container root with unrelated supplementary groups.
In most cases this issue is unoticed as libvirtd runs as UID/GID 0
without any supplementary groups.
Signed-off-by: Richard Weinberger <richard(a)nod.at>
---
I've marked that patch as RFC as I'm not sure if all users of virSetUIDGID()
expect this behavior too.
Thanks,
//richard
---
src/util/virutil.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/util/virutil.c b/src/util/virutil.c
index cddc78a..ea697a3 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -1103,7 +1103,7 @@ virSetUIDGID(uid_t uid, gid_t gid, gid_t *groups ATTRIBUTE_UNUSED,
}
# if HAVE_SETGROUPS
- if (ngroups && setgroups(ngroups, groups) < 0) {
+ if (setgroups(ngroups, groups) < 0) {
virReportSystemError(errno, "%s",
_("cannot set supplemental groups"));
return -1;
--
2.4.2
9 years
[libvirt] [PATCH] lxc: Bind mount container TTYs
by Richard Weinberger
Instead of creating symlinks, bind mount the devices to
/dev/pts/XY.
Using bind mounts it is no longer needed to add pts devices
to files like /dev/securetty.
Signed-off-by: Richard Weinberger <richard(a)nod.at>
---
src/lxc/lxc_container.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 7d531e2..ea76370 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1141,6 +1141,20 @@ static int lxcContainerMountFSDevPTS(virDomainDefPtr def,
return ret;
}
+static int lxcContainerBindMountDevice(const char *src, const char *dst)
+{
+ if (virFileTouch(dst, 0666) < 0)
+ return -1;
+
+ if (mount(src, dst, "none", MS_BIND, NULL) < 0) {
+ virReportSystemError(errno, _("Failed to bind %s on to %s"), src,
+ dst);
+ return -1;
+ }
+
+ return 0;
+}
+
static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths)
{
size_t i;
@@ -1164,34 +1178,24 @@ static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths)
}
/* We have private devpts capability, so bind that */
- if (virFileTouch("/dev/ptmx", 0666) < 0)
+ if (lxcContainerBindMountDevice("/dev/pts/ptmx", "/dev/ptmx") < 0)
return -1;
- if (mount("/dev/pts/ptmx", "/dev/ptmx", "ptmx", MS_BIND, NULL) < 0) {
- virReportSystemError(errno, "%s",
- _("Failed to bind /dev/pts/ptmx on to /dev/ptmx"));
- return -1;
- }
-
for (i = 0; i < nttyPaths; i++) {
char *tty;
if (virAsprintf(&tty, "/dev/tty%zu", i+1) < 0)
return -1;
- if (symlink(ttyPaths[i], tty) < 0) {
- virReportSystemError(errno,
- _("Failed to symlink %s to %s"),
- ttyPaths[i], tty);
- VIR_FREE(tty);
+
+ if (lxcContainerBindMountDevice(ttyPaths[i], tty) < 0) {
return -1;
+ VIR_FREE(tty);
}
+
VIR_FREE(tty);
+
if (i == 0 &&
- symlink(ttyPaths[i], "/dev/console") < 0) {
- virReportSystemError(errno,
- _("Failed to symlink %s to /dev/console"),
- ttyPaths[i]);
+ lxcContainerBindMountDevice(ttyPaths[i], "/dev/console") < 0)
return -1;
- }
}
return 0;
}
--
2.4.2
9 years
[libvirt] [PATCH] lxc: Don't make container's TTY a controlling TTY
by Richard Weinberger
Userspace does not expect that the initial console
is a controlling TTY. systemd can deal with that, others not.
On sysv init distros getty will fail to spawn a controlling on
/dev/console or /dev/tty1. Which will cause to whole container
to reboot upon ctrl-c.
This patch changes the behavior of libvirt to match the kernel
behavior where the initial TTY is also not controlling.
The only user visible change should be that a container with
bash as PID 1 would complain. But this matches exactly the kernel
be behavior with intit=/bin/bash.
To get a controlling TTY for bash just run "setsid /bin/bash".
Signed-off-by: Richard Weinberger <richard(a)nod.at>
---
src/lxc/lxc_container.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 11e9514..7d531e2 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -278,18 +278,6 @@ static int lxcContainerSetupFDs(int *ttyfd,
"as the FDs are about to be closed for exec of "
"the container init process");
- if (setsid() < 0) {
- virReportSystemError(errno, "%s",
- _("setsid failed"));
- goto cleanup;
- }
-
- if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) {
- virReportSystemError(errno, "%s",
- _("ioctl(TIOCSCTTY) failed"));
- goto cleanup;
- }
-
if (dup2(*ttyfd, STDIN_FILENO) < 0) {
virReportSystemError(errno, "%s",
_("dup2(stdin) failed"));
@@ -2210,7 +2198,7 @@ static int lxcContainerChild(void *data)
VIR_DEBUG("Container TTY path: %s", ttyPath);
- ttyfd = open(ttyPath, O_RDWR|O_NOCTTY);
+ ttyfd = open(ttyPath, O_RDWR);
if (ttyfd < 0) {
virReportSystemError(errno,
_("Failed to open tty %s"),
--
2.4.2
9 years
[libvirt] [PATCH] libxl: open libxl log stream with libvirtd log_level
by Jim Fehlig
Instead of a hardcoded DEBUG log level, use the overall
daemon log level specified in libvirtd.conf when opening
a log stream with libxl. libxl is very verbose when DEBUG
log level is set, resulting in huge log files that can
potentially fill a disk. Control of libxl verbosity should
be placed in the administrator's hands.
Signed-off-by: Jim Fehlig <jfehlig(a)suse.com>
---
src/libxl/libxl_conf.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index a76ad5a..40fa4b5 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -1496,6 +1496,7 @@ libxlDriverConfigNew(void)
{
libxlDriverConfigPtr cfg;
char *log_file = NULL;
+ xentoollog_level log_level;
char ebuf[1024];
unsigned int free_mem;
@@ -1540,9 +1541,24 @@ libxlDriverConfigNew(void)
}
VIR_FREE(log_file);
+ switch (virLogGetDefaultPriority()) {
+ case VIR_LOG_DEBUG:
+ log_level = XTL_DEBUG;
+ break;
+ case VIR_LOG_INFO:
+ log_level = XTL_INFO;
+ break;
+ case VIR_LOG_WARN:
+ log_level = XTL_WARN;
+ break;
+ case VIR_LOG_ERROR:
+ log_level = XTL_ERROR;
+ break;
+ }
+
cfg->logger =
(xentoollog_logger *)xtl_createlogger_stdiostream(cfg->logger_file,
- XTL_DEBUG, XTL_STDIOSTREAM_SHOW_DATE);
+ log_level, XTL_STDIOSTREAM_SHOW_DATE);
if (!cfg->logger) {
VIR_ERROR(_("cannot create logger for libxenlight, disabling driver"));
goto error;
--
2.5.0
9 years
[libvirt] Assert with libvirt + xen hvm
by CloudPatch Staff
We're hitting an assert whenever we try to create an HVM instance under Xen
via libvirtd.
System is running on Gentoo, package information as follows:
app-emulation/xen-4.5.0 USE="api debug flask hvm pam pygrub python qemu
screen"
app-emulation/xen-tools-4.5.0 USE="api debug flask hvm pam pygrub python
qemu screen"
app-emulation/libvirt-1.2.11-r2:0/1.2.11 USE="caps libvirtd lvm macvtap nls
qemu udev vepa virtualbox xen"
The following commands are run in parallel:
vmmachine ~ # libvirtd --listen
2015-01-22 16:33:13.596+0000: 2620: info : libvirt version: 1.2.11
2015-01-22 16:33:13.596+0000: 2620: error : udevGetDMIData:1607 : Failed to
get udev device for syspath '/sys/devices/virtual/dmi/id' or
'/sys/class/dmi/id'
libvirtd: libxl_fork.c:350: sigchld_installhandler_core: Assertion
`((void)"application must negotiate with libxl about SIGCHLD",
!(sigchld_saved_action.sa_flags & 4) &&
(sigchld_saved_action.__sigaction_handler.sa_handler == ((__sighandler_t)
0) || sigchld_saved_action.__sigaction_handler.sa_handler ==
((__sighandler_t) 1)))' failed.
Aborted
vmmachine ~ # VIRSH_DEBUG=0 virsh create xml
create: file(optdata): xml
libvirt: XML-RPC error : End of file while reading data: Input/output error
error: Failed to create domain from xml
error: End of file while reading data: Input/output error
libvirt: Domain Config error : Requested operation is not valid: A
different callback was requested
9 years
[libvirt] [PATCH] virsh: fix no error when pass a count <= 0 to setvcpus
by Luyao Huang
https://bugzilla.redhat.com/show_bug.cgi?id=1248277
When count <= 0, the client exit without set an error.
Signed-off-by: Luyao Huang <lhuang(a)redhat.com>
---
tools/virsh-domain.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index f7edeeb..b6da684 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -6744,8 +6744,12 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
- if (vshCommandOptInt(ctl, cmd, "count", &count) < 0 || count <= 0)
+ if (vshCommandOptInt(ctl, cmd, "count", &count) < 0)
goto cleanup;
+ if (count <= 0) {
+ vshError(ctl, _("Invalid value '%d' for number of virtual CPUs"), count);
+ goto cleanup;
+ }
/* none of the options were specified */
if (!current && flags == 0) {
--
1.8.3.1
9 years, 1 month
[libvirt] [PATCH v2] lxc: fuse mount for /proc/cpuinfo
by Cédric Bosdonnat
We already have a fuse mount to reflect the cgroup memory restrictions
in the container. This commit adds the same for the number of available
CPUs. Only the CPUs listed by virProcessGetAffinity are shown in the
container's cpuinfo.
---
src/lxc/lxc_container.c | 42 ++++++++++++-------
src/lxc/lxc_fuse.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 133 insertions(+), 15 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index a433552..7ae13a8 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -1055,24 +1055,38 @@ static int lxcContainerMountProcFuse(virDomainDefPtr def,
const char *stateDir)
{
int ret;
- char *meminfo_path = NULL;
+ char *src_path = NULL;
+ char *dst_path = NULL;
+ const char *paths[] = {"meminfo", "cpuinfo"};
+ size_t i;
- VIR_DEBUG("Mount /proc/meminfo stateDir=%s", stateDir);
+ for (i = 0; i < 2; i++) {
+ VIR_DEBUG("Mount /proc/%s stateDir=%s", paths[i], stateDir);
+
+ if ((ret = virAsprintf(&src_path,
+ "/.oldroot/%s/%s.fuse/%s",
+ stateDir,
+ def->name,
+ paths[i])) < 0)
+ return ret;
+
+ if ((ret = virAsprintf(&dst_path,
+ "/proc/%s",
+ paths[i])) < 0) {
+ VIR_FREE(src_path);
+ return ret;
+ }
- if ((ret = virAsprintf(&meminfo_path,
- "/.oldroot/%s/%s.fuse/meminfo",
- stateDir,
- def->name)) < 0)
- return ret;
+ if ((ret = mount(src_path, dst_path,
+ NULL, MS_BIND, NULL)) < 0) {
+ virReportSystemError(errno,
+ _("Failed to mount %s on %s"),
+ src_path, dst_path);
+ }
- if ((ret = mount(meminfo_path, "/proc/meminfo",
- NULL, MS_BIND, NULL)) < 0) {
- virReportSystemError(errno,
- _("Failed to mount %s on /proc/meminfo"),
- meminfo_path);
+ VIR_FREE(src_path);
+ VIR_FREE(dst_path);
}
-
- VIR_FREE(meminfo_path);
return ret;
}
#else
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 34a69cc..0d60434 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -42,6 +42,58 @@
#if WITH_FUSE
static const char *fuse_meminfo_path = "/meminfo";
+static const char *fuse_cpuinfo_path = "/cpuinfo";
+
+static virBufferPtr lxcProcComputeCpuinfo(void) {
+ FILE *fd = NULL;
+ char *line = NULL;
+ size_t n;
+ bool writeProc = false;
+ virBuffer buffer = VIR_BUFFER_INITIALIZER;
+ virBufferPtr new_cpuinfo = &buffer;
+ pid_t pid;
+ virBitmapPtr cpuAffinity = NULL;
+
+ fd = fopen("/proc/cpuinfo", "r");
+ if (fd == NULL) {
+ virReportSystemError(errno, "%s", _("Cannot open /proc/cpuinfo"));
+ goto error;
+ }
+
+ pid = getpid();
+ if (!(cpuAffinity = virProcessGetAffinity(pid)))
+ goto error;
+
+ while (getline(&line, &n, fd) > 0) {
+ if (STRPREFIX(line, "processor\t:")) {
+ unsigned long cpuid = 0;
+ char *suffix = NULL;
+ if (virStrToLong_ul(line + 12, &suffix, 10, &cpuid) < 0)
+ goto error;
+
+ if (virBitmapGetBit(cpuAffinity, cpuid, &writeProc) < 0)
+ goto error;
+ }
+
+ if (writeProc) {
+ virBufferAdd(new_cpuinfo, line, -1);
+
+ if (virBufferCheckError(new_cpuinfo) < 0)
+ goto error;
+ }
+ }
+
+ cleanup:
+ VIR_FREE(line);
+ VIR_FORCE_FCLOSE(fd);
+ virBitmapFree(cpuAffinity);
+ return new_cpuinfo;
+
+ error:
+ virBufferFreeAndReset(new_cpuinfo);
+ new_cpuinfo = NULL;
+ goto cleanup;
+}
static int lxcProcGetattr(const char *path, struct stat *stbuf)
{
@@ -50,6 +102,7 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
struct stat sb;
struct fuse_context *context = fuse_get_context();
virDomainDefPtr def = (virDomainDefPtr)context->private_data;
+ virBufferPtr cpuinfo = NULL;
memset(stbuf, 0, sizeof(struct stat));
if (virAsprintf(&mempath, "/proc/%s", path) < 0)
@@ -76,12 +129,36 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
stbuf->st_atime = sb.st_atime;
stbuf->st_ctime = sb.st_ctime;
stbuf->st_mtime = sb.st_mtime;
+ } else if (STREQ(path, fuse_cpuinfo_path)) {
+ if (!(cpuinfo = lxcProcComputeCpuinfo())) {
+ res = -EIO;
+ goto cleanup;
+ }
+
+ if (stat(mempath, &sb) < 0) {
+ res = -errno;
+ goto cleanup;
+ }
+
+ stbuf->st_uid = def->idmap.uidmap ? def->idmap.uidmap[0].target : 0;
+ stbuf->st_gid = def->idmap.gidmap ? def->idmap.gidmap[0].target : 0;
+ stbuf->st_mode = sb.st_mode;
+ stbuf->st_nlink = 1;
+ stbuf->st_blksize = sb.st_blksize;
+ stbuf->st_size = virBufferUse(cpuinfo);
+ stbuf->st_blocks = stbuf->st_size / 512;
+ if (stbuf->st_size % 512 != 0)
+ stbuf->st_blocks++;
+ stbuf->st_atime = sb.st_atime;
+ stbuf->st_ctime = sb.st_ctime;
+ stbuf->st_mtime = sb.st_mtime;
} else {
res = -ENOENT;
}
cleanup:
VIR_FREE(mempath);
+ virBufferFreeAndReset(cpuinfo);
return res;
}
@@ -96,6 +173,7 @@ static int lxcProcReaddir(const char *path, void *buf,
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, fuse_meminfo_path + 1, NULL, 0);
+ filler(buf, fuse_cpuinfo_path + 1, NULL, 0);
return 0;
}
@@ -103,7 +181,8 @@ static int lxcProcReaddir(const char *path, void *buf,
static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED,
struct fuse_file_info *fi ATTRIBUTE_UNUSED)
{
- if (!STREQ(path, fuse_meminfo_path))
+ if (!STREQ(path, fuse_meminfo_path) &&
+ !STREQ(path, fuse_cpuinfo_path))
return -ENOENT;
if ((fi->flags & 3) != O_RDONLY)
@@ -234,6 +313,28 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
return res;
}
+static int lxcProcReadCpuinfo(char *buf, size_t size, off_t offset)
+{
+ virBufferPtr new_cpuinfo = lxcProcComputeCpuinfo();
+ int new_size = -1;
+ int copied = -1;
+
+ if (!new_cpuinfo)
+ goto error;
+
+ copied = size;
+ new_size = virBufferUse(new_cpuinfo);
+
+ if ((new_size - offset) < size)
+ copied = new_size - offset;
+
+ memcpy(buf, virBufferCurrentContent(new_cpuinfo) + offset, copied);
+
+ error:
+ virBufferFreeAndReset(new_cpuinfo);
+ return copied;
+}
+
static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
char *buf ATTRIBUTE_UNUSED,
size_t size ATTRIBUTE_UNUSED,
@@ -254,6 +355,9 @@ static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
if (STREQ(path, fuse_meminfo_path)) {
if ((res = lxcProcReadMeminfo(hostpath, def, buf, size, offset)) < 0)
res = lxcProcHostRead(hostpath, buf, size, offset);
+ } else if (STREQ(path, fuse_cpuinfo_path)) {
+ if ((res = lxcProcReadCpuinfo(buf, size, offset)) < 0)
+ res = lxcProcHostRead(hostpath, buf, size, offset);
}
VIR_FREE(hostpath);
--
2.1.4
9 years, 1 month
[libvirt] [PATCHv3 0/2] Added waiting for DAD to finish for bridge address.
by Maxim Perevedentsev
This is a fix for commit db488c79173b240459c7754f38c3c6af9b432970
dnsmasq main process which is relied on when waiting for DAD to complete
exits without actually waiting for DAD. This is dnsmasq daemon's task.
It seems to be a race that DAD finished before dnsmasq main process exited.
The above commit needs the execution to block until DAD finishes
for bridge IPv6 address because then it closes dummy tap device.
Thus we need to ensure this ourselves.
So we periodically poll the kernel using netlink and
check whether there are any IPv6 addresses assigned to bridge
which have 'tentative' state. After DAD is finished, execution continues.
I guess that is what dnsmasq was assumed to do.
We use netlink to dump information about existing IPv6 addresses. Netlink's
response is a multi-part message. Unfortunately, the current implementation
of virNetlink treats such messages as faulty and throws an error. So the patch 2/2
adds multi-part nelink response support.
Update v2: fixed syntax.
Update v3: moved to virnetdev.
Resend: These patches were ignored and buried long ago :-(
Maxim Perevedentsev (2):
network: added waiting for DAD to finish for bridge address.
netlink: add support for multi-part netlink messages.
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 35 +++++++++-
src/util/virnetdev.c | 160 ++++++++++++++++++++++++++++++++++++++++++++
src/util/virnetdev.h | 2 +
src/util/virnetlink.c | 4 +-
5 files changed, 200 insertions(+), 2 deletions(-)
--
1.8.3.1
9 years, 1 month
[libvirt] [PATCH] docs: event impl. registration before hypervisor connection
by Dominik Perpeet
Event implementations need to be registered before a connection to the
Hypervisor is opened, otherwise event handling can be impaired (e.g.
delayed messages). This fact is referenced in an e-mail [1], but should
also be noted in the documentation of the registration functions.
[1] https://www.redhat.com/archives/libvirt-users/2014-April/msg00011.html
---
src/util/virevent.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/util/virevent.c b/src/util/virevent.c
index 54b6396..e0fd35e 100644
--- a/src/util/virevent.c
+++ b/src/util/virevent.c
@@ -204,6 +204,9 @@ virEventRemoveTimeout(int timer)
* to integrate with the libglib2 event loop, or libevent
* or the QT event loop.
*
+ * For proper event handling, it is important that the event implementation
+ * is registered before a connection to the Hypervisor is opened.
+ *
* Use of the virEventAddHandle() and similar APIs require that the
* corresponding handler is registered. Use of the
* virConnectDomainEventRegisterAny() and similar APIs requires that
@@ -247,6 +250,9 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle,
* not have a need to integrate with an external event
* loop impl.
*
+ * For proper event handling, it is important that the event implementation
+ * is registered before a connection to the Hypervisor is opened.
+ *
* Once registered, the application has to invoke virEventRunDefaultImpl() in
* a loop to process events. Failure to do so may result in connections being
* closed unexpectedly as a result of keepalive timeout. The default
--
1.8.3.1
9 years, 1 month