diff --git a/libvirt.changes b/libvirt.changes index 324ea54..3a1899f 100644 --- a/libvirt.changes +++ b/libvirt.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Jan 30 16:11:54 MST 2009 - jfehlig@novell.com + +- Fix build for architectures not supporting numa +- Forward port suse-network.patch and snapshots.patch + ------------------------------------------------------------------- Wed Jan 28 15:45:25 MST 2009 - jfehlig@novell.com diff --git a/libvirt.spec b/libvirt.spec index df13fe2..1d2ee72 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -30,7 +30,7 @@ %endif Name: libvirt -BuildRequires: PolicyKit-devel bridge-utils cyrus-sasl-devel fdupes gettext gnutls-devel hal-devel iptables-devel libnuma-devel libxml2-devel lvm2 ncurses-devel parted-devel pkg-config python-devel readline-devel util-linux xhtml-dtd +BuildRequires: PolicyKit-devel bridge-utils cyrus-sasl-devel fdupes gettext gnutls-devel hal-devel iptables-devel libxml2-devel lvm2 ncurses-devel parted-devel pkg-config python-devel readline-devel util-linux xhtml-dtd %if %{with_xen} BuildRequires: xen-devel %endif @@ -42,6 +42,9 @@ BuildRequires: avahi-devel %if %{with_selinux} BuildRequires: libselinux-devel %endif +%ifarch x86_64 ia64 +BuildRequires: libnuma-devel +%endif # Only for directory ownership: BuildRequires: gtk-doc Url: http://libvirt.org/ @@ -49,7 +52,7 @@ License: LGPL v2.1 or later Group: Development/Libraries/C and C++ AutoReqProv: yes Version: 0.5.1 -Release: 1 +Release: 2 Summary: A C toolkit to interract with the virtualization capabilities of Linux Requires: readline Requires: ncurses @@ -78,6 +81,8 @@ Patch6: detach-disk.patch Patch7: migrate-params.patch Patch8: cve-2008-5086.patch Patch9: devhelp.patch +Patch10: suse-network.patch +Patch11: snapshots.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -179,6 +184,8 @@ Authors: %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 +%patch11 -p1 %build %if ! %{with_xen} @@ -312,6 +319,9 @@ rm -rf $RPM_BUILD_ROOT %{py_sitedir}/libvirtmod* %changelog +* Fri Jan 30 2009 jfehlig@novell.com +- Fix build for architectures not supporting numa +- Forward port suse-network.patch and snapshots.patch * Wed Jan 28 2009 jfehlig@novell.com - Updated to version 0.5.1 - CPU and scheduler support for LXC diff --git a/snapshots.patch b/snapshots.patch new file mode 100644 index 0000000..1d84f3a --- /dev/null +++ b/snapshots.patch @@ -0,0 +1,1139 @@ +Index: libvirt-0.5.1/include/libvirt/libvirt.h.in +=================================================================== +--- libvirt-0.5.1.orig/include/libvirt/libvirt.h.in ++++ libvirt-0.5.1/include/libvirt/libvirt.h.in +@@ -470,6 +470,21 @@ int virDomainRestore + const char *from); + + /* ++ * Snapshots ++ */ ++int virDomainSnapshotCreate (virDomainPtr domain, ++ const char* name); ++int virDomainSnapshotApply (virDomainPtr domain, ++ const char* name); ++int virDomainSnapshotDelete (virDomainPtr domain, ++ const char* name); ++int virDomainNumOfSnapshots (virDomainPtr domain); ++int virDomainListSnapshots (virDomainPtr domain, ++ char **const names, ++ int maxnames); ++ ++ ++/* + * Domain core dump + */ + int virDomainCoreDump (virDomainPtr domain, +Index: libvirt-0.5.1/src/libvirt.c +=================================================================== +--- libvirt-0.5.1.orig/src/libvirt.c ++++ libvirt-0.5.1/src/libvirt.c +@@ -1777,6 +1777,168 @@ virDomainRestore(virConnectPtr conn, con + return -1; + } + ++ ++/** ++ * virDomainSnapshotCreate: ++ * @domain: a domain object ++ * @name: name for the new snapshot ++ * ++ * Creates a snapshot from a running domain ++ * ++ * Returns 0 in case of success and -1 in case of failure. ++ */ ++int ++virDomainSnapshotCreate(virDomainPtr domain, const char* name) ++{ ++ virConnectPtr conn; ++ ++ DEBUG("domain=%p", domain); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ return (-1); ++ } ++ ++ conn = domain->conn; ++ if (conn->flags & VIR_CONNECT_RO) { ++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); ++ return (-1); ++ } ++ ++ if (conn->driver->domainSnapshotCreate) ++ return conn->driver->domainSnapshotCreate(domain, name); ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ return -1; ++} ++ ++/** ++ * virDomainSnapshotApply: ++ * @domain: a domain object ++ * @name: name of the snapshot to apply ++ * ++ * Starts a domain using a given snapshot. The domain needs to be shut down ++ * before calling thsi function. ++ * ++ * Returns 0 in case of success and -1 in case of failure. ++ */ ++int ++virDomainSnapshotApply(virDomainPtr domain, const char* name) ++{ ++ virConnectPtr conn; ++ ++ DEBUG("domain=%p", domain); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ return (-1); ++ } ++ ++ conn = domain->conn; ++ if (conn->flags & VIR_CONNECT_RO) { ++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); ++ return (-1); ++ } ++ ++ if (conn->driver->domainSnapshotApply) ++ return conn->driver->domainSnapshotApply(domain, name); ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ return -1; ++} ++ ++/** ++ * virDomainSnapshotDelete: ++ * @domain: a domain object ++ * @name: name of the snapshot to delete ++ * ++ * Deletes a snapshot from the given domain ++ * ++ * Returns 0 in case of success and -1 in case of failure. ++ */ ++int ++virDomainSnapshotDelete(virDomainPtr domain, const char* name) ++{ ++ virConnectPtr conn; ++ ++ DEBUG("domain=%p", domain); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ return (-1); ++ } ++ ++ conn = domain->conn; ++ if (conn->flags & VIR_CONNECT_RO) { ++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); ++ return (-1); ++ } ++ ++ if (conn->driver->domainSnapshotDelete) ++ return conn->driver->domainSnapshotDelete(domain, name); ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ return -1; ++} ++ ++/** ++ * virDomainNumOfSnapshots: ++ * @domain: a domain object ++ * ++ * Returns the number of snapshots of the given domain or -1 in case of failure ++ */ ++int ++virDomainNumOfSnapshots(virDomainPtr domain) ++{ ++ virConnectPtr conn; ++ ++ DEBUG("domain=%p", domain); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ return (-1); ++ } ++ ++ conn = domain->conn; ++ if (conn->driver->domainNumOfSnapshots) ++ return conn->driver->domainNumOfSnapshots(domain); ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ return -1; ++} ++ ++/** ++ * virDomainListSnapshots: ++ * @domain: a domain object ++ * @names: pointer to an array to store the snapshot names ++ * @maxnames: size of the array ++ * ++ * List the names of all snapshots of the given domain. The names are ++ * stored in the @names array. Unused array entries are set to NULL. ++ * ++ * Returns 0 in case of success and -1 in case of failure. ++ */ ++int ++virDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames) ++{ ++ virConnectPtr conn; ++ ++ DEBUG("domain=%p", domain); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ return (-1); ++ } ++ ++ conn = domain->conn; ++ if (conn->driver->domainListSnapshots) ++ return conn->driver->domainListSnapshots(domain, names, maxnames); ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ return -1; ++} ++ ++ + /** + * virDomainCoreDump: + * @domain: a domain object +Index: libvirt-0.5.1/src/driver.h +=================================================================== +--- libvirt-0.5.1.orig/src/driver.h ++++ libvirt-0.5.1/src/driver.h +@@ -145,6 +145,21 @@ typedef int + (*virDrvDomainRestore) (virConnectPtr conn, + const char *from); + typedef int ++ (*virDrvDomainSnapshotCreate) (virDomainPtr domain, ++ const char* name); ++typedef int ++ (*virDrvDomainSnapshotApply) (virDomainPtr domain, ++ const char* name); ++typedef int ++ (*virDrvDomainSnapshotDelete) (virDomainPtr domain, ++ const char* name); ++typedef int ++ (*virDrvDomainNumOfSnapshots) (virDomainPtr domain); ++typedef int ++ (*virDrvDomainListSnapshots) (virDomainPtr domain, ++ char **const names, ++ int maxnames); ++typedef int + (*virDrvDomainCoreDump) (virDomainPtr domain, + const char *to, + int flags); +@@ -387,6 +402,12 @@ struct _virDriver { + virDrvDomainEventDeregister domainEventDeregister; + virDrvDomainMigratePrepare2 domainMigratePrepare2; + virDrvDomainMigrateFinish2 domainMigrateFinish2; ++ ++ virDrvDomainSnapshotCreate domainSnapshotCreate; ++ virDrvDomainSnapshotApply domainSnapshotApply; ++ virDrvDomainSnapshotDelete domainSnapshotDelete; ++ virDrvDomainNumOfSnapshots domainNumOfSnapshots; ++ virDrvDomainListSnapshots domainListSnapshots; + }; + + typedef int +Index: libvirt-0.5.1/src/xen_unified.c +=================================================================== +--- libvirt-0.5.1.orig/src/xen_unified.c ++++ libvirt-0.5.1/src/xen_unified.c +@@ -924,6 +924,81 @@ xenUnifiedDomainRestore (virConnectPtr c + } + + static int ++xenUnifiedDomainSnapshotCreate(virDomainPtr domain, const char* name) ++{ ++ GET_PRIVATE(domain->conn); ++ int i; ++ ++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) ++ if (priv->opened[i] && ++ drivers[i]->domainSnapshotCreate && ++ drivers[i]->domainSnapshotCreate(domain, name) == 0) ++ return 0; ++ ++ return -1; ++} ++ ++static int ++xenUnifiedDomainSnapshotApply(virDomainPtr domain, const char* name) ++{ ++ GET_PRIVATE(domain->conn); ++ int i; ++ ++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) ++ if (priv->opened[i] && ++ drivers[i]->domainSnapshotApply && ++ drivers[i]->domainSnapshotApply(domain, name) == 0) ++ return 0; ++ ++ return -1; ++} ++ ++static int ++xenUnifiedDomainSnapshotDelete(virDomainPtr domain, const char* name) ++{ ++ GET_PRIVATE(domain->conn); ++ int i; ++ ++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) ++ if (priv->opened[i] && ++ drivers[i]->domainSnapshotDelete && ++ drivers[i]->domainSnapshotDelete(domain, name) == 0) ++ return 0; ++ ++ return -1; ++} ++ ++static int ++xenUnifiedDomainNumOfSnapshots(virDomainPtr domain) ++{ ++ GET_PRIVATE(domain->conn); ++ int i; ++ ++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) ++ if (priv->opened[i] && ++ drivers[i]->domainNumOfSnapshots) ++ return drivers[i]->domainNumOfSnapshots(domain); ++ ++ return -1; ++} ++ ++static int ++xenUnifiedDomainListSnapshots(virDomainPtr domain, char **const names, ++ int maxnames) ++{ ++ GET_PRIVATE(domain->conn); ++ int i; ++ ++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) ++ if (priv->opened[i] && ++ drivers[i]->domainListSnapshots && ++ drivers[i]->domainListSnapshots(domain, names, maxnames) == 0) ++ return 0; ++ ++ return -1; ++} ++ ++static int + xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags) + { + GET_PRIVATE(dom->conn); +@@ -1425,6 +1500,11 @@ static virDriver xenUnifiedDriver = { + .domainGetInfo = xenUnifiedDomainGetInfo, + .domainSave = xenUnifiedDomainSave, + .domainRestore = xenUnifiedDomainRestore, ++ .domainSnapshotCreate = xenUnifiedDomainSnapshotCreate, ++ .domainSnapshotApply = xenUnifiedDomainSnapshotApply, ++ .domainSnapshotDelete = xenUnifiedDomainSnapshotDelete, ++ .domainNumOfSnapshots = xenUnifiedDomainNumOfSnapshots, ++ .domainListSnapshots = xenUnifiedDomainListSnapshots, + .domainCoreDump = xenUnifiedDomainCoreDump, + .domainSetVcpus = xenUnifiedDomainSetVcpus, + .domainPinVcpu = xenUnifiedDomainPinVcpu, +Index: libvirt-0.5.1/src/xen_unified.h +=================================================================== +--- libvirt-0.5.1.orig/src/xen_unified.h ++++ libvirt-0.5.1/src/xen_unified.h +@@ -78,6 +78,11 @@ struct xenUnifiedDriver { + virDrvDomainGetInfo domainGetInfo; + virDrvDomainSave domainSave; + virDrvDomainRestore domainRestore; ++ virDrvDomainSnapshotCreate domainSnapshotCreate; ++ virDrvDomainSnapshotApply domainSnapshotApply; ++ virDrvDomainSnapshotDelete domainSnapshotDelete; ++ virDrvDomainNumOfSnapshots domainNumOfSnapshots; ++ virDrvDomainListSnapshots domainListSnapshots; + virDrvDomainCoreDump domainCoreDump; + virDrvDomainSetVcpus domainSetVcpus; + virDrvDomainPinVcpu domainPinVcpu; +Index: libvirt-0.5.1/src/xend_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/xend_internal.c ++++ libvirt-0.5.1/src/xend_internal.c +@@ -51,6 +51,12 @@ + + #ifndef PROXY + ++static int xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name); ++static int xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name); ++static int xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name); ++static int xenDaemonDomainNumOfSnapshots(virDomainPtr domain); ++static int xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames); ++ + /* + * The number of Xen scheduler parameters + */ +@@ -3024,6 +3030,87 @@ xenDaemonDomainRestore(virConnectPtr con + } + return xend_op(conn, "", "op", "restore", "file", filename, NULL); + } ++ ++static int ++xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name) ++{ ++ if ((domain == NULL) || (name == NULL)) { ++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); ++ return (-1); ++ } ++ return xend_op(domain->conn, domain->name, "op", ++ "snapshot_create", "name", name, NULL); ++} ++ ++static int ++xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name) ++{ ++ if ((domain == NULL) || (name == NULL)) { ++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); ++ return (-1); ++ } ++ return xend_op(domain->conn, domain->name, "op", ++ "snapshot_apply", "name", name, NULL); ++} ++ ++static int ++xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name) ++{ ++ if ((domain == NULL) || (name == NULL)) { ++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); ++ return (-1); ++ } ++ return xend_op(domain->conn, domain->name, "op", ++ "snapshot_delete", "name", name, NULL); ++} ++ ++static int ++xenDaemonDomainNumOfSnapshots(virDomainPtr domain) ++{ ++ struct sexpr *root, *node, *value; ++ int i; ++ ++ root = sexpr_get(domain->conn, ++ "/xend/domain/%s?op=snapshot_list", domain->name); ++ if (root == NULL) ++ return -1; ++ ++ for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) { ++ value = node->u.s.car; ++ ++ if (value->kind == SEXPR_VALUE) ++ i++; ++ } ++ ++ return i; ++} ++ ++static int ++xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names, ++ int maxnames) ++{ ++ struct sexpr *root, *node, *value; ++ int i; ++ root = sexpr_get(domain->conn, ++ "/xend/domain/%s?op=snapshot_list", domain->name); ++ if (root == NULL) ++ return -1; ++ ++ for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) { ++ value = node->u.s.car; ++ ++ if (value->kind == SEXPR_VALUE) { ++ names[i] = strdup(value->u.value); ++ if (++i > maxnames) ++ return 0; ++ } ++ } ++ ++ for (; i < maxnames; i++) ++ names[i] = NULL; ++ ++ return 0; ++} + #endif /* !PROXY */ + + /** +@@ -4781,6 +4868,11 @@ struct xenUnifiedDriver xenDaemonDriver + xenDaemonDomainGetInfo, /* domainGetInfo */ + xenDaemonDomainSave, /* domainSave */ + xenDaemonDomainRestore, /* domainRestore */ ++ xenDaemonDomainSnapshotCreate, /* domainSnapshotCreate */ ++ xenDaemonDomainSnapshotApply, /* domainSnapshotApply */ ++ xenDaemonDomainSnapshotDelete, /* domainSnapshotDelete */ ++ xenDaemonDomainNumOfSnapshots, /* domainNumOfSnapshots */ ++ xenDaemonDomainListSnapshots, /* domainListSnapshots */ + xenDaemonDomainCoreDump, /* domainCoreDump */ + xenDaemonDomainSetVcpus, /* domainSetVcpus */ + xenDaemonDomainPinVcpu, /* domainPinVcpu */ +Index: libvirt-0.5.1/src/proxy_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/proxy_internal.c ++++ libvirt-0.5.1/src/proxy_internal.c +@@ -68,6 +68,11 @@ struct xenUnifiedDriver xenProxyDriver = + xenProxyDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ +Index: libvirt-0.5.1/src/xen_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/xen_internal.c ++++ libvirt-0.5.1/src/xen_internal.c +@@ -699,6 +699,11 @@ struct xenUnifiedDriver xenHypervisorDri + xenHypervisorGetDomainInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + NULL, /* domainCoreDump */ + xenHypervisorSetVcpus, /* domainSetVcpus */ + xenHypervisorPinVcpu, /* domainPinVcpu */ +Index: libvirt-0.5.1/src/xm_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/xm_internal.c ++++ libvirt-0.5.1/src/xm_internal.c +@@ -100,6 +100,11 @@ struct xenUnifiedDriver xenXMDriver = { + xenXMDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + NULL, /* domainCoreDump */ + xenXMDomainSetVcpus, /* domainSetVcpus */ + xenXMDomainPinVcpu, /* domainPinVcpu */ +Index: libvirt-0.5.1/src/xs_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/xs_internal.c ++++ libvirt-0.5.1/src/xs_internal.c +@@ -74,6 +74,11 @@ struct xenUnifiedDriver xenStoreDriver = + xenStoreGetDomainInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ +Index: libvirt-0.5.1/src/virsh.c +=================================================================== +--- libvirt-0.5.1.orig/src/virsh.c ++++ libvirt-0.5.1/src/virsh.c +@@ -1099,6 +1099,189 @@ cmdSave(vshControl *ctl, const vshCmd *c + return ret; + } + ++ ++/* ++ * "snapshot-create" command ++ */ ++static vshCmdInfo info_snapshot_create[] = { ++ {"syntax", "snapshot-create "}, ++ {"help", gettext_noop("Create a snapshot of the domain")}, ++ {"desc", gettext_noop("Create a snapshot of the domain")}, ++ {NULL, NULL} ++}; ++ ++static vshCmdOptDef opts_snapshot_create[] = { ++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, ++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd) ++{ ++ virDomainPtr dom; ++ char *name; ++ char *domain; ++ int ret = TRUE; ++ ++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) ++ return FALSE; ++ ++ if (!(name = vshCommandOptString(cmd, "name", NULL))) ++ return FALSE; ++ ++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain))) ++ return FALSE; ++ ++ if (virDomainSnapshotCreate(dom, name) == 0) { ++ vshPrint(ctl, _("Snapshot %s created for domain %s\n"), name, domain); ++ } else { ++ vshError(ctl, FALSE, _("Failed to create snapshot %s for domain %s"), ++ name, domain); ++ ret = FALSE; ++ } ++ ++ virDomainFree(dom); ++ return ret; ++} ++ ++/* ++ * "snapshot-apply" command ++ */ ++static vshCmdInfo info_snapshot_apply[] = { ++ {"syntax", "snapshot-apply "}, ++ {"help", gettext_noop("Start the domain using a snapshot")}, ++ {"desc", gettext_noop("Start the domain using a snapshot")}, ++ {NULL, NULL} ++}; ++ ++static vshCmdOptDef opts_snapshot_apply[] = { ++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, ++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdSnapshotApply(vshControl *ctl, const vshCmd *cmd) ++{ ++ virDomainPtr dom; ++ char *name; ++ char *domain; ++ int ret = TRUE; ++ ++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) ++ return FALSE; ++ ++ if (!(name = vshCommandOptString(cmd, "name", NULL))) ++ return FALSE; ++ ++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain))) ++ return FALSE; ++ ++ if (virDomainSnapshotApply(dom, name) == 0) { ++ vshPrint(ctl, _("Domain %s started using snapshot %s\n"), ++ domain, name); ++ } else { ++ vshError(ctl, FALSE, _("Failed to start domain %s using snapshot %s"), ++ domain, name); ++ ret = FALSE; ++ } ++ ++ virDomainFree(dom); ++ return ret; ++} ++ ++/* ++ * "snapshot-delete" command ++ */ ++static vshCmdInfo info_snapshot_delete[] = { ++ {"syntax", "snapshot-delete "}, ++ {"help", gettext_noop("Delete a snapshot from a domain")}, ++ {"desc", gettext_noop("Delete a snapshot from a domain")}, ++ {NULL, NULL} ++}; ++ ++static vshCmdOptDef opts_snapshot_delete[] = { ++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, ++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) ++{ ++ virDomainPtr dom; ++ char *name; ++ char *domain; ++ int ret = TRUE; ++ ++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) ++ return FALSE; ++ ++ if (!(name = vshCommandOptString(cmd, "name", NULL))) ++ return FALSE; ++ ++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain))) ++ return FALSE; ++ ++ if (virDomainSnapshotDelete(dom, name) == 0) { ++ vshPrint(ctl, _("Snapshot %s deleted from domain %s\n"), name, domain); ++ } else { ++ vshError(ctl, FALSE, _("Failed to delete snapshot %s from domain %s"), ++ name, domain); ++ ret = FALSE; ++ } ++ ++ virDomainFree(dom); ++ return ret; ++} ++ ++/* ++ * "snapshot-list" command ++ */ ++static vshCmdInfo info_snapshot_list[] = { ++ {"syntax", "snapshot-list "}, ++ {"help", gettext_noop("List all snapshots of a domain")}, ++ {"desc", gettext_noop("List all snapshots of a domain")}, ++ {NULL, NULL} ++}; ++ ++static vshCmdOptDef opts_snapshot_list[] = { ++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) ++{ ++ virDomainPtr dom; ++ char *domain; ++ char** names; ++ int num; ++ int i; ++ int ret = TRUE; ++ ++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) ++ return FALSE; ++ ++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain))) ++ return FALSE; ++ ++ // TODO Display snapshot details ++ num = virDomainNumOfSnapshots(dom); ++ names = malloc(num * sizeof(*names)); ++ virDomainListSnapshots(dom, names, num); ++ ++ for (i = 0; i < num; i++) { ++ printf("%s\n", names[i]); ++ free(names[i]); ++ } ++ ++ free(names); ++ virDomainFree(dom); ++ return ret; ++} ++ + /* + * "schedinfo" command + */ +@@ -5697,6 +5880,12 @@ static const vshCmdDef commands[] = { + {"undefine", cmdUndefine, opts_undefine, info_undefine}, + {"uri", cmdURI, NULL, info_uri}, + ++ {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create}, ++ {"snapshot-apply", cmdSnapshotApply, opts_snapshot_apply, info_snapshot_apply}, ++ {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete}, ++ {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list}, ++ ++ + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as}, + {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete}, +Index: libvirt-0.5.1/src/lxc_driver.c +=================================================================== +--- libvirt-0.5.1.orig/src/lxc_driver.c ++++ libvirt-0.5.1/src/lxc_driver.c +@@ -1291,6 +1291,11 @@ static virDriver lxcDriver = { + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + }; + + static virStateDriver lxcStateDriver = { +Index: libvirt-0.5.1/src/openvz_driver.c +=================================================================== +--- libvirt-0.5.1.orig/src/openvz_driver.c ++++ libvirt-0.5.1/src/openvz_driver.c +@@ -1146,6 +1146,11 @@ static virDriver openvzDriver = { + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + }; + + int openvzRegister(void) { +Index: libvirt-0.5.1/src/qemu_driver.c +=================================================================== +--- libvirt-0.5.1.orig/src/qemu_driver.c ++++ libvirt-0.5.1/src/qemu_driver.c +@@ -3794,6 +3794,11 @@ static virDriver qemuDriver = { + qemudDomainEventDeregister, /* domainEventDeregister */ + qemudDomainMigratePrepare2, /* domainMigratePrepare2 */ + qemudDomainMigrateFinish2, /* domainMigrateFinish2 */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + }; + + +Index: libvirt-0.5.1/src/remote_internal.c +=================================================================== +--- libvirt-0.5.1.orig/src/remote_internal.c ++++ libvirt-0.5.1/src/remote_internal.c +@@ -5391,6 +5391,11 @@ static virDriver driver = { + .domainEventDeregister = remoteDomainEventDeregister, + .domainMigratePrepare2 = remoteDomainMigratePrepare2, + .domainMigrateFinish2 = remoteDomainMigrateFinish2, ++ .domainSnapshotCreate = NULL, ++ .domainSnapshotApply = NULL, ++ .domainSnapshotDelete = NULL, ++ .domainNumOfSnapshots = NULL, ++ .domainListSnapshots = NULL, + }; + + static virNetworkDriver network_driver = { +Index: libvirt-0.5.1/src/test.c +=================================================================== +--- libvirt-0.5.1.orig/src/test.c ++++ libvirt-0.5.1/src/test.c +@@ -2255,6 +2255,11 @@ static virDriver testDriver = { + NULL, /* domainEventDeregister */ + NULL, /* domainMigratePrepare2 */ + NULL, /* domainMigrateFinish2 */ ++ NULL, /* domainSnapshotCreate */ ++ NULL, /* domainSnapshotApply */ ++ NULL, /* domainSnapshotDelete */ ++ NULL, /* domainNumOfSnapshots */ ++ NULL, /* domainListSnapshots */ + }; + + static virNetworkDriver testNetworkDriver = { +Index: libvirt-0.5.1/docs/libvirt-api.xml +=================================================================== +--- libvirt-0.5.1.orig/docs/libvirt-api.xml ++++ libvirt-0.5.1/docs/libvirt-api.xml +@@ -183,6 +183,11 @@ + + + ++ ++ ++ ++ ++ + + + +@@ -1237,6 +1242,36 @@ see note above'/> + + + ++ ++ Start a shut off domain based on a previously taken snapshot ++ ++ ++ ++ ++ ++ Create a snapshot from a running domain ++ ++ ++ ++ ++ ++ Delete a snapshot from a domain ++ ++ ++ ++ ++ ++ Returns the number of snapshot a given domain has ++ ++ ++ ++ ++ Returns the names of the snapshots of a domain ++ ++ ++ ++ ++ + + Undefine a domain but does not stop it if it is running + +Index: libvirt-0.5.1/python/libvirt-py.c +=================================================================== +--- libvirt-0.5.1.orig/python/libvirt-py.c ++++ libvirt-0.5.1/python/libvirt-py.c +@@ -25,6 +25,25 @@ LIBVIRT_END_ALLOW_THREADS; + } + + PyObject * ++libvirt_virDomainSnapshotDelete(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { ++ PyObject *py_retval; ++ int c_retval; ++ virDomainPtr domain; ++ PyObject *pyobj_domain; ++ char * name; ++ ++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotDelete", &pyobj_domain, &name)) ++ return(NULL); ++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); ++LIBVIRT_BEGIN_ALLOW_THREADS; ++ ++ c_retval = virDomainSnapshotDelete(domain, name); ++LIBVIRT_END_ALLOW_THREADS; ++ py_retval = libvirt_intWrap((int) c_retval); ++ return(py_retval); ++} ++ ++PyObject * + libvirt_virStorageVolGetKey(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + const char * c_retval; +@@ -847,6 +866,25 @@ LIBVIRT_END_ALLOW_THREADS; + } + + PyObject * ++libvirt_virDomainSnapshotCreate(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { ++ PyObject *py_retval; ++ int c_retval; ++ virDomainPtr domain; ++ PyObject *pyobj_domain; ++ char * name; ++ ++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotCreate", &pyobj_domain, &name)) ++ return(NULL); ++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); ++LIBVIRT_BEGIN_ALLOW_THREADS; ++ ++ c_retval = virDomainSnapshotCreate(domain, name); ++LIBVIRT_END_ALLOW_THREADS; ++ py_retval = libvirt_intWrap((int) c_retval); ++ return(py_retval); ++} ++ ++PyObject * + libvirt_virNetworkDefineXML(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + virNetworkPtr c_retval; +@@ -882,6 +920,24 @@ LIBVIRT_END_ALLOW_THREADS; + } + + PyObject * ++libvirt_virDomainNumOfSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { ++ PyObject *py_retval; ++ int c_retval; ++ virDomainPtr domain; ++ PyObject *pyobj_domain; ++ ++ if (!PyArg_ParseTuple(args, (char *)"O:virDomainNumOfSnapshots", &pyobj_domain)) ++ return(NULL); ++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); ++LIBVIRT_BEGIN_ALLOW_THREADS; ++ ++ c_retval = virDomainNumOfSnapshots(domain); ++LIBVIRT_END_ALLOW_THREADS; ++ py_retval = libvirt_intWrap((int) c_retval); ++ return(py_retval); ++} ++ ++PyObject * + libvirt_virDomainResume(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + int c_retval; +@@ -900,6 +956,25 @@ LIBVIRT_END_ALLOW_THREADS; + } + + PyObject * ++libvirt_virDomainSnapshotApply(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { ++ PyObject *py_retval; ++ int c_retval; ++ virDomainPtr domain; ++ PyObject *pyobj_domain; ++ char * name; ++ ++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotApply", &pyobj_domain, &name)) ++ return(NULL); ++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); ++LIBVIRT_BEGIN_ALLOW_THREADS; ++ ++ c_retval = virDomainSnapshotApply(domain, name); ++LIBVIRT_END_ALLOW_THREADS; ++ py_retval = libvirt_intWrap((int) c_retval); ++ return(py_retval); ++} ++ ++PyObject * + libvirt_virConnectGetHostname(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { + PyObject *py_retval; + char * c_retval; +Index: libvirt-0.5.1/python/libvirt-py.h +=================================================================== +--- libvirt-0.5.1.orig/python/libvirt-py.h ++++ libvirt-0.5.1/python/libvirt-py.h +@@ -1,6 +1,7 @@ + /* Generated */ + + PyObject * libvirt_virStoragePoolGetXMLDesc(PyObject *self, PyObject *args); ++PyObject * libvirt_virDomainSnapshotDelete(PyObject *self, PyObject *args); + PyObject * libvirt_virStorageVolGetKey(PyObject *self, PyObject *args); + PyObject * libvirt_virConnectClose(PyObject *self, PyObject *args); + PyObject * libvirt_virDomainDefineXML(PyObject *self, PyObject *args); +Index: libvirt-0.5.1/python/libvirt.py +=================================================================== +--- libvirt-0.5.1.orig/python/libvirt.py ++++ libvirt-0.5.1/python/libvirt.py +@@ -382,6 +382,12 @@ class virDomain: + ret = libvirtmod.virDomainGetName(self._o) + return ret + ++ def numOfSnapshots(self): ++ """Returns the number of snapshot a given domain has """ ++ ret = libvirtmod.virDomainNumOfSnapshots(self._o) ++ if ret == -1: raise libvirtError ('virDomainNumOfSnapshots() failed', dom=self) ++ return ret ++ + def reboot(self, flags): + """Reboot a domain, the domain object is still usable there + after but the domain OS is being stopped for a restart. +@@ -456,6 +462,24 @@ class virDomain: + if ret == -1: raise libvirtError ('virDomainShutdown() failed', dom=self) + return ret + ++ def snapshotApply(self, name): ++ """Start a shut off domain based on a previously taken snapshot """ ++ ret = libvirtmod.virDomainSnapshotApply(self._o, name) ++ if ret == -1: raise libvirtError ('virDomainSnapshotApply() failed', dom=self) ++ return ret ++ ++ def snapshotCreate(self, name): ++ """Create a snapshot from a running domain """ ++ ret = libvirtmod.virDomainSnapshotCreate(self._o, name) ++ if ret == -1: raise libvirtError ('virDomainSnapshotCreate() failed', dom=self) ++ return ret ++ ++ def snapshotDelete(self, name): ++ """Delete a snapshot from a domain """ ++ ret = libvirtmod.virDomainSnapshotDelete(self._o, name) ++ if ret == -1: raise libvirtError ('virDomainSnapshotDelete() failed', dom=self) ++ return ret ++ + def suspend(self): + """Suspends an active domain, the process is frozen without + further access to CPU resources and I/O but the memory used +@@ -512,6 +536,12 @@ class virDomain: + ret = libvirtmod.virDomainInterfaceStats(self._o, path) + return ret + ++ def listSnapshots(self): ++ """Returns the names of the snapshots of a domain """ ++ ret = libvirtmod.virDomainListSnapshots(self._o) ++ if ret is None: raise libvirtError ('virDomainListSnapshots() failed', dom=self) ++ return ret ++ + def pinVcpu(self, vcpu, cpumap): + """Dynamically change the real CPUs which can be allocated to + a virtual CPU. This function requires privileged access to +Index: libvirt-0.5.1/python/libvir.c +=================================================================== +--- libvirt-0.5.1.orig/python/libvir.c ++++ libvirt-0.5.1/python/libvir.c +@@ -1375,6 +1375,35 @@ libvirt_virStoragePoolGetInfo(PyObject * + return(py_retval); + } + ++static PyObject * ++libvirt_virDomainListSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { ++ PyObject *py_retval; ++ int i, num; ++ char** names; ++ virDomainPtr domain; ++ PyObject *pyobj_domain; ++ ++ if (!PyArg_ParseTuple(args, (char *)"O:virDomainListSnapshots", ++ &pyobj_domain)) ++ return(NULL); ++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); ++ ++LIBVIRT_BEGIN_ALLOW_THREADS; ++ num = virDomainNumOfSnapshots(domain); ++ names = malloc(num * sizeof(*names)); ++ virDomainListSnapshots(domain, names, num); ++LIBVIRT_END_ALLOW_THREADS; ++ ++ py_retval = PyList_New(num); ++ for (i = 0; i < num; i++) { ++ PyList_SetItem(py_retval, i, Py_BuildValue("s", names[i])); ++ free(names[i]); ++ } ++ free(names); ++ ++ return(py_retval); ++} ++ + + static PyObject * + libvirt_virStorageVolGetInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) { +@@ -2246,6 +2275,7 @@ static PyMethodDef libvirtMethods[] = { + {(char *) "virDomainSetSchedulerParameters", libvirt_virDomainSetSchedulerParameters, METH_VARARGS, NULL}, + {(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL}, + {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL}, ++ {(char *) "virDomainListSnapshots", libvirt_virDomainListSnapshots, METH_VARARGS, NULL}, + {(char *) "virConnectListStoragePools", libvirt_virConnectListStoragePools, METH_VARARGS, NULL}, + {(char *) "virConnectListDefinedStoragePools", libvirt_virConnectListDefinedStoragePools, METH_VARARGS, NULL}, + {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL}, +Index: libvirt-0.5.1/python/libvirt-python-api.xml +=================================================================== +--- libvirt-0.5.1.orig/python/libvirt-python-api.xml ++++ libvirt-0.5.1/python/libvirt-python-api.xml +@@ -135,6 +135,11 @@ + + + ++ ++ Returns the names of the snapshots of a domain ++ ++ ++ + + list the storage pools, stores the pointers to the names in @names + +Index: libvirt-0.5.1/python/generator.py +=================================================================== +--- libvirt-0.5.1.orig/python/generator.py ++++ libvirt-0.5.1/python/generator.py +@@ -313,6 +313,7 @@ skip_impl = ( + 'virDomainSetSchedulerParameters', + 'virDomainGetVcpus', + 'virDomainPinVcpu', ++ 'virDomainListSnapshots', + 'virStoragePoolGetUUID', + 'virStoragePoolGetUUIDString', + 'virStoragePoolLookupByUUID', +Index: libvirt-0.5.1/src/libvirt_sym.version.in +=================================================================== +--- libvirt-0.5.1.orig/src/libvirt_sym.version.in ++++ libvirt-0.5.1/src/libvirt_sym.version.in +@@ -224,6 +224,11 @@ LIBVIRT_0.4.2 { + LIBVIRT_0.4.5 { + global: + virConnectFindStoragePoolSources; ++ virDomainSnapshotCreate; ++ virDomainSnapshotApply; ++ virDomainSnapshotDelete; ++ virDomainNumOfSnapshots; ++ virDomainListSnapshots; + } LIBVIRT_0.4.2; + + LIBVIRT_0.5.0 { diff --git a/suse-network.patch b/suse-network.patch new file mode 100644 index 0000000..a8fb050 --- /dev/null +++ b/suse-network.patch @@ -0,0 +1,191 @@ +Index: libvirt-0.5.1/src/network_conf.c +=================================================================== +--- libvirt-0.5.1.orig/src/network_conf.c ++++ libvirt-0.5.1/src/network_conf.c +@@ -752,6 +752,137 @@ error: + return NULL; + } + ++static int virNetworkIsBridge(const char *name) ++{ ++ char *path = NULL; ++ int ret = 0; ++ struct stat s; ++ ++ if (asprintf(&path, "/sys/class/net/%s/bridge", name) < 0) ++ goto out; ++ ++ if (stat(path, &s) != 0) ++ goto out; ++ ++ if (S_ISDIR(s.st_mode)) ++ ret = 1; ++ ++ out: ++ free(path); ++ return ret; ++} ++ ++static unsigned long virNetworkDefSuseGetValue(const char *netName, const char *valName) ++{ ++ unsigned long ret = 0; ++ char *path = NULL; ++ FILE *f; ++ ++ if (asprintf(&path, "/sys/class/net/%s/bridge/%s", netName, valName) < 0) ++ return ret; ++ ++ if ((f = fopen(path, "r")) == NULL) ++ goto out; ++ ++ if (fscanf(f, "%lu", &ret) != 1) { ++ ret = 0; ++ goto out; ++ } ++ ++ ++ out: ++ if (f != NULL) ++ fclose(f); ++ free(path); ++ return ret; ++} ++ ++static virNetworkObjPtr virNetworkLoadSuseNet(virConnectPtr conn, ++ virNetworkObjListPtr nets, ++ const char *name) ++{ ++ virNetworkDefPtr def; ++ virNetworkObjPtr network; ++ int err; ++ ++ if ((network = virNetworkFindByName(nets, name))) { ++ return network; ++ } ++ ++ if (VIR_ALLOC(network) < 0) { ++ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL); ++ return NULL; ++ } ++ ++ network->autostart = 1; ++ network->active = 1; ++ network->readonly = 1; ++ ++ if (VIR_ALLOC(def) < 0) { ++ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL); ++ goto error; ++ } ++ ++ network->def = def; ++ ++ /* name */ ++ def->name = strdup(name); ++ if (def->name == NULL) { ++ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL); ++ goto error; ++ } ++ ++ /* uuid */ ++ if ((err = virUUIDGenerate(def->uuid))) { ++ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR, ++ _("Failed to generate UUID: %s"), strerror(err)); ++ goto error; ++ } ++ ++ /* bridge information */ ++ def->bridge = strdup(name); ++ if (def->bridge == NULL) { ++ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL); ++ goto error; ++ } ++ def->stp = (int)virNetworkDefSuseGetValue(name, "stp_state"); ++ def->delay = virNetworkDefSuseGetValue(name, "forward_delay"); ++ ++ /* Add network to the list */ ++ if (VIR_REALLOC_N(nets->objs, nets->count + 1) < 0) { ++ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL); ++ VIR_FREE(network); ++ return NULL; ++ } ++ ++ nets->objs[nets->count] = network; ++ nets->count++; ++ ++ return network; ++ ++ error: ++ virNetworkObjFree(network); ++ return NULL; ++} ++ ++static void virNetworkLoadSuseNetworks(virConnectPtr conn, ++ virNetworkObjListPtr nets) ++{ ++ DIR *dir = NULL; ++ struct dirent *de; ++ ++ dir = opendir("/sys/class/net"); ++ if (dir == NULL) ++ return; ++ ++ while ((de = readdir(dir))) { ++ if (virNetworkIsBridge(de->d_name)) { ++ virNetworkLoadSuseNet(conn, nets, de->d_name); ++ } ++ } ++ closedir(dir); ++} ++ + int virNetworkLoadAllConfigs(virConnectPtr conn, + virNetworkObjListPtr nets, + const char *configDir, +@@ -787,6 +918,7 @@ int virNetworkLoadAllConfigs(virConnectP + + closedir(dir); + ++ virNetworkLoadSuseNetworks(conn, nets); + return 0; + } + +Index: libvirt-0.5.1/src/network_conf.h +=================================================================== +--- libvirt-0.5.1.orig/src/network_conf.h ++++ libvirt-0.5.1/src/network_conf.h +@@ -86,6 +86,7 @@ struct _virNetworkObj { + unsigned int active : 1; + unsigned int autostart : 1; + unsigned int persistent : 1; ++ unsigned int readonly : 1; + + char *configFile; /* Persistent config file path */ + char *autostartLink; /* Symlink path for autostart */ +Index: libvirt-0.5.1/src/network_driver.c +=================================================================== +--- libvirt-0.5.1.orig/src/network_driver.c ++++ libvirt-0.5.1/src/network_driver.c +@@ -763,6 +763,11 @@ static int networkShutdownNetworkDaemon( + if (!virNetworkIsActive(network)) + return 0; + ++ if (network->readonly) { ++ networkLog(NETWORK_WARN, ": Network '%s' is readonly", network->def->name); ++ return -1; ++ } ++ + if (network->dnsmasqPid > 0) + kill(network->dnsmasqPid, SIGTERM); + +@@ -1082,6 +1087,12 @@ static int networkSetAutostart(virNetwor + return -1; + } + ++ if (network->readonly) { ++ networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR, ++ ": Network '%s' is readonly", network->def->name); ++ return -1; ++ } ++ + autostart = (autostart != 0); + + if (network->autostart == autostart)