[libvirt] [PATCH RFC] storage: ZFS support
by Roman Bogorodskiy
Implement ZFS storage backend driver. Currently supported
only on FreeBSD because of ZFS limitations on Linux.
Features supported:
- pool-start, pool-stop
- pool-info
- vol-list
- vol-create / vol-delete
Pool definition looks like that:
<pool type='zfs'>
<name>myzfspool</name>
<source>
<name>actualpoolname</name>
</source>
</pool>
The 'actualpoolname' value is a name of the pool on the system,
such as shown by 'zpool list' command. Target makes no sense
here because volumes path is always /dev/zvol/$poolname/$volname.
Users has to create a pool on his own, this driver doesn't
support pool creation currently.
A volume could be used with Qemu by adding an entry like this:
<disk type='volume' device='disk'>
<driver name='qemu' type='raw'/>
<source pool='myzfspool' volume='vol5'/>
<target dev='hdc' bus='ide'/>
</disk>
---
configure.ac | 43 +++++
include/libvirt/libvirt.h.in | 1 +
po/POTFILES.in | 1 +
src/Makefile.am | 8 +
src/conf/storage_conf.c | 11 +-
src/conf/storage_conf.h | 4 +-
src/qemu/qemu_conf.c | 1 +
src/storage/storage_backend.c | 6 +
src/storage/storage_backend_zfs.c | 344 ++++++++++++++++++++++++++++++++++++++
src/storage/storage_backend_zfs.h | 29 ++++
src/storage/storage_driver.c | 1 +
tools/virsh-pool.c | 3 +
12 files changed, 449 insertions(+), 3 deletions(-)
create mode 100644 src/storage/storage_backend_zfs.c
create mode 100644 src/storage/storage_backend_zfs.h
diff --git a/configure.ac b/configure.ac
index f37c716..7e46460 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1734,6 +1734,10 @@ AC_ARG_WITH([storage-gluster],
[AS_HELP_STRING([--with-storage-gluster],
[with Gluster backend for the storage driver @<:@default=check@:>@])],
[],[with_storage_gluster=check])
+AC_ARG_WITH([storage-zfs],
+ [AS_HELP_STRING([--with-storage-zfs],
+ [with ZFS backend for the storage driver @<:@default=check@:>@])],
+ [],[with_storage_zfs=check])
if test "$with_libvirtd" = "no"; then
with_storage_dir=no
@@ -1746,6 +1750,7 @@ if test "$with_libvirtd" = "no"; then
with_storage_rbd=no
with_storage_sheepdog=no
with_storage_gluster=no
+ with_storage_zfs=no
fi
if test "$with_storage_dir" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
@@ -1963,6 +1968,43 @@ if test "$with_storage_gluster" = "yes"; then
fi
AM_CONDITIONAL([WITH_STORAGE_GLUSTER], [test "$with_storage_gluster" = "yes"])
+if test "$with_storage_zfs" = "check"; then
+ with_storage_zfs=$with_freebsd
+fi
+
+if test "$with_storage_zfs" = "yes" && test "$with_freebsd" = "no"; then
+ AC_MSG_ERROR([The ZFS storage driver can be enabled on FreeBSD only.])
+fi
+
+if test "$with_storage_zfs" = "yes" ||
+ test "$with_storage_zfs" = "check"; then
+ AC_PATH_PROG([ZFS], [zfs], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG([ZPOOL], [zpool], [], [$PATH:/sbin:/usr/sbin])
+
+ if test "$with_storage_zfs" = "yes"; then
+ if test -z "$ZFS" || test -z "$ZPOOL"; then
+ AC_MSG_ERROR([We need zfs and zpool for ZFS storage driver])
+ fi
+ else
+ if test -z "$ZFS" || test -z "$ZPOOL"; then
+ with_storage_zfs=no
+ fi
+
+ if test "$with_storage_zfs" = "check"; then
+ with_storage_zfs=yes
+ fi
+ fi
+
+ if test "$with_storage_zfs" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_STORAGE_ZFS], 1,
+ [whether ZFS backend for storage driver is enabled])
+ AC_DEFINE_UNQUOTED([ZFS], ["$ZFS"], [Location of zfs program])
+ AC_DEFINE_UNQUOTED([ZPOOL], ["$ZPOOL"], [Location of zpool program])
+ fi
+fi
+AM_CONDITIONAL([WITH_STORAGE_ZFS],
+ [test "$with_storage_zfs" = "yes"])
+
if test "$with_storage_fs" = "yes" ||
test "$with_storage_gluster" = "yes"; then
AC_PATH_PROG([GLUSTER_CLI], [gluster], [], [$PATH:/sbin:/usr/sbin])
@@ -2806,6 +2848,7 @@ AC_MSG_NOTICE([ Disk: $with_storage_disk])
AC_MSG_NOTICE([ RBD: $with_storage_rbd])
AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog])
AC_MSG_NOTICE([ Gluster: $with_storage_gluster])
+AC_MSG_NOTICE([ ZFS: $with_storage_zfs])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Security Drivers])
AC_MSG_NOTICE([])
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index ad6785f..47ea695 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3170,6 +3170,7 @@ typedef enum {
VIR_CONNECT_LIST_STORAGE_POOLS_RBD = 1 << 14,
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15,
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16,
+ VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17,
} virConnectListAllStoragePoolsFlags;
int virConnectListAllStoragePools(virConnectPtr conn,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d10e892..2646bcc 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -148,6 +148,7 @@ src/storage/storage_backend_mpath.c
src/storage/storage_backend_rbd.c
src/storage/storage_backend_scsi.c
src/storage/storage_backend_sheepdog.c
+src/storage/storage_backend_zfs.c
src/storage/storage_driver.c
src/test/test_driver.c
src/uml/uml_conf.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 982f63d..d5d06d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -862,6 +862,9 @@ STORAGE_DRIVER_SHEEPDOG_SOURCES = \
STORAGE_DRIVER_GLUSTER_SOURCES = \
storage/storage_backend_gluster.h storage/storage_backend_gluster.c
+STORAGE_DRIVER_ZFS_SOURCES = \
+ storage/storage_backend_zfs.h storage/storage_backend_zfs.c
+
STORAGE_HELPER_DISK_SOURCES = \
storage/parthelper.c
@@ -1514,6 +1517,10 @@ libvirt_driver_storage_impl_la_CFLAGS += $(GLUSTERFS_CFLAGS)
libvirt_driver_storage_impl_la_LIBADD += $(GLUSTERFS_LIBS)
endif WITH_STORAGE_GLUSTER
+if WITH_STORAGE_ZFS
+libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_ZFS_SOURCES)
+endif WITH_STORAGE_ZFS
+
if WITH_NODE_DEVICES
# Needed to keep automake quiet about conditionals
if WITH_DRIVER_MODULES
@@ -1723,6 +1730,7 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_RBD_SOURCES) \
$(STORAGE_DRIVER_SHEEPDOG_SOURCES) \
$(STORAGE_DRIVER_GLUSTER_SOURCES) \
+ $(STORAGE_DRIVER_ZFS_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index e33eb1b..5ec9c97 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -61,7 +61,8 @@ VIR_ENUM_IMPL(virStoragePool,
VIR_STORAGE_POOL_LAST,
"dir", "fs", "netfs",
"logical", "disk", "iscsi",
- "scsi", "mpath", "rbd", "sheepdog", "gluster")
+ "scsi", "mpath", "rbd",
+ "sheepdog", "gluster", "zfs")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
VIR_STORAGE_POOL_FS_LAST,
@@ -278,7 +279,13 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.formatFromString = virStorageVolFormatDiskTypeFromString,
.formatToString = virStorageVolFormatDiskTypeToString,
},
- }
+ },
+ {.poolType = VIR_STORAGE_POOL_ZFS,
+ .poolOptions = {
+ .flags = (VIR_STORAGE_POOL_SOURCE_NAME),
+ .defaultFormat = VIR_STORAGE_FILE_RAW,
+ },
+ },
};
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index ecd0dfe..1276ac2 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -92,6 +92,7 @@ typedef enum {
VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */
VIR_STORAGE_POOL_GLUSTER, /* Gluster device */
+ VIR_STORAGE_POOL_ZFS, /* ZFS */
VIR_STORAGE_POOL_LAST,
} virStoragePoolType;
@@ -509,7 +510,8 @@ VIR_ENUM_DECL(virStoragePartedFs)
VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \
VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \
- VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER)
+ VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER | \
+ VIR_CONNECT_LIST_STORAGE_POOLS_ZFS)
# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL \
(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE | \
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index e62bec0..1ed47a8 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1292,6 +1292,7 @@ qemuTranslateDiskSourcePool(virConnectPtr conn,
case VIR_STORAGE_POOL_LOGICAL:
case VIR_STORAGE_POOL_DISK:
case VIR_STORAGE_POOL_SCSI:
+ case VIR_STORAGE_POOL_ZFS:
if (!(def->src->path = virStorageVolGetPath(vol)))
goto cleanup;
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 27b02cb..aad913e 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -88,6 +88,9 @@
#if WITH_STORAGE_GLUSTER
# include "storage_backend_gluster.h"
#endif
+#if WITH_STORAGE_ZFS
+# include "storage_backend_zfs.h"
+#endif
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -125,6 +128,9 @@ static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_GLUSTER
&virStorageBackendGluster,
#endif
+#if WITH_STORAGE_ZFS
+ &virStorageBackendZFS,
+#endif
NULL
};
diff --git a/src/storage/storage_backend_zfs.c b/src/storage/storage_backend_zfs.c
new file mode 100644
index 0000000..1079bc7
--- /dev/null
+++ b/src/storage/storage_backend_zfs.c
@@ -0,0 +1,344 @@
+/*
+ * storage_backend_zfs.c: storage backend for ZFS handling
+ *
+ * Copyright (C) 2014 Roman Bogorodskiy
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "storage_backend_zfs.h"
+#include "virlog.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+VIR_LOG_INIT("storage.storage_backend_zfs");
+
+/*
+ * Some common flags of zfs and zpool commands we use:
+ * -H -- don't print headers and separate fields by tab
+ * -p -- show exact numbers instead of human-readable, i.e.
+ * for size, show just a number instead of 2G etc
+ */
+
+
+static int
+virStorageBackendZFSCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ bool *isActive)
+{
+ char *devpath;
+
+ if (virAsprintf(&devpath, "/dev/zvol/%s",
+ pool->def->source.name) == -1)
+ return -1;
+ *isActive = virFileIsDir(devpath);
+ VIR_FREE(devpath);
+
+ return 0;
+}
+
+static int
+virStorageBackendZFSStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int
+virStorageBackendZFSParseVol(virStoragePoolObjPtr pool,
+ const char *volume)
+{
+ int ret = -1;
+ char **tokens;
+ size_t count;
+ char **name_tokens = NULL;
+ char *vol_name;
+ bool is_new_vol = false;
+ virStorageVolDefPtr vol = NULL;
+
+ if (!(tokens = virStringSplitCount(volume, "\t", 0, &count)))
+ return -1;
+
+ if (count != 2)
+ goto cleanup;
+
+ if (!(name_tokens = virStringSplit(tokens[0], "/", 2)))
+ goto cleanup;
+
+ vol_name = name_tokens[1];
+
+ vol = virStorageVolDefFindByName(pool, vol_name);
+
+ if (vol == NULL) {
+ if (VIR_ALLOC(vol) < 0)
+ goto cleanup;
+
+ is_new_vol = true;
+ vol->type = VIR_STORAGE_VOL_BLOCK;
+
+ if (VIR_STRDUP(vol->name, vol_name) < 0)
+ goto cleanup;
+ }
+
+ if (!vol->key && VIR_STRDUP(vol->key, tokens[0]) < 0)
+ goto cleanup;
+
+ if (vol->target.path == NULL) {
+ if (virAsprintf(&vol->target.path, "/dev/zvol/%s/%s",
+ pool->def->source.name, vol->name) < 0)
+ goto cleanup;
+ }
+
+ if (virStrToLong_ull(tokens[1], NULL, 10, &vol->target.capacity) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed volsize reported"));
+ goto cleanup;
+ }
+
+ if (is_new_vol &&
+ VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virStringFreeList(tokens);
+ virStringFreeList(name_tokens);
+ if (is_new_vol && (ret == -1))
+ virStorageVolDefFree(vol);
+ return ret;
+}
+
+static int
+virStorageBackendZFSFindVols(virStoragePoolObjPtr pool)
+{
+ virCommandPtr cmd = NULL;
+ char *volumes_list = NULL;
+ char **lines = NULL;
+ size_t i;
+
+ /**
+ * $ zfs list -Hp -t volume -o name,volsize -r test
+ * test/vol1 5368709120
+ * test/vol3 1073741824
+ * test/vol4 1572864000
+ * $
+ *
+ * Arguments description:
+ * -t volume -- we want to see only volumes
+ * -o name,volsize -- limit output to name and volume size
+ * -r -- we want to see all the childer of our pool
+ */
+ cmd = virCommandNewArgList(ZFS,
+ "list", "-Hp",
+ "-t", "volume", "-r",
+ "-o", "name,volsize",
+ pool->def->source.name,
+ NULL);
+ virCommandSetOutputBuffer(cmd, &volumes_list);
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ if (!(lines = virStringSplit(volumes_list, "\n", 0)))
+ goto cleanup;
+
+ for (i = 0; lines[i]; i++) {
+ if (STREQ(lines[i], ""))
+ continue;
+
+ if (virStorageBackendZFSParseVol(pool, lines[i]) < 0)
+ continue;
+ }
+
+ cleanup:
+ virCommandFree(cmd);
+ virStringFreeList(lines);
+ VIR_FREE(volumes_list);
+
+ return 0;
+}
+
+static int
+virStorageBackendZFSRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
+{
+ virCommandPtr cmd = NULL;
+ char *zpool_props = NULL;
+ char **lines = NULL;
+ size_t i;
+
+ /**
+ * $ zpool get -Hp health,size,free,allocated test
+ * test health ONLINE -
+ * test size 199715979264 -
+ * test free 198899976704 -
+ * test allocated 816002560 -
+ * $
+ *
+ * Here we just provide a list of properties we want to see
+ */
+ cmd = virCommandNewArgList(ZPOOL,
+ "get", "-Hp",
+ "health,size,free,allocated",
+ pool->def->source.name,
+ NULL);
+ virCommandSetOutputBuffer(cmd, &zpool_props);
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ if (!(lines = virStringSplit(zpool_props, "\n", 0)))
+ goto cleanup;
+
+ for (i = 0; lines[i]; i++) {
+ char **tokens;
+ size_t count;
+ char *prop_name;
+
+ if (STREQ(lines[i], ""))
+ continue;
+
+ if (!(tokens = virStringSplitCount(lines[i], "\t", 0, &count)))
+ goto cleanup;
+
+ if (count != 4)
+ continue;
+
+ prop_name = tokens[1];
+
+ if (STREQ(prop_name, "free") || STREQ(prop_name, "size") ||
+ STREQ(prop_name, "allocated")) {
+ unsigned long long value;
+ if (virStrToLong_ull(tokens[2], NULL, 10, &value) < 0)
+ goto cleanup;
+
+ if (STREQ(prop_name, "free"))
+ pool->def->available = value;
+ else if (STREQ(prop_name, "size"))
+ pool->def->capacity = value;
+ else if (STREQ(prop_name, "allocated"))
+ pool->def->allocation = value;
+ }
+ }
+
+ /* Obtain a list of volumes */
+ if (virStorageBackendZFSFindVols(pool) < 0)
+ goto cleanup;
+
+ cleanup:
+ virCommandFree(cmd);
+ virStringFreeList(lines);
+ VIR_FREE(zpool_props);
+
+ return 0;
+}
+
+static int
+virStorageBackendZFSStopPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int
+virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ virCommandPtr cmd = NULL;
+ int ret = -1;
+
+ vol->type = VIR_STORAGE_VOL_BLOCK;
+
+ if (vol->target.path != NULL) {
+ /* A target path passed to CreateVol has no meaning */
+ VIR_FREE(vol->target.path);
+ }
+
+ if (virAsprintf(&vol->target.path, "/dev/zvol/%s/%s",
+ pool->def->source.name, vol->name) == -1)
+ return -1;
+
+ /**
+ * $ zfs create -o volmode=dev -V 10240K test/volname
+ *
+ * -o volmode=dev -- we want to get volumes exposed as cdev
+ * devices. If we don't specify that zfs
+ * will lookup vfs.zfs.vol.mode sysctl value
+ * -V -- tells to create a volume with the specified size
+ */
+ cmd = virCommandNewArgList(ZFS, "create", "-o", "volmode=dev",
+ "-V", NULL);
+ virCommandAddArgFormat(cmd, "%lluK",
+ VIR_DIV_UP(vol->target.capacity, 1024));
+ virCommandAddArgFormat(cmd, "%s/%s",
+ pool->def->source.name, vol->name);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&vol->key, "%s/%s",
+ pool->def->source.name, vol->name) == -1)
+ goto cleanup;
+
+ if (virStorageBackendZFSFindVols(pool) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virCommandFree(cmd);
+ return ret;
+
+}
+
+static int
+virStorageBackendZFSDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int flags)
+{
+ int ret = -1;
+ virCommandPtr destroy_cmd = virCommandNewArgList(ZFS, "destroy", NULL);
+
+ virCheckFlags(0, -1);
+
+ virCommandAddArgFormat(destroy_cmd, "%s/%s",
+ pool->def->source.name, vol->name);
+
+ if (virCommandRun(destroy_cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ virCommandFree(destroy_cmd);
+ return ret;
+}
+
+
+virStorageBackend virStorageBackendZFS = {
+ .type = VIR_STORAGE_POOL_ZFS,
+
+ .checkPool = virStorageBackendZFSCheckPool,
+ .startPool = virStorageBackendZFSStartPool,
+ .refreshPool = virStorageBackendZFSRefreshPool,
+ .stopPool = virStorageBackendZFSStopPool,
+ .createVol = virStorageBackendZFSCreateVol,
+ .deleteVol = virStorageBackendZFSDeleteVol,
+};
diff --git a/src/storage/storage_backend_zfs.h b/src/storage/storage_backend_zfs.h
new file mode 100644
index 0000000..4c34b59
--- /dev/null
+++ b/src/storage/storage_backend_zfs.h
@@ -0,0 +1,29 @@
+/*
+ * storage_backend_zfs.h: storage backend for ZFS handling
+ *
+ * Copyright (C) 2014 Roman Bogorodskiy
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_ZFS_H__
+# define __VIR_STORAGE_BACKEND_ZFS_H__
+
+# include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendZFS;
+
+#endif /* __VIR_STORAGE_BACKEND_ZFS_H__ */
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index 3830867..d23d663 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -1431,6 +1431,7 @@ storageVolLookupByPath(virConnectPtr conn,
case VIR_STORAGE_POOL_GLUSTER:
case VIR_STORAGE_POOL_RBD:
case VIR_STORAGE_POOL_SHEEPDOG:
+ case VIR_STORAGE_POOL_ZFS:
case VIR_STORAGE_POOL_LAST:
if (VIR_STRDUP(stable_path, path) < 0) {
virStoragePoolObjUnlock(pool);
diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c
index 7c40b5b..80313b1 100644
--- a/tools/virsh-pool.c
+++ b/tools/virsh-pool.c
@@ -1063,6 +1063,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
case VIR_STORAGE_POOL_GLUSTER:
flags |= VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER;
break;
+ case VIR_STORAGE_POOL_ZFS:
+ flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS;
+ break;
case VIR_STORAGE_POOL_LAST:
break;
}
--
1.9.0
10 years, 4 months
[libvirt] [PATCH] change blkiotune weight range min from 100 to 10
by Martin Kletzander
This reflects the same change made in kernel commit df457f845e (before
v2.6.38-rc7). On the rare occasion when the user would try setting
the weight to value in range <10, 100) on older kernel, we will error
out with EINVAL properly. Modifying the error message (adding a hint
for example) would cause weird logs, especially without stacked error
messages (I couldn't resist mentioning it again).
There is no (easy) way of getting the limits from kernel, since it's
not exposed.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1100769
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/lxc/lxc_driver.c | 4 ++--
src/qemu/qemu_driver.c | 4 ++--
tools/virsh-domain.c | 2 +-
tools/virsh.pod | 4 ++--
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 05d10b4..a7f4b87 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2559,7 +2559,7 @@ lxcDomainSetBlkioParameters(virDomainPtr dom,
virTypedParameterPtr param = ¶ms[i];
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
- if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
+ if (params[i].value.ui > 1000 || params[i].value.ui < 10) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("out of blkio weight range."));
ret = -1;
@@ -2660,7 +2660,7 @@ lxcDomainSetBlkioParameters(virDomainPtr dom,
virTypedParameterPtr param = ¶ms[i];
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
- if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
+ if (params[i].value.ui > 1000 || params[i].value.ui < 10) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("out of blkio weight range."));
ret = -1;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 626d557..eae8ae2 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7819,7 +7819,7 @@ qemuDomainSetBlkioParameters(virDomainPtr dom,
virTypedParameterPtr param = ¶ms[i];
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
- if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
+ if (params[i].value.ui > 1000 || params[i].value.ui < 10) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("out of blkio weight range."));
ret = -1;
@@ -7920,7 +7920,7 @@ qemuDomainSetBlkioParameters(virDomainPtr dom,
virTypedParameterPtr param = ¶ms[i];
if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
- if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
+ if (params[i].value.ui > 1000 || params[i].value.ui < 10) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("out of blkio weight range."));
ret = -1;
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index ba47258..c58beaf 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -1255,7 +1255,7 @@ static const vshCmdOptDef opts_blkiotune[] = {
},
{.name = "weight",
.type = VSH_OT_INT,
- .help = N_("IO Weight in range [100, 1000]")
+ .help = N_("IO Weight in range [10, 1000]")
},
{.name = "device-weights",
.type = VSH_OT_STRING,
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 849ae31..9f3cbee 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1824,8 +1824,8 @@ Specifying -1 as a value for these limits is interpreted as unlimited.
[[I<--config>] [I<--live>] | [I<--current>]]
Display or set the blkio parameters. QEMU/KVM supports I<--weight>.
-I<--weight> is in range [100, 1000]. After kernel 2.6.39, the value
-could be in the range [10, 1000].
+I<--weight> is in range [100, 1000]. Since kernel 2.6.39, the value
+is in the range [10, 1000].
B<device-weights> is a single string listing one or more device/weight
pairs, in the format of /path/to/device,weight,/path/to/device,weight.
--
2.0.2
10 years, 4 months
[libvirt] [PATCH 0/2] virtio serial address allocation
by Ján Tomko
Ján Tomko (2):
Add test for virtio serial port assignment
Implement virtio serial address allocation
src/conf/domain_addr.c | 426 +++++++++++++++++++++
src/conf/domain_addr.h | 49 +++
src/conf/domain_conf.c | 30 --
src/libvirt_private.syms | 9 +
src/qemu/qemu_command.c | 61 +++
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_hotplug.c | 31 +-
tests/qemuhotplugtest.c | 2 +-
.../qemuxml2argv-channel-virtio-auto.args | 8 +-
.../qemuxml2argv-channel-virtio-autoassign.args | 20 +
.../qemuxml2argv-channel-virtio-autoassign.xml | 50 +++
tests/qemuxml2argvtest.c | 2 +
.../qemuxml2xmlout-channel-virtio-auto.xml | 10 +-
14 files changed, 658 insertions(+), 42 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-virtio-autoassign.xml
--
1.8.5.5
10 years, 4 months
[libvirt] [libvirt-sandbox PATCH 0/2] virt-sandbox-service fixes
by Cédric Bosdonnat
Here are a 2 fixes that make virt-sandbox-service work for me.
One allows it to work if selinux isn't handled by libvirtd, the other
safely handles some file copying that can be different across distros.
Cédric Bosdonnat (2):
virt-sandbox-service: check for security label only if they can be
handled
virt-sandbox-service: fix some paths for SUSE
bin/virt-sandbox-service | 42 ++++++++++++++++++++++++++++++++++++------
1 file changed, 36 insertions(+), 6 deletions(-)
--
1.8.4.5
10 years, 4 months
[libvirt] [PATCH] spec: drop anything older than Fedora 13
by Eric Blake
RHEL 5 is based on libvirt 0.8.2, as was Fedora 13. RHEL 5 also
happens to be the oldest box that we actively support with a
buildbot, so it is time to clean up some crufty conditionals in
the spec file that no longer are necessary for modern Fedora.
Although it is probably okay to make further simplifications to
a newer minimum Fedora version, that can be done as a later patch.
This patch just focuses on cleaning any comparison of %{?fedora}
that will always be true or false once we assume a minimum of F13.
* libvirt.spec.in: Make with_audit default to on. Move other
conditionals to a single RHEL-5 block. Simplify any fedora
comparison older than 13. Document our assumptions.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
libvirt.spec.in | 69 ++++++++++++++++++++-------------------------------------
1 file changed, 24 insertions(+), 45 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 9c7b241..091eec8 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1,5 +1,7 @@
# -*- rpm-spec -*-
+# This spec file assumes you are building for Fedora 13 or newer,
+# or for RHEL 5 or newer. It may need some tweaks for other distros.
# If neither fedora nor rhel was defined, try to guess them from %{dist}
%if !0%{?rhel} && !0%{?fedora}
%{expand:%(echo "%{?dist}" | \
@@ -122,7 +124,6 @@
%define with_libpcap 0%{!?_without_libpcap:0}
%define with_macvtap 0%{!?_without_macvtap:0}
%define with_libnl 0%{!?_without_libnl:0}
-%define with_audit 0%{!?_without_audit:0}
%define with_dtrace 0%{!?_without_dtrace:0}
%define with_cgconfig 0%{!?_without_cgconfig:0}
%define with_sanlock 0%{!?_without_sanlock:0}
@@ -136,6 +137,7 @@
# Non-server/HV driver defaults which are always enabled
%define with_sasl 0%{!?_without_sasl:1}
+%define with_audit 0%{!?_without_audit:1}
# Finally set the OS / architecture specific special cases
@@ -224,31 +226,21 @@
%define with_libxl 0
%endif
-# PolicyKit was introduced in Fedora 8 / RHEL-6 or newer
-%if 0%{?fedora} >= 8 || 0%{?rhel} >= 6
- %define with_polkit 0%{!?_without_polkit:1}
-%endif
-
-# libcapng is used to manage capabilities in Fedora 12 / RHEL-6 or newer
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
- %define with_capng 0%{!?_without_capng:1}
-%endif
-
# fuse is used to provide virtualized /proc for LXC
%if 0%{?fedora} >= 17 || 0%{?rhel} >= 7
%define with_fuse 0%{!?_without_fuse:1}
%endif
-# netcf is used to manage network interfaces in Fedora 12 / RHEL-6 or newer
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
- %define with_netcf 0%{!?_without_netcf:%{server_drivers}}
-%endif
-
-# udev is used to manage host devices in Fedora 12 / RHEL-6 or newer
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
- %define with_udev 0%{!?_without_udev:%{server_drivers}}
-%else
+# RHEL 5 lacks newer tools
+%if 0%{?rhel} == 5
%define with_hal 0%{!?_without_hal:%{server_drivers}}
+%else
+ %define with_polkit 0%{!?_without_polkit:1}
+ %define with_capng 0%{!?_without_capng:1}
+ %define with_netcf 0%{!?_without_netcf:%{server_drivers}}
+ %define with_udev 0%{!?_without_udev:%{server_drivers}}
+ %define with_yajl 0%{!?_without_yajl:%{server_drivers}}
+ %define with_dtrace 1
%endif
# interface requires netcf
@@ -256,11 +248,6 @@
%define with_interface 0
%endif
-# Enable yajl library for JSON mode with QEMU
-%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6
- %define with_yajl 0%{!?_without_yajl:%{server_drivers}}
-%endif
-
# Enable sanlock library for lock management with QEMU
# Sanlock is available only on x86_64 for RHEL
%if 0%{?fedora} >= 16
@@ -321,16 +308,8 @@
%define with_libnl 1
%endif
-%if 0%{?fedora} >= 11 || 0%{?rhel} >= 5
- %define with_audit 0%{!?_without_audit:1}
-%endif
-
-%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6
- %define with_dtrace 1
-%endif
-
# Pull in cgroups config system
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+%if 0%{?fedora} || 0%{?rhel} >= 6
%if %{with_qemu} || %{with_lxc}
%define with_cgconfig 0%{!?_without_cgconfig:1}
%endif
@@ -350,7 +329,7 @@
# Force QEMU to run as non-root
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+%if 0%{?fedora} || 0%{?rhel} >= 6
%define qemu_user qemu
%define qemu_group qemu
%else
@@ -473,7 +452,7 @@ BuildRequires: libattr-devel
# For pool-build probing for existing pools
BuildRequires: libblkid-devel >= 2.17
%endif
-%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+%if 0%{?fedora} || 0%{?rhel} >= 6
# for augparse, optionally used in testing
BuildRequires: augeas
%endif
@@ -538,7 +517,7 @@ BuildRequires: cyrus-sasl-devel
%if 0%{?fedora} >= 20 || 0%{?rhel} >= 7
BuildRequires: polkit-devel >= 0.112
%else
- %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
BuildRequires: polkit-devel >= 0.93
%else
BuildRequires: PolicyKit-devel >= 0.6
@@ -621,7 +600,7 @@ BuildRequires: netcf-devel >= 0.1.4
%endif
%endif
%if %{with_esx}
- %if 0%{?fedora} >= 9 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
BuildRequires: libcurl-devel
%else
BuildRequires: curl-devel
@@ -705,7 +684,7 @@ Requires: avahi-libs
%if 0%{?fedora} >= 20 || 0%{?rhel} >= 7
Requires: polkit >= 0.112
%else
- %if 0%{?fedora} >= 12 || 0%{?rhel} >=6
+ %if 0%{?fedora} || 0%{?rhel} >=6
Requires: polkit >= 0.93
%else
Requires: PolicyKit >= 0.6
@@ -865,7 +844,7 @@ Requires: nfs-utils
# For mkfs
Requires: util-linux
# For glusterfs
- %if 0%{?fedora} >= 11
+ %if 0%{?fedora}
Requires: glusterfs-client >= 2.0.1
%endif
%endif
@@ -1579,7 +1558,7 @@ mv $RPM_BUILD_ROOT%{_datadir}/systemtap/tapset/libvirt_qemu_probes.stp \
%endif
%endif
-%if 0%{?fedora} < 14 && 0%{?rhel} < 6
+%if 0%{?rhel} == 5
rm -f $RPM_BUILD_ROOT%{_prefix}/lib/sysctl.d/libvirtd.conf
%endif
@@ -1607,7 +1586,7 @@ fi
%if ! %{with_driver_modules}
%if %{with_qemu}
%pre daemon
- %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
# We want soft static allocation of well-known ids, as disk images
# are commonly shared across NFS mounts by id rather than name; see
# https://fedoraproject.org/wiki/Packaging:UsersAndGroups
@@ -1762,7 +1741,7 @@ fi
%if %{with_driver_modules}
%if %{with_qemu}
%pre daemon-driver-qemu
- %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
# We want soft static allocation of well-known ids, as disk images
# are commonly shared across NFS mounts by id rather than name; see
# https://fedoraproject.org/wiki/Packaging:UsersAndGroups
@@ -1869,7 +1848,7 @@ exit 0
%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
%config(noreplace) %{_sysconfdir}/libvirt/virtlockd.conf
- %if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
%config(noreplace) %{_prefix}/lib/sysctl.d/libvirtd.conf
%endif
@@ -1897,7 +1876,7 @@ exit 0
%endif
%if %{with_polkit}
- %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
+ %if 0%{?fedora} || 0%{?rhel} >= 6
%{_datadir}/polkit-1/actions/org.libvirt.unix.policy
%{_datadir}/polkit-1/actions/org.libvirt.api.policy
%else
--
1.9.3
10 years, 4 months
[libvirt] [PATCHv1.5 0/8] Gluster security driver support and snapshot file pre-creation
by Peter Krempa
I'm posting a rebased version as John notified me that the original series cannot be applied cleanly any more.
Peter Krempa (8):
storage: Implement storage driver helper to chown disk images
storage: Add witness for checking storage volume use in security
driver
security: DAC: Remove superfluous link resolution
security: DAC: Introduce callback to perform image chown
security: DAC: Plumb usage of chown callback
qemu: Implement DAC driver chown callback to co-operate with storage
drv
storage: Implement virStorageFileCreate for local and gluster files
qemu: snapshot: Use storage driver to pre-create snapshot file
src/qemu/qemu_driver.c | 66 ++++++++++++++++----
src/security/security_dac.c | 109 +++++++++++++++++++++++-----------
src/security/security_dac.h | 3 +
src/security/security_manager.c | 4 +-
src/security/security_manager.h | 19 +++++-
src/storage/storage_backend.h | 6 ++
src/storage/storage_backend_fs.c | 29 +++++++++
src/storage/storage_backend_gluster.c | 27 +++++++++
src/storage/storage_driver.c | 58 ++++++++++++++++++
src/storage/storage_driver.h | 3 +
10 files changed, 277 insertions(+), 47 deletions(-)
--
2.0.0
10 years, 4 months
[libvirt] [PATCH v2] leaseshelper: improvements to support all events
by Nehal J Wani
This patch enables the helper program to detect event(s) triggered when there
is a change in lease length or expiry and client-id. This transfers complete
control of leases database to libvirt and obsoletes use of the lease database
file (<network-name>.leases). That file will not be created, read, or written.
This is achieved by adding the option --leasefile-ro to dnsmasq and passing a
custom env var to leaseshelper, which helps us map events related to leases
with their corresponding network bridges, no matter what the event be.
Also, this requires the addition of a new non-lease entry in our custom lease
database: "server-duid". It is required to identify a DHCPv6 server.
Now that dnsmasq doesn't maintain its own leases database, it relies on our
helper program to tell it about previous leases and server duid. Thus, this
patch makes our leases program honor an extra action: "init", in which it sends
the known info in a particular format to dnsmasq by printing it to stdout.
---
This is compatible with libvirt 1.2.6 as only additions have been
introduced, and the old leases file (*.staus) will still be supported.
v1: https://www.redhat.com/archives/libvir-list/2014-July/msg00568.html
src/network/bridge_driver.c | 7 ++
src/network/leaseshelper.c | 152 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 136 insertions(+), 23 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 6a2e760..4363cd8 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1289,7 +1289,10 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
+ /* Libvirt gains full control of leases database */
+ virCommandAddArgFormat(cmd, "--leasefile-ro");
virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
+ virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", network->def->bridge);
*cmdout = cmd;
ret = 0;
@@ -3432,6 +3435,10 @@ networkGetDHCPLeases(virNetworkPtr network,
goto error;
}
+ /* Ignore server-duid. It's not part of a lease */
+ if (virJSONValueObjectHasKey(lease_tmp, "server-duid"))
+ continue;
+
if (!(mac_tmp = virJSONValueObjectGetString(lease_tmp, "mac-address"))) {
/* leaseshelper program guarantees that lease will be stored only if
* mac-address is known otherwise not */
diff --git a/src/network/leaseshelper.c b/src/network/leaseshelper.c
index e4b5283..cc4b4ac 100644
--- a/src/network/leaseshelper.c
+++ b/src/network/leaseshelper.c
@@ -50,6 +50,12 @@
*/
#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024)
+/*
+ * Use this when passing possibly-NULL strings to printf-a-likes.
+ * Required for unknown parameters during init call.
+ */
+#define EMPTY_STR(s) ((s) ? (s) : "*")
+
static const char *program_name;
/* Display version information. */
@@ -65,7 +71,7 @@ usage(int status)
if (status) {
fprintf(stderr, _("%s: try --help for more details\n"), program_name);
} else {
- printf(_("Usage: %s add|old|del mac|clientid ip [hostname]\n"
+ printf(_("Usage: %s add|old|del|init mac|clientid ip [hostname]\n"
"Designed for use with 'dnsmasq --dhcp-script'\n"
"Refer to man page of dnsmasq for more details'\n"),
program_name);
@@ -89,6 +95,7 @@ enum virLeaseActionFlags {
VIR_LEASE_ACTION_ADD, /* Create new lease */
VIR_LEASE_ACTION_OLD, /* Lease already exists, renew it */
VIR_LEASE_ACTION_DEL, /* Delete the lease */
+ VIR_LEASE_ACTION_INIT, /* Tell dnsmasq of existing leases on restart */
VIR_LEASE_ACTION_LAST
};
@@ -96,7 +103,7 @@ enum virLeaseActionFlags {
VIR_ENUM_DECL(virLeaseAction);
VIR_ENUM_IMPL(virLeaseAction, VIR_LEASE_ACTION_LAST,
- "add", "old", "del");
+ "add", "old", "del", "init");
int
main(int argc, char **argv)
@@ -105,6 +112,7 @@ main(int argc, char **argv)
char *pid_file = NULL;
char *lease_entries = NULL;
char *custom_lease_file = NULL;
+ char *server_duid = NULL;
const char *ip = NULL;
const char *mac = NULL;
const char *iaid = virGetEnvAllowSUID("DNSMASQ_IAID");
@@ -112,20 +120,26 @@ main(int argc, char **argv)
const char *interface = virGetEnvAllowSUID("DNSMASQ_INTERFACE");
const char *exptime_tmp = virGetEnvAllowSUID("DNSMASQ_LEASE_EXPIRES");
const char *hostname = virGetEnvAllowSUID("DNSMASQ_SUPPLIED_HOSTNAME");
+ const char *server_duid_env = virGetEnvAllowSUID("DNSMASQ_SERVER_DUID");
const char *leases_str = NULL;
long long currtime = 0;
long long expirytime = 0;
size_t i = 0;
+ size_t count_ipv6 = 0;
+ size_t count_ipv4 = 0;
int action = -1;
int pid_file_fd = -1;
int rv = EXIT_FAILURE;
int custom_lease_file_len = 0;
bool add = false;
+ bool init = false;
bool delete = false;
virJSONValuePtr lease_new = NULL;
virJSONValuePtr lease_tmp = NULL;
virJSONValuePtr leases_array = NULL;
virJSONValuePtr leases_array_new = NULL;
+ virJSONValuePtr *leases_ipv4 = NULL;
+ virJSONValuePtr *leases_ipv6 = NULL;
virSetErrorFunc(NULL, NULL);
virSetErrorLogPriorityFunc(NULL);
@@ -156,17 +170,18 @@ main(int argc, char **argv)
}
}
- if (argc != 4 && argc != 5) {
+ if (argc != 4 && argc != 5 && argc != 2) {
/* Refer man page of dnsmasq --dhcp-script for more details */
usage(EXIT_FAILURE);
}
/* Make sure dnsmasq knows the interface. The interface name is not known
- * when dnsmasq (re)starts and throws 'del' events for expired leases.
- * So, if any old lease has expired, it will be automatically removed the
- * next time this program is invoked */
- if (!interface)
- goto cleanup;
+ * via env variable set by dnsmasq when dnsmasq (re)starts and throws 'del'
+ * events for expired leases. So, libvirtd sets another env var for this
+ * purpose */
+ if (!interface) {
+ interface = virGetEnvAllowSUID("VIR_BRIDGE_NAME");
+ }
ip = argv[3];
mac = argv[2];
@@ -185,9 +200,14 @@ main(int argc, char **argv)
exptime[strlen(exptime) - 1] = '\0';
/* Check if it is an IPv6 lease */
- if (virGetEnvAllowSUID("DNSMASQ_IAID")) {
+ if (iaid) {
mac = virGetEnvAllowSUID("DNSMASQ_MAC");
clientid = argv[2];
+
+ if (server_duid_env) {
+ if (VIR_STRDUP(server_duid, server_duid_env) < 0)
+ goto cleanup;
+ }
}
if (virAsprintf(&custom_lease_file,
@@ -264,6 +284,8 @@ main(int argc, char **argv)
goto cleanup;
}
}
+ } else if (action == VIR_LEASE_ACTION_INIT) {
+ init = true;
} else {
fprintf(stderr, _("Unsupported action: %s\n"),
virLeaseActionTypeToString(action));
@@ -294,6 +316,7 @@ main(int argc, char **argv)
i = 0;
while (i < virJSONValueArraySize(leases_array)) {
const char *ip_tmp = NULL;
+ const char *server_duid_tmp = NULL;
long long expirytime_tmp = -1;
if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) {
@@ -302,6 +325,20 @@ main(int argc, char **argv)
goto cleanup;
}
+ if ((server_duid_tmp
+ = virJSONValueObjectGetString(lease_tmp, "server-duid"))) {
+ /* Control reaches here atmost once */
+ if (!server_duid) {
+ /* Control reaches here when the 'action' is not for an
+ * ipv6 lease or, for some weird reason the env var
+ * DNSMASQ_SERVER_DUID wasn't set*/
+ if (VIR_STRDUP(server_duid, server_duid_tmp) < 0)
+ goto cleanup;
+ }
+ i++;
+ continue;
+ }
+
if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address")) ||
(virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp) < 0)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -328,39 +365,108 @@ main(int argc, char **argv)
goto cleanup;
}
+ /* Store pointers to ipv4 and ipv6 leases */
+ if (strchr(ip_tmp, ':'))
+ ignore_value(VIR_APPEND_ELEMENT(leases_ipv6, count_ipv6, lease_tmp));
+ else
+ ignore_value(VIR_APPEND_ELEMENT(leases_ipv4, count_ipv4, lease_tmp));
+
ignore_value(virJSONValueArraySteal(leases_array, i));
}
}
}
- if (add) {
- if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ if (init) {
+ /* Man page of dnsmasq says: the script (helper program, in our case)
+ * should write the saved state of the lease database, in dnsmasq
+ * leasefile format, to stdout and exit with zero exit code, when
+ * called with argument init. Format:
+ * #For all ipv4 leases:
+ * Expiry_time MAC_address IP_address Hostname Client-id
+ * #If DHCPv6 is present:
+ * duid Server_DUID
+ * #For all ipv6 leases:
+ * Expiry_time IAID IP_address Hostname Client-DUID */
+ long long expirytime_tmp = -1;
+ for (i = 0; i < count_ipv4; i++) {
+ lease_tmp = leases_ipv4[i];
+ virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp);
+ printf("%lld %s %s %s %s\n",
+ expirytime_tmp,
+ virJSONValueObjectGetString(lease_tmp, "mac-address"),
+ virJSONValueObjectGetString(lease_tmp, "ip-address"),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id")));
+ }
+ if (server_duid) {
+ printf("duid %s\n", server_duid);
+ for (i = 0; i < count_ipv6; i++) {
+ lease_tmp = leases_ipv6[i];
+ virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp);
+ printf("%lld %s %s %s %s\n",
+ expirytime_tmp,
+ virJSONValueObjectGetString(lease_tmp, "iaid"),
+ virJSONValueObjectGetString(lease_tmp, "ip-address"),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id")));
+ }
+ }
+ }
+ else {
+ if (add) {
+ if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+ lease_new = NULL;
+ }
+
+ if (server_duid) {
+ if (!(lease_new = virJSONValueNewObject())) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectAppendString(lease_new,
+ "server-duid", server_duid) < 0)
+ goto cleanup;
+
+ if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+ lease_new = NULL;
+ }
+
+ if (!(leases_str = virJSONValueToString(leases_array_new, true))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to create json"));
+ _("empty json array"));
goto cleanup;
}
- lease_new = NULL;
- }
- if (!(leases_str = virJSONValueToString(leases_array_new, true))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("empty json array"));
- goto cleanup;
+ /* Write to file */
+ if (virFileRewrite(custom_lease_file, 0644,
+ customLeaseRewriteFile, &leases_str) < 0)
+ goto cleanup;
}
- /* Write to file */
- if (virFileRewrite(custom_lease_file, 0644,
- customLeaseRewriteFile, &leases_str) < 0)
- goto cleanup;
-
rv = EXIT_SUCCESS;
cleanup:
if (pid_file_fd != -1)
virPidFileReleasePath(pid_file, pid_file_fd);
+ for (i = 0; i < count_ipv4; i++)
+ VIR_FREE(leases_ipv4);
+ for (i = 0; i < count_ipv6; i++)
+ VIR_FREE(leases_ipv6);
VIR_FREE(pid_file);
VIR_FREE(exptime);
+ VIR_FREE(server_duid);
+ VIR_FREE(lease_entries);
VIR_FREE(custom_lease_file);
virJSONValueFree(lease_new);
virJSONValueFree(leases_array);
--
1.9.3
10 years, 4 months
[libvirt] [PATCHv4 0/2] lxc keep/drop capabilities
by Cédric Bosdonnat
Hi all,
Even though the v3 has been ACKed (but not pushed), I rebased it on top of
master before pushing it and did a few changes that are worth checking before.
* Path 1 (feature) and 3 (doc) of the previous version merge merged together as
suggested for another similar series.
* virCgroupAllowDevice() has been changed to use negative major / minor device
values to output '*'. I never saw any of them negative, but I don't have a
good knowledge of that.
--
Cedric
Cédric Bosdonnat (2):
lxc: allow to keep or drop capabilities
lxc domain from xml: convert lxc.cap.drop
docs/drvlxc.html.in | 47 ++++
docs/schemas/domaincommon.rng | 207 ++++++++++++++++++
src/conf/domain_conf.c | 126 ++++++++++-
src/conf/domain_conf.h | 56 +++++
src/libvirt_private.syms | 3 +
src/lxc/lxc_cgroup.c | 8 +
src/lxc/lxc_container.c | 241 +++++++++++++++++++--
src/lxc/lxc_native.c | 25 +++
src/util/vircgroup.c | 57 ++++-
src/util/vircgroup.h | 2 +
tests/domainschemadata/domain-caps-features.xml | 28 +++
tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 2 +
tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 2 +
tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 2 +
tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 2 +
.../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 4 +
tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 2 +
tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 4 +
tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 2 +
tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 4 +
tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 8 +
tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 4 +
22 files changed, 816 insertions(+), 20 deletions(-)
create mode 100644 tests/domainschemadata/domain-caps-features.xml
--
1.8.4.5
10 years, 4 months