For some reason these have been stored in /var/lib, although other
drivers (e.g. qemu and lxc) store their state files in /var/run.
It's much nicer to store state files in /var/run because it is
automatically cleared out when the system reboots. We can then use
existence of the state file as a convenient indicator of whether or
not a particular network is active.
Since changing the location of the state files by itself will cause
problems in the case of a *live* upgrade from an older libvirt that
uses /var/lib (because current status of active networks will be
lost), the network driver initialization has been modified to migrate
any network state files from /var/lib to /var/run.
This will not help those trying to *downgrade*, but in practice this
will only be problematic in two cases
1) If there are networks with network-wide bandwidth limits configured
*and in use* by a guest during a downgrade to "old" libvirt. In this
case, the class ID's used for that network's tc rules, as well as
the currently in-use bandwidth "floor" will be forgotten.
2) If someone does this: 1) upgrade libvirt, 2) downgrade libvirt, 3)
modify running state of network (e.g. add a static dhcp host, etc),
4) upgrade. In this case, the modifications to the running network
will be lost (but not any persistent changes to the network's
config).
---
change from V1:
* merged previous 2/5 & 3/5 into a single patch that changes the
location and migrates old state files, to avoid potential problems
by people trying to use git bisect.
* move the files with a direct copy, rather than reading/parsing the
XML then formatting/writing it. Note (hopefully) correct use of
readdir!
* put the migration into a separate static function
* don't put oldStateDir in driverState, as we only use it once during
initialization.
* only attempt migration when running privileged, since the
unprivileged state location hasn't changed.
src/network/bridge_driver.c | 97 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 91 insertions(+), 6 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 4ca3de5..57dfb2d 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -41,6 +41,7 @@
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if.h>
+#include <dirent.h>
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
@@ -416,6 +417,88 @@ firewalld_dbus_filter_bridge(DBusConnection *connection
ATTRIBUTE_UNUSED,
}
#endif
+static int
+networkMigrateStateFiles(virNetworkDriverStatePtr driver)
+{
+ /* Due to a change in location of network state xml beginning in
+ * libvirt 1.2.4 (from /var/lib/libvirt/network to
+ * /var/run/libvirt/network), we must check for state files in two
+ * locations. Anything found in the old location must be written
+ * to the new location, then erased from the old location. (Note
+ * that we read/write the file rather than calling rename()
+ * because the old and new state directories are likely in
+ * different filesystems).
+ */
+ int ret = -1;
+ const char *oldStateDir = LOCALSTATEDIR "/lib/libvirt/network";
+ DIR *dir;
+ struct dirent *entry;
+ char *oldPath = NULL, *newPath = NULL;
+ char *contents = NULL;
+
+ if (!(dir = opendir(oldStateDir))) {
+ if (errno == ENOENT)
+ return 0;
+
+ virReportSystemError(errno, _("failed to open directory
'%s'"),
+ oldStateDir);
+ return -1;
+ }
+
+ if (virFileMakePath(driver->stateDir) < 0) {
+ virReportSystemError(errno, _("cannot create directory %s"),
+ driver->stateDir);
+ goto cleanup;
+ }
+
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (!entry) {
+ if (errno) {
+ virReportSystemError(errno, _("failed to read directory
'%s'"),
+ oldStateDir);
+ goto cleanup;
+ }
+ break;
+ }
+
+ if (entry->d_type != DT_REG ||
+ STREQ(entry->d_name, ".") ||
+ STREQ(entry->d_name, ".."))
+ continue;
+
+ if (virAsprintf(&oldPath, "%s/%s",
+ oldStateDir, entry->d_name) < 0)
+ goto cleanup;
+ if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&newPath, "%s/%s",
+ driver->stateDir, entry->d_name) < 0)
+ goto cleanup;
+ if (virFileWriteStr(newPath, contents, S_IRUSR | S_IWUSR) < 0) {
+ virReportSystemError(errno,
+ _("failed to write network status file
'%s'"),
+ newPath);
+ goto cleanup;
+ }
+
+ unlink(oldPath);
+ VIR_FREE(oldPath);
+ VIR_FREE(newPath);
+ VIR_FREE(contents);
+ }
+
+ ret = 0;
+ cleanup:
+ closedir(dir);
+ VIR_FREE(oldPath);
+ VIR_FREE(newPath);
+ VIR_FREE(contents);
+ return ret;
+}
+
/**
* networkStateInitialize:
*
@@ -445,11 +528,6 @@ networkStateInitialize(bool privileged,
/* configuration/state paths are one of
* ~/.config/libvirt/... (session/unprivileged)
* /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
- *
- * NB: The qemu driver puts its domain state in /var/run, and I
- * think the network driver should have used /var/run too (instead
- * of /var/lib), but it's been this way for a long time, and we
- * probably shouldn't change it now.
*/
if (privileged) {
if (VIR_STRDUP(driverState->networkConfigDir,
@@ -457,7 +535,7 @@ networkStateInitialize(bool privileged,
VIR_STRDUP(driverState->networkAutostartDir,
SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0
||
VIR_STRDUP(driverState->stateDir,
- LOCALSTATEDIR "/lib/libvirt/network") < 0 ||
+ LOCALSTATEDIR "/run/libvirt/network") < 0 ||
VIR_STRDUP(driverState->pidDir,
LOCALSTATEDIR "/run/libvirt/network") < 0 ||
VIR_STRDUP(driverState->dnsmasqStateDir,
@@ -465,6 +543,13 @@ networkStateInitialize(bool privileged,
VIR_STRDUP(driverState->radvdStateDir,
LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
goto error;
+
+ /* migration from old to new location is only applicable for
+ * privileged mode - unprivileged mode directories haven't
+ * changed location.
+ */
+ if (networkMigrateStateFiles(driverState) < 0)
+ goto error;
} else {
configdir = virGetUserConfigDirectory();
rundir = virGetUserRuntimeDirectory();
--
1.9.0