[PATCH] qemu: Optimize monitor event name lookup with hash tables
by Rayhan Faizel
Currently, monitor event names are looked up using binary search which has
O(log(n)) time complexity. This can be optimized even further with a
compile-time static hash table generated by the gperf tool. As gperf ensures
perfect hashing, lookup times are guaranteed to be O(1).
This patch also makes gperf a requirement for compiling libvirt if the QEMU
driver is enabled.
Signed-off-by: Rayhan Faizel <rayhan.faizel(a)gmail.com>
---
docs/kbase/internals/qemu-event-handlers.rst | 13 +-
meson.build | 2 +
src/qemu/meson.build | 9 +
src/qemu/qemu_monitor_event.gperf | 68 ++++++++
src/qemu/qemu_monitor_json.c | 171 +++++--------------
src/qemu/qemu_monitor_json.h | 45 +++++
6 files changed, 170 insertions(+), 138 deletions(-)
create mode 100644 src/qemu/qemu_monitor_event.gperf
diff --git a/docs/kbase/internals/qemu-event-handlers.rst b/docs/kbase/internals/qemu-event-handlers.rst
index 3589c4c48c..5ec11e28bd 100644
--- a/docs/kbase/internals/qemu-event-handlers.rst
+++ b/docs/kbase/internals/qemu-event-handlers.rst
@@ -23,16 +23,15 @@ QEMU monitor events
Any event emitted by qemu is received by
``qemu_monitor_json.c:qemuMonitorJSONIOProcessEvent()``. It looks up the
-event by name in the table ``eventHandlers`` (in the same file), which
-should have an entry like this for each event that libvirt
-understands::
+event by name from a hash-table, generated at compile-time by ``gperf``
+based on a list of entries defined in ``qemu_monitor_event.gperf``.
+``qemu_monitor_event.gperf`` should should have an entry like this
+for each event that libvirt understands::
- { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
-
-NB: This table is searched with bsearch, so it *must* be alphabetically sorted.
+ "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged
``qemuMonitorJSONIOProcessEvent`` calls the function listed in
-``eventHandlers``, e.g.::
+``qemu_monitor_event.gperf``, e.g.::
qemu_monitor_json.c:qemuMonitorJSONHandleNicRxFilterChanged()
diff --git a/meson.build b/meson.build
index e8b0094b91..03f1f0d56d 100644
--- a/meson.build
+++ b/meson.build
@@ -1708,6 +1708,8 @@ if not get_option('driver_qemu').disabled()
qemu_slirp_path = '/usr/bin/slirp-helper'
endif
conf.set_quoted('QEMU_SLIRP_HELPER', qemu_slirp_path)
+
+ gperf_prog = find_program('gperf')
endif
endif
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 907893d431..2440476a7b 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -88,11 +88,20 @@ qemu_shim_sources = files(
'qemu_shim.c',
)
+qemu_driver_gperf_sources = []
+
+qemu_driver_gperf_sources += custom_target(
+ 'qemu_monitor_event.c',
+ input : 'qemu_monitor_event.gperf',
+ output : 'qemu_monitor_event.c',
+ command : [gperf_prog, '@INPUT@', '--output-file', '@OUTPUT@'])
+
if conf.has('WITH_QEMU')
qemu_driver_impl = static_library(
'virt_driver_qemu_impl',
[
qemu_driver_sources,
+ qemu_driver_gperf_sources,
qemu_dtrace_gen_headers,
],
dependencies: [
diff --git a/src/qemu/qemu_monitor_event.gperf b/src/qemu/qemu_monitor_event.gperf
new file mode 100644
index 0000000000..de2f958b9e
--- /dev/null
+++ b/src/qemu/qemu_monitor_event.gperf
@@ -0,0 +1,68 @@
+/*
+ * qemu_monitor_event.gperf: QEMU Monitor Event Lookup Table
+ *
+ * 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 "qemu_monitor_json.h"
+%}
+qemuEventHandler;
+%null_strings
+%define initializer-suffix ,NULL
+%language=ANSI-C
+%define slot-name type
+%define lookup-function-name qemu_monitor_event_lookup
+%define hash-function-name qemu_monitor_event_hash
+%readonly-tables
+%omit-struct-type
+%struct-type
+%%
+"ACPI_DEVICE_OST", qemuMonitorJSONHandleAcpiOstInfo
+"BALLOON_CHANGE", qemuMonitorJSONHandleBalloonChange
+"BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError
+"BLOCK_WRITE_THRESHOLD", qemuMonitorJSONHandleBlockThreshold
+"DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted
+"DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange
+"DEVICE_UNPLUG_GUEST_ERROR", qemuMonitorJSONHandleDeviceUnplugErr
+"DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted
+"GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded
+"GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic
+"JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange
+"MEMORY_DEVICE_SIZE_CHANGE", qemuMonitorJSONHandleMemoryDeviceSizeChange
+"MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure
+"MIGRATION", qemuMonitorJSONHandleMigrationStatus
+"MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass
+"NETDEV_STREAM_DISCONNECTED", qemuMonitorJSONHandleNetdevStreamDisconnected
+"NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged
+"PR_MANAGER_STATUS_CHANGED", qemuMonitorJSONHandlePRManagerStatusChanged
+"RDMA_GID_STATUS_CHANGED", qemuMonitorJSONHandleRdmaGidStatusChanged
+"RESET", qemuMonitorJSONHandleReset
+"RESUME", qemuMonitorJSONHandleResume
+"RTC_CHANGE", qemuMonitorJSONHandleRTCChange
+"SHUTDOWN", qemuMonitorJSONHandleShutdown
+"SPICE_CONNECTED", qemuMonitorJSONHandleSPICEConnect
+"SPICE_DISCONNECTED", qemuMonitorJSONHandleSPICEDisconnect
+"SPICE_INITIALIZED", qemuMonitorJSONHandleSPICEInitialize
+"SPICE_MIGRATE_COMPLETED", qemuMonitorJSONHandleSpiceMigrated
+"STOP", qemuMonitorJSONHandleStop
+"SUSPEND", qemuMonitorJSONHandlePMSuspend
+"SUSPEND_DISK", qemuMonitorJSONHandlePMSuspendDisk
+"VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect
+"VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect
+"VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize
+"VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange
+"WAKEUP", qemuMonitorJSONHandlePMWakeup
+"WATCHDOG", qemuMonitorJSONHandleWatchdog
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index eb84a3d938..93df4490ad 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -49,102 +49,12 @@ VIR_LOG_INIT("qemu.qemu_monitor_json");
#define LINE_ENDING "\r\n"
-static void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleReset(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleStop(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleResume(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleRTCChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleWatchdog(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleIOError(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleVNCConnect(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleVNCInitialize(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleSPICEConnect(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleTrayChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandlePMWakeup(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandlePMSuspend(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleJobStatusChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleBalloonChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleGuestCrashloaded(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleGuestPanic(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleSerialChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleMigrationStatus(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleMigrationPass(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleBlockThreshold(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleDumpCompleted(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleDeviceUnplugErr(qemuMonitor *mon, virJSONValue *data);
-static void qemuMonitorJSONHandleNetdevStreamDisconnected(qemuMonitor *mon, virJSONValue *data);
-
-typedef struct {
- const char *type;
- void (*handler)(qemuMonitor *mon, virJSONValue *data);
-} qemuEventHandler;
-
-static qemuEventHandler eventHandlers[] = {
- { "ACPI_DEVICE_OST", qemuMonitorJSONHandleAcpiOstInfo, },
- { "BALLOON_CHANGE", qemuMonitorJSONHandleBalloonChange, },
- { "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
- { "BLOCK_WRITE_THRESHOLD", qemuMonitorJSONHandleBlockThreshold, },
- { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, },
- { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
- { "DEVICE_UNPLUG_GUEST_ERROR", qemuMonitorJSONHandleDeviceUnplugErr, },
- { "DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted, },
- { "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, },
- { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
- { "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
- { "MEMORY_DEVICE_SIZE_CHANGE", qemuMonitorJSONHandleMemoryDeviceSizeChange, },
- { "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, },
- { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
- { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
- { "NETDEV_STREAM_DISCONNECTED", qemuMonitorJSONHandleNetdevStreamDisconnected, },
- { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
- { "PR_MANAGER_STATUS_CHANGED", qemuMonitorJSONHandlePRManagerStatusChanged, },
- { "RDMA_GID_STATUS_CHANGED", qemuMonitorJSONHandleRdmaGidStatusChanged, },
- { "RESET", qemuMonitorJSONHandleReset, },
- { "RESUME", qemuMonitorJSONHandleResume, },
- { "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, },
- { "SHUTDOWN", qemuMonitorJSONHandleShutdown, },
- { "SPICE_CONNECTED", qemuMonitorJSONHandleSPICEConnect, },
- { "SPICE_DISCONNECTED", qemuMonitorJSONHandleSPICEDisconnect, },
- { "SPICE_INITIALIZED", qemuMonitorJSONHandleSPICEInitialize, },
- { "SPICE_MIGRATE_COMPLETED", qemuMonitorJSONHandleSpiceMigrated, },
- { "STOP", qemuMonitorJSONHandleStop, },
- { "SUSPEND", qemuMonitorJSONHandlePMSuspend, },
- { "SUSPEND_DISK", qemuMonitorJSONHandlePMSuspendDisk, },
- { "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
- { "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
- { "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
- { "VSERPORT_CHANGE", qemuMonitorJSONHandleSerialChange, },
- { "WAKEUP", qemuMonitorJSONHandlePMWakeup, },
- { "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
- /* We use bsearch, so keep this list sorted. */
-};
-
-static int
-qemuMonitorEventCompare(const void *key, const void *elt)
-{
- const char *type = key;
- const qemuEventHandler *handler = elt;
- return strcmp(type, handler->type);
-}
-
static int
qemuMonitorJSONIOProcessEvent(qemuMonitor *mon,
virJSONValue *obj)
{
const char *type;
- qemuEventHandler *handler;
+ const qemuEventHandler *handler;
virJSONValue *data;
g_autofree char *details = NULL;
virJSONValue *timestamp;
@@ -171,8 +81,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitor *mon,
}
qemuMonitorEmitEvent(mon, type, seconds, micros, details);
- handler = bsearch(type, eventHandlers, G_N_ELEMENTS(eventHandlers),
- sizeof(eventHandlers[0]), qemuMonitorEventCompare);
+ handler = qemu_monitor_event_lookup(type, strlen(type));
if (handler) {
VIR_DEBUG("handle %s handler=%p data=%p", type,
handler->handler, data);
@@ -543,7 +452,7 @@ qemuMonitorJSONMakeCommand(const char *cmdname,
}
-static void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data)
{
bool guest = false;
virTristateBool guest_initiated = VIR_TRISTATE_BOOL_ABSENT;
@@ -554,17 +463,17 @@ static void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data)
qemuMonitorEmitShutdown(mon, guest_initiated);
}
-static void qemuMonitorJSONHandleReset(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
+void qemuMonitorJSONHandleReset(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
{
qemuMonitorEmitReset(mon);
}
-static void qemuMonitorJSONHandleStop(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
+void qemuMonitorJSONHandleStop(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
{
qemuMonitorEmitStop(mon);
}
-static void qemuMonitorJSONHandleResume(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
+void qemuMonitorJSONHandleResume(qemuMonitor *mon, virJSONValue *data G_GNUC_UNUSED)
{
qemuMonitorEmitResume(mon);
}
@@ -635,7 +544,7 @@ qemuMonitorJSONGuestPanicExtractInfo(virJSONValue *data)
}
-static void
+void
qemuMonitorJSONHandleGuestPanic(qemuMonitor *mon,
virJSONValue *data)
{
@@ -649,7 +558,7 @@ qemuMonitorJSONHandleGuestPanic(qemuMonitor *mon,
}
-static void qemuMonitorJSONHandleRTCChange(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleRTCChange(qemuMonitor *mon, virJSONValue *data)
{
long long offset = 0;
if (virJSONValueObjectGetNumberLong(data, "offset", &offset) < 0) {
@@ -665,7 +574,7 @@ VIR_ENUM_IMPL(qemuMonitorWatchdogAction,
"none", "pause", "reset", "poweroff", "shutdown", "debug", "inject-nmi",
);
-static void qemuMonitorJSONHandleWatchdog(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleWatchdog(qemuMonitor *mon, virJSONValue *data)
{
const char *action;
int actionID;
@@ -689,7 +598,7 @@ VIR_ENUM_IMPL(qemuMonitorIOErrorAction,
);
-static void
+void
qemuMonitorJSONHandleIOError(qemuMonitor *mon, virJSONValue *data)
{
const char *device;
@@ -802,19 +711,19 @@ qemuMonitorJSONHandleGraphicsVNC(qemuMonitor *mon,
authScheme, x509dname, saslUsername);
}
-static void qemuMonitorJSONHandleVNCConnect(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleVNCConnect(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
}
-static void qemuMonitorJSONHandleVNCInitialize(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleVNCInitialize(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
}
-static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleVNCDisconnect(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsVNC(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
@@ -884,24 +793,24 @@ qemuMonitorJSONHandleGraphicsSPICE(qemuMonitor *mon,
}
-static void qemuMonitorJSONHandleSPICEConnect(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleSPICEConnect(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_CONNECT);
}
-static void qemuMonitorJSONHandleSPICEInitialize(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleSPICEInitialize(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE);
}
-static void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitor *mon, virJSONValue *data)
+void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitor *mon, virJSONValue *data)
{
qemuMonitorJSONHandleGraphicsSPICE(mon, data, VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT);
}
-static void
+void
qemuMonitorJSONHandleJobStatusChange(qemuMonitor *mon,
virJSONValue *data)
{
@@ -924,7 +833,7 @@ qemuMonitorJSONHandleJobStatusChange(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleTrayChange(qemuMonitor *mon,
virJSONValue *data)
{
@@ -955,14 +864,14 @@ qemuMonitorJSONHandleTrayChange(qemuMonitor *mon,
qemuMonitorEmitTrayChange(mon, devAlias, devid, reason);
}
-static void
+void
qemuMonitorJSONHandlePMWakeup(qemuMonitor *mon,
virJSONValue *data G_GNUC_UNUSED)
{
qemuMonitorEmitPMWakeup(mon);
}
-static void
+void
qemuMonitorJSONHandlePMSuspend(qemuMonitor *mon,
virJSONValue *data G_GNUC_UNUSED)
{
@@ -970,7 +879,7 @@ qemuMonitorJSONHandlePMSuspend(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleBalloonChange(qemuMonitor *mon,
virJSONValue *data)
{
@@ -983,14 +892,14 @@ qemuMonitorJSONHandleBalloonChange(qemuMonitor *mon,
qemuMonitorEmitBalloonChange(mon, actual);
}
-static void
+void
qemuMonitorJSONHandlePMSuspendDisk(qemuMonitor *mon,
virJSONValue *data G_GNUC_UNUSED)
{
qemuMonitorEmitPMSuspendDisk(mon);
}
-static void
+void
qemuMonitorJSONHandleDeviceDeleted(qemuMonitor *mon, virJSONValue *data)
{
const char *device;
@@ -1004,7 +913,7 @@ qemuMonitorJSONHandleDeviceDeleted(qemuMonitor *mon, virJSONValue *data)
}
-static void
+void
qemuMonitorJSONHandleDeviceUnplugErr(qemuMonitor *mon, virJSONValue *data)
{
const char *device;
@@ -1021,7 +930,7 @@ qemuMonitorJSONHandleDeviceUnplugErr(qemuMonitor *mon, virJSONValue *data)
}
-static void
+void
qemuMonitorJSONHandleNetdevStreamDisconnected(qemuMonitor *mon, virJSONValue *data)
{
const char *name;
@@ -1035,7 +944,7 @@ qemuMonitorJSONHandleNetdevStreamDisconnected(qemuMonitor *mon, virJSONValue *da
}
-static void
+void
qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitor *mon, virJSONValue *data)
{
const char *name;
@@ -1049,7 +958,7 @@ qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitor *mon, virJSONValue *data)
}
-static void
+void
qemuMonitorJSONHandleSerialChange(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1070,7 +979,7 @@ qemuMonitorJSONHandleSerialChange(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon,
virJSONValue *data G_GNUC_UNUSED)
{
@@ -1078,7 +987,7 @@ qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1100,7 +1009,7 @@ qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1147,7 +1056,7 @@ qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleMigrationStatus(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1168,7 +1077,7 @@ qemuMonitorJSONHandleMigrationStatus(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleMigrationPass(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1183,7 +1092,7 @@ qemuMonitorJSONHandleMigrationPass(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleAcpiOstInfo(qemuMonitor *mon, virJSONValue *data)
{
virJSONValue *info;
@@ -1220,7 +1129,7 @@ qemuMonitorJSONHandleAcpiOstInfo(qemuMonitor *mon, virJSONValue *data)
}
-static void
+void
qemuMonitorJSONHandleBlockThreshold(qemuMonitor *mon, virJSONValue *data)
{
const char *nodename;
@@ -1280,7 +1189,7 @@ qemuMonitorJSONExtractDumpStats(virJSONValue *result,
}
-static void
+void
qemuMonitorJSONHandleDumpCompleted(qemuMonitor *mon,
virJSONValue *data)
{
@@ -1302,8 +1211,8 @@ qemuMonitorJSONHandleDumpCompleted(qemuMonitor *mon,
}
-static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon,
- virJSONValue *data)
+void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon,
+ virJSONValue *data)
{
const char *name;
bool connected;
@@ -1323,8 +1232,8 @@ static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon,
}
-static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon,
- virJSONValue *data)
+void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon,
+ virJSONValue *data)
{
const char *netdev;
bool gid_status;
@@ -1357,7 +1266,7 @@ static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon,
}
-static void
+void
qemuMonitorJSONHandleGuestCrashloaded(qemuMonitor *mon,
virJSONValue *data)
{
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 9684660d86..5bd4b21b7d 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -27,6 +27,51 @@
#include "cpu/cpu.h"
#include "util/virgic.h"
+typedef struct {
+ const char *type;
+ void (*handler)(qemuMonitor *mon, virJSONValue *data);
+} qemuEventHandler;
+
+const qemuEventHandler *
+qemu_monitor_event_lookup(const char *str, size_t len);
+
+void qemuMonitorJSONHandleShutdown(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleReset(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleStop(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleResume(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleRTCChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleWatchdog(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleIOError(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleVNCConnect(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleVNCInitialize(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleVNCDisconnect(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleSPICEConnect(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleSPICEInitialize(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleSPICEDisconnect(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleTrayChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandlePMWakeup(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandlePMSuspend(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleJobStatusChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleBalloonChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleGuestCrashloaded(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleGuestPanic(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleDeviceDeleted(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleSerialChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleSpiceMigrated(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleMigrationStatus(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleMigrationPass(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleAcpiOstInfo(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleBlockThreshold(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleDumpCompleted(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleMemoryFailure(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleMemoryDeviceSizeChange(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleDeviceUnplugErr(qemuMonitor *mon, virJSONValue *data);
+void qemuMonitorJSONHandleNetdevStreamDisconnected(qemuMonitor *mon, virJSONValue *data);
+
int
qemuMonitorJSONIOProcessLine(qemuMonitor *mon,
const char *line,
--
2.34.1
9 months
[PATCH v2] network: add modify-or-add feature to net-update
by Abhiram Tilak
The current way of updating a network configuration uses `virsh
net-update` to add, delete or modify entries. But with such a mechansim
one should know if an entry with current info already exists. Adding
modify-or-add option automatically performs either modify or add
depending on the current state.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/363
Signed-off-by: Abhiram Tilak <atp.exp(a)gmail.com>
---
Changes in v2:
- Removed the modify-or-add functionality for sections
where modify is not applicable.
- Changed the existing implementation of `UpdateIPDHCPHost`,
to avoid code duplication.
- Changed the implementation of modify-or-delete to reassign
the `command` variable instead of using multiple nested conditions.
docs/manpages/virsh.rst | 5 +-
include/libvirt/libvirt-network.h | 12 +--
src/conf/network_conf.c | 134 +++++++++++++++++++++---------
tools/virsh-network.c | 6 +-
4 files changed, 110 insertions(+), 47 deletions(-)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 115b802c45..0da3827f6b 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -5908,7 +5908,10 @@ changes optionally taking effect immediately, without needing to
destroy and re-start the network.
*command* is one of "add-first", "add-last", "add" (a synonym for
-add-last), "delete", or "modify".
+add-last), "delete", "modify", "modify-or-add" (modify + add-last), or
+"modify-or-add-first". The 'modify-or-add*' commands perform modify or
+add operation depending on the given state, and can be useful for
+scripting.
*section* is one of "bridge", "domain", "ip", "ip-dhcp-host",
"ip-dhcp-range", "forward", "forward-interface", "forward-pf",
diff --git a/include/libvirt/libvirt-network.h b/include/libvirt/libvirt-network.h
index 58591be7ac..bb4468b160 100644
--- a/include/libvirt/libvirt-network.h
+++ b/include/libvirt/libvirt-network.h
@@ -176,11 +176,13 @@ int virNetworkUndefine (virNetworkPtr network);
* Since: 0.10.2
*/
typedef enum {
- VIR_NETWORK_UPDATE_COMMAND_NONE = 0, /* invalid (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_MODIFY = 1, /* modify an existing element (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_DELETE = 2, /* delete an existing element (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_ADD_LAST = 3, /* add an element at end of list (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST = 4, /* add an element at start of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_NONE = 0, /* invalid (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY = 1, /* modify an existing element (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_DELETE = 2, /* delete an existing element (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_ADD_LAST = 3, /* add an element at end of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST = 4, /* add an element at start of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST = 5, /* conditionally modify or add an element at end (Since: 10.4.0) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST = 6, /* conditionally modify or add an element at start (Since: 10.4.0) */
# ifdef VIR_ENUM_SENTINELS
VIR_NETWORK_UPDATE_COMMAND_LAST /* (Since: 0.10.2) */
# endif
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index cc92ed0b03..a7c3dea163 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -2720,6 +2720,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
virNetworkIPDef *ipdef = virNetworkIPDefByIndex(def, parentIndex);
virNetworkDHCPHostDef host = { 0 };
bool partialOkay = (command == VIR_NETWORK_UPDATE_COMMAND_DELETE);
+ int foundMatchedEntry = -1, foundExactEntry = -1;
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
goto cleanup;
@@ -2740,22 +2741,47 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
}
- if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+ /* check if the entry already exsits */
+ for (i = 0; i < ipdef->nhosts; i++) {
- /* search for the entry with this (ip|mac|name),
- * and update the IP+(mac|name) */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((host.mac && ipdef->hosts[i].mac &&
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
- (VIR_SOCKET_ADDR_VALID(&host.ip) &&
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip)) ||
- (host.name &&
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name))) {
- break;
- }
+ /* try to match any of (ip|mac|name) attributes */
+ if ((host.mac && ipdef->hosts[i].mac &&
+ !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
+ (VIR_SOCKET_ADDR_VALID(&host.ip) &&
+ virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip)) ||
+ (host.name &&
+ STREQ_NULLABLE(host.name, ipdef->hosts[i].name))) {
+ foundMatchedEntry = i;
+ }
+
+ /* find exact entry - all specified attributes must match */
+ if ((!host.mac || !ipdef->hosts[i].mac ||
+ !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) &&
+ (!host.name ||
+ STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) &&
+ (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
+ virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
+ foundExactEntry = i;
+ break;
}
+ }
+
+ /* modify-or-add: convert command to add or modify based on foundEntry */
+ if (foundEntry == -1) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST;
+ else if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_LAST;
+ } else if (foundEntry >= 0) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_MODIFY;
+ }
+
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
- if (i == ipdef->nhosts) {
+ /* log error if no such entry exists to be modified */
+ if (foundMatchedEntry == -1) {
g_autofree char *ip = virSocketAddrFormat(&host.ip);
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't locate an existing dhcp host entry with \"mac='%1$s'\" \"name='%2$s'\" \"ip='%3$s'\" in network '%4$s'"),
@@ -2779,21 +2805,13 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
/* log error if an entry with same name/address/ip already exists */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((host.mac && ipdef->hosts[i].mac &&
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
- (host.name &&
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) ||
- (VIR_SOCKET_ADDR_VALID(&host.ip) &&
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
- g_autofree char *ip = virSocketAddrFormat(&host.ip);
+ if (foundMatchedEntry >= 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("there is an existing dhcp host entry in network '%1$s' that matches \"<host mac='%2$s' name='%3$s' ip='%4$s'/>\""),
+ def->name, host.mac ? host.mac : _("unknown"),
+ host.name, ip ? ip : _("unknown"));
+ goto cleanup;
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("there is an existing dhcp host entry in network '%1$s' that matches \"<host mac='%2$s' name='%3$s' ip='%4$s'/>\""),
- def->name, host.mac ? host.mac : _("unknown"),
- host.name, ip ? ip : _("unknown"));
- goto cleanup;
- }
}
/* add to beginning/end of list */
@@ -2804,18 +2822,8 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
} else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
- /* find matching entry - all specified attributes must match */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((!host.mac || !ipdef->hosts[i].mac ||
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) &&
- (!host.name ||
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) &&
- (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
- break;
- }
- }
- if (i == ipdef->nhosts) {
+ /* log error if there is no entry with exact match*/
+ if (foundExactEntry == -1) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't locate a matching dhcp host entry in network '%1$s'"),
def->name);
@@ -2865,6 +2873,14 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDef *def,
return -1;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("dhcp ranges cannot be modified, use add command instead of modify-or-add"));
+ return -1;
+ }
+
if (virNetworkDHCPRangeDefParseXML(def->name, ipdef, ctxt->node, &range) < 0)
return -1;
@@ -2964,6 +2980,13 @@ virNetworkDefUpdateForwardInterface(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("forward interface entries cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
/* parsing this is so simple that it doesn't have its own function */
iface.type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
if (!(iface.device.dev = virXMLPropString(ctxt->node, "dev"))) {
@@ -3085,6 +3108,18 @@ virNetworkDefUpdatePortGroup(virNetworkDef *def,
goto cleanup;
}
+ /* modify-or-add: convert command to add or modify based on foundName */
+ if (foundName == -1) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST;
+ else if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_LAST;
+ } else if (foundName >= 0) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_MODIFY;
+ }
+
/* if there is already a different default, we can't make this
* one the default.
*/
@@ -3153,6 +3188,13 @@ virNetworkDefUpdateDNSHost(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS HOST records cannot be modified, use add instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
goto cleanup;
@@ -3249,6 +3291,13 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS SRV records cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "srv") < 0)
goto cleanup;
@@ -3330,6 +3379,13 @@ virNetworkDefUpdateDNSTxt(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS TXT records cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "txt") < 0)
goto cleanup;
diff --git a/tools/virsh-network.c b/tools/virsh-network.c
index 597e3d4530..d7dc5df5a8 100644
--- a/tools/virsh-network.c
+++ b/tools/virsh-network.c
@@ -1231,7 +1231,8 @@ static const vshCmdOptDef opts_network_update[] = {
.positional = true,
.required = true,
.completer = virshNetworkUpdateCommandCompleter,
- .help = N_("type of update (add-first, add-last (add), delete, or modify)")
+ .help = N_("type of update (add-first, add-last (add), delete, modify,"
+ "modify-or-add, or modify-or-add-first)")
},
{.name = "section",
.type = VSH_OT_STRING,
@@ -1260,7 +1261,8 @@ static const vshCmdOptDef opts_network_update[] = {
VIR_ENUM_IMPL(virshNetworkUpdateCommand,
VIR_NETWORK_UPDATE_COMMAND_LAST,
- "none", "modify", "delete", "add-last", "add-first");
+ "none", "modify", "delete", "add-last", "add-first", "modify-or-add",
+ "modify-or-add-first");
VIR_ENUM_IMPL(virshNetworkSection,
VIR_NETWORK_SECTION_LAST,
--
2.42.1
9 months
[PATCH v3] network: add modify-or-add feature to net-update
by Abhiram Tilak
The current way of updating a network configuration uses `virsh
net-update` to add, delete or modify entries. But with such a mechansim
one should know if an entry with current info already exists. Adding
modify-or-add option automatically performs either modify or add
depending on the current state.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/363
Signed-off-by: Abhiram Tilak <atp.exp(a)gmail.com>
---
Changes in v3:
- Changed the indexes used to delete or modify instead of `i`.
Changes in v2:
- Removed the modify-or-add functionality for sections
where modify is not applicable.
- Changed the existing implementation of `UpdateIPDHCPHost`,
to avoid code duplication.
- Changed the implementation of modify-or-delete to reassign
the `command` variable instead of using multiple nested conditions.
docs/manpages/virsh.rst | 5 +-
include/libvirt/libvirt-network.h | 12 +--
src/conf/network_conf.c | 142 +++++++++++++++++++++---------
tools/virsh-network.c | 6 +-
4 files changed, 114 insertions(+), 51 deletions(-)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index fa038e4547..918e6db30c 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -5906,7 +5906,10 @@ changes optionally taking effect immediately, without needing to
destroy and re-start the network.
*command* is one of "add-first", "add-last", "add" (a synonym for
-add-last), "delete", or "modify".
+add-last), "delete", "modify", "modify-or-add" (modify + add-last), or
+"modify-or-add-first". The 'modify-or-add*' commands perform modify or
+add operation depending on the given state, and can be useful for
+scripting.
*section* is one of "bridge", "domain", "ip", "ip-dhcp-host",
"ip-dhcp-range", "forward", "forward-interface", "forward-pf",
diff --git a/include/libvirt/libvirt-network.h b/include/libvirt/libvirt-network.h
index 58591be7ac..bb4468b160 100644
--- a/include/libvirt/libvirt-network.h
+++ b/include/libvirt/libvirt-network.h
@@ -176,11 +176,13 @@ int virNetworkUndefine (virNetworkPtr network);
* Since: 0.10.2
*/
typedef enum {
- VIR_NETWORK_UPDATE_COMMAND_NONE = 0, /* invalid (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_MODIFY = 1, /* modify an existing element (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_DELETE = 2, /* delete an existing element (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_ADD_LAST = 3, /* add an element at end of list (Since: 0.10.2) */
- VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST = 4, /* add an element at start of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_NONE = 0, /* invalid (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY = 1, /* modify an existing element (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_DELETE = 2, /* delete an existing element (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_ADD_LAST = 3, /* add an element at end of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST = 4, /* add an element at start of list (Since: 0.10.2) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST = 5, /* conditionally modify or add an element at end (Since: 10.4.0) */
+ VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST = 6, /* conditionally modify or add an element at start (Since: 10.4.0) */
# ifdef VIR_ENUM_SENTINELS
VIR_NETWORK_UPDATE_COMMAND_LAST /* (Since: 0.10.2) */
# endif
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index cc92ed0b03..4f76257d06 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -2720,6 +2720,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
virNetworkIPDef *ipdef = virNetworkIPDefByIndex(def, parentIndex);
virNetworkDHCPHostDef host = { 0 };
bool partialOkay = (command == VIR_NETWORK_UPDATE_COMMAND_DELETE);
+ int foundMatchedEntry = -1, foundExactEntry = -1;
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
goto cleanup;
@@ -2740,22 +2741,47 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
}
- if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+ /* check if the entry already exsits */
+ for (i = 0; i < ipdef->nhosts; i++) {
- /* search for the entry with this (ip|mac|name),
- * and update the IP+(mac|name) */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((host.mac && ipdef->hosts[i].mac &&
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
- (VIR_SOCKET_ADDR_VALID(&host.ip) &&
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip)) ||
- (host.name &&
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name))) {
- break;
- }
+ /* try to match any of (ip|mac|name) attributes */
+ if ((host.mac && ipdef->hosts[i].mac &&
+ !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
+ (VIR_SOCKET_ADDR_VALID(&host.ip) &&
+ virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip)) ||
+ (host.name &&
+ STREQ_NULLABLE(host.name, ipdef->hosts[i].name))) {
+ foundMatchedEntry = i;
+ }
+
+ /* find exact entry - all attributes must match if they exist */
+ if ((!host.mac || !ipdef->hosts[i].mac ||
+ !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) &&
+ (!host.name ||
+ STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) &&
+ (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
+ virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
+ foundExactEntry = i;
+ break;
}
+ }
+
+ /* modify-or-add: convert command to add or modify based on foundEntry */
+ if (foundEntry == -1) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST;
+ else if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_LAST;
+ } else if (foundEntry >= 0) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_MODIFY;
+ }
+
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
- if (i == ipdef->nhosts) {
+ /* log error if no such entry exists to be modified */
+ if (foundMatchedEntry == -1) {
g_autofree char *ip = virSocketAddrFormat(&host.ip);
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't locate an existing dhcp host entry with \"mac='%1$s'\" \"name='%2$s'\" \"ip='%3$s'\" in network '%4$s'"),
@@ -2768,8 +2794,8 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
* then clear out the extra copy to get rid of the duplicate pointers
* to its data (mac and name strings).
*/
- virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
- ipdef->hosts[i] = host;
+ virNetworkDHCPHostDefClear(&ipdef->hosts[foundMatchedEntry]);
+ ipdef->hosts[foundMatchedEntry] = host;
memset(&host, 0, sizeof(host));
} else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
@@ -2779,21 +2805,13 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
/* log error if an entry with same name/address/ip already exists */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((host.mac && ipdef->hosts[i].mac &&
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
- (host.name &&
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) ||
- (VIR_SOCKET_ADDR_VALID(&host.ip) &&
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
- g_autofree char *ip = virSocketAddrFormat(&host.ip);
+ if (foundMatchedEntry >= 0) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("there is an existing dhcp host entry in network '%1$s' that matches \"<host mac='%2$s' name='%3$s' ip='%4$s'/>\""),
+ def->name, host.mac ? host.mac : _("unknown"),
+ host.name, ip ? ip : _("unknown"));
+ goto cleanup;
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("there is an existing dhcp host entry in network '%1$s' that matches \"<host mac='%2$s' name='%3$s' ip='%4$s'/>\""),
- def->name, host.mac ? host.mac : _("unknown"),
- host.name, ip ? ip : _("unknown"));
- goto cleanup;
- }
}
/* add to beginning/end of list */
@@ -2804,18 +2822,8 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
goto cleanup;
} else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
- /* find matching entry - all specified attributes must match */
- for (i = 0; i < ipdef->nhosts; i++) {
- if ((!host.mac || !ipdef->hosts[i].mac ||
- !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) &&
- (!host.name ||
- STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) &&
- (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
- virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
- break;
- }
- }
- if (i == ipdef->nhosts) {
+ /* log error if there is no entry with exact match*/
+ if (foundExactEntry == -1) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't locate a matching dhcp host entry in network '%1$s'"),
def->name);
@@ -2823,8 +2831,8 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
}
/* remove it */
- virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
- VIR_DELETE_ELEMENT(ipdef->hosts, i, ipdef->nhosts);
+ virNetworkDHCPHostDefClear(&ipdef->hosts[foundExactEntry]);
+ VIR_DELETE_ELEMENT(ipdef->hosts, foundExactEntry, ipdef->nhosts);
} else {
virNetworkDefUpdateUnknownCommand(command);
@@ -2865,6 +2873,14 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDef *def,
return -1;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("dhcp ranges cannot be modified, use add command instead of modify-or-add"));
+ return -1;
+ }
+
if (virNetworkDHCPRangeDefParseXML(def->name, ipdef, ctxt->node, &range) < 0)
return -1;
@@ -2964,6 +2980,13 @@ virNetworkDefUpdateForwardInterface(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("forward interface entries cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
/* parsing this is so simple that it doesn't have its own function */
iface.type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
if (!(iface.device.dev = virXMLPropString(ctxt->node, "dev"))) {
@@ -3085,6 +3108,18 @@ virNetworkDefUpdatePortGroup(virNetworkDef *def,
goto cleanup;
}
+ /* modify-or-add: convert command to add or modify based on foundName */
+ if (foundName == -1) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST;
+ else if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_ADD_LAST;
+ } else if (foundName >= 0) {
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST)
+ command = VIR_NETWORK_UPDATE_COMMAND_MODIFY;
+ }
+
/* if there is already a different default, we can't make this
* one the default.
*/
@@ -3153,6 +3188,13 @@ virNetworkDefUpdateDNSHost(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS HOST records cannot be modified, use add instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
goto cleanup;
@@ -3249,6 +3291,13 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS SRV records cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "srv") < 0)
goto cleanup;
@@ -3330,6 +3379,13 @@ virNetworkDefUpdateDNSTxt(virNetworkDef *def,
goto cleanup;
}
+ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_FIRST ||
+ command == VIR_NETWORK_UPDATE_COMMAND_MODIFY_ADD_LAST) {
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+ _("DNS TXT records cannot be modified, use add command instead of modify-or-add"));
+ goto cleanup;
+ }
+
if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "txt") < 0)
goto cleanup;
diff --git a/tools/virsh-network.c b/tools/virsh-network.c
index 6fcc7fd8ee..88eb673482 100644
--- a/tools/virsh-network.c
+++ b/tools/virsh-network.c
@@ -1215,7 +1215,8 @@ static const vshCmdOptDef opts_network_update[] = {
.positional = true,
.required = true,
.completer = virshNetworkUpdateCommandCompleter,
- .help = N_("type of update (add-first, add-last (add), delete, or modify)")
+ .help = N_("type of update (add-first, add-last (add), delete, modify,"
+ "modify-or-add, or modify-or-add-first)")
},
{.name = "section",
.type = VSH_OT_STRING,
@@ -1245,7 +1246,8 @@ static const vshCmdOptDef opts_network_update[] = {
VIR_ENUM_IMPL(virshNetworkUpdateCommand,
VIR_NETWORK_UPDATE_COMMAND_LAST,
- "none", "modify", "delete", "add-last", "add-first");
+ "none", "modify", "delete", "add-last", "add-first", "modify-or-add",
+ "modify-or-add-first");
VIR_ENUM_IMPL(virshNetworkSection,
VIR_NETWORK_SECTION_LAST,
--
2.39.2
9 months
[PATCH] docs: Fix broken links
by Han Han
For the links of drvinterface, drvnetwork, drvnwfilter, and Nagios-virt,
there are no alternative docs. Just remove them directly.
Signed-off-by: Han Han <hhan(a)redhat.com>
---
docs/apps.rst | 10 ++--------
docs/kbase/live_full_disk_backup.rst | 2 +-
docs/manpages/virt-sanlock-cleanup.rst | 2 +-
docs/manpages/virtinterfaced.rst | 1 -
docs/manpages/virtnetworkd.rst | 1 -
docs/manpages/virtnwfilterd.rst | 1 -
docs/manpages/virtstoraged.rst | 2 +-
docs/manpages/virtvzd.rst | 2 +-
docs/windows.rst | 2 +-
9 files changed, 7 insertions(+), 16 deletions(-)
diff --git a/docs/apps.rst b/docs/apps.rst
index b7d19e15d5..443c888c4d 100644
--- a/docs/apps.rst
+++ b/docs/apps.rst
@@ -35,7 +35,7 @@ virsh
machine to be cloned to form a new virtual machine. It automates
copying of data across to new disk images, and updates the UUID, MAC
address, and name in the configuration.
-`virt-df <https://people.redhat.com/rjones/virt-df/>`__
+`virt-df <https://libguestfs.org/virt-df.1.html>`__
Examine the utilization of each filesystem in a virtual machine from
the comfort of the host machine. This tool peeks into the guest disks
and determines how much space is used. It can cope with common Linux
@@ -235,13 +235,7 @@ Monitoring
The plugins provided by Guido G��nther allow to monitor various things
like network and block I/O with
`Munin <https://munin-monitoring.org/>`__.
-`Nagios-virt <https://people.redhat.com/rjones/nagios-virt/>`__
- Nagios-virt is a configuration tool to add monitoring of your
- virtualised domains to `Nagios <https://www.nagios.org/>`__. You can
- use this tool to either set up a new Nagios installation for your Xen
- or QEMU/KVM guests, or to integrate with your existing Nagios
- installation.
-`PCP <https://pcp.io/man/man1/pmdalibvirt.1.html>`__
+`PCP <https://man7.org/linux/man-pages/man1/pmdalibvirt.1.html>`__
The PCP libvirt PMDA (plugin) is part of the
`PCP <https://pcp.io/>`__ toolkit and provides hypervisor and guest
information and complete set of guest performance metrics. It
diff --git a/docs/kbase/live_full_disk_backup.rst b/docs/kbase/live_full_disk_backup.rst
index 562a9e87b0..f20169e314 100644
--- a/docs/kbase/live_full_disk_backup.rst
+++ b/docs/kbase/live_full_disk_backup.rst
@@ -12,7 +12,7 @@ space requirements. The following outlines an efficient method to do
that using libvirt's APIs. This method involves concepts: the notion of
`backing chains <https://libvirt.org/kbase/backing_chains.html>`_,
`QCOW2 overlays
-<https://qemu.readthedocs.io/en/latest/interop/live-block-operations.html#...>`_,
+<https://www.qemu.org/docs/master/interop/live-block-operations.html#disk-...>`_,
and a special operation called "active block-commit", which allows
live-merging an overlay disk image into its backing file.
diff --git a/docs/manpages/virt-sanlock-cleanup.rst b/docs/manpages/virt-sanlock-cleanup.rst
index 3ad70ce683..bf3ef6742b 100644
--- a/docs/manpages/virt-sanlock-cleanup.rst
+++ b/docs/manpages/virt-sanlock-cleanup.rst
@@ -75,5 +75,5 @@ PURPOSE
SEE ALSO
========
-virsh(1), `online instructions <https://libvirt.org/locking.html>`_,
+virsh(1), `online instructions <https://libvirt.org/kbase/locking.html>`_,
`https://libvirt.org/ <https://libvirt.org/>`_
diff --git a/docs/manpages/virtinterfaced.rst b/docs/manpages/virtinterfaced.rst
index 247a8c4009..ef63f4c278 100644
--- a/docs/manpages/virtinterfaced.rst
+++ b/docs/manpages/virtinterfaced.rst
@@ -211,4 +211,3 @@ SEE ALSO
virsh(1), libvirtd(8),
`https://libvirt.org/daemons.html <https://libvirt.org/daemons.html>`_,
-`https://libvirt.org/drvinterface.html <https://libvirt.org/drvinterface.html>`_
diff --git a/docs/manpages/virtnetworkd.rst b/docs/manpages/virtnetworkd.rst
index 22b3fc0f2d..3bd1dd3221 100644
--- a/docs/manpages/virtnetworkd.rst
+++ b/docs/manpages/virtnetworkd.rst
@@ -211,4 +211,3 @@ SEE ALSO
virsh(1), libvirtd(8),
`https://libvirt.org/daemons.html <https://libvirt.org/daemons.html>`_,
-`https://libvirt.org/drvnetwork.html <https://libvirt.org/drvnetwork.html>`_
diff --git a/docs/manpages/virtnwfilterd.rst b/docs/manpages/virtnwfilterd.rst
index b1fc45e7a2..1ec11c247f 100644
--- a/docs/manpages/virtnwfilterd.rst
+++ b/docs/manpages/virtnwfilterd.rst
@@ -211,4 +211,3 @@ SEE ALSO
virsh(1), libvirtd(8),
`https://libvirt.org/daemons.html <https://libvirt.org/daemons.html>`_,
-`https://libvirt.org/drvnwfilter.html <https://libvirt.org/drvnwfilter.html>`_
diff --git a/docs/manpages/virtstoraged.rst b/docs/manpages/virtstoraged.rst
index 70863282d1..fe966f3123 100644
--- a/docs/manpages/virtstoraged.rst
+++ b/docs/manpages/virtstoraged.rst
@@ -211,4 +211,4 @@ SEE ALSO
virsh(1), libvirtd(8),
`https://libvirt.org/daemons.html <https://libvirt.org/daemons.html>`_,
-`https://libvirt.org/drvstorage.html <https://libvirt.org/drvstorage.html>`_
+`https://libvirt.org/storage.html <https://libvirt.org/drvstorage.html>`_
diff --git a/docs/manpages/virtvzd.rst b/docs/manpages/virtvzd.rst
index aa44885d46..52aac2259c 100644
--- a/docs/manpages/virtvzd.rst
+++ b/docs/manpages/virtvzd.rst
@@ -211,4 +211,4 @@ SEE ALSO
virsh(1), libvirtd(8),
`https://libvirt.org/daemons.html <https://libvirt.org/daemons.html>`_,
-`https://libvirt.org/drvvz.html <https://libvirt.org/drvvz.html>`_
+`https://libvirt.org/drvopenvz.html <https://libvirt.org/drvopenvz.html>`_
diff --git a/docs/windows.rst b/docs/windows.rst
index b9aa5626cf..ee3caef41a 100644
--- a/docs/windows.rst
+++ b/docs/windows.rst
@@ -13,7 +13,7 @@ Installation packages
Users who need pre-built Windows DLLs of libvirt are advised to use the `Virt
Viewer <https://virt-manager.org>`__ pre-compiled `Windows MSI
-packages <https://virt-manager.org/download/>`__
+packages <https://virt-manager.org/download.html>`__
These installers include the libvirt, gtk-vnc and spice-gtk DLLs along with any
of their pre-requisite supporting DLLs, the virsh command line tool and the
--
2.45.1
9 months
[PATCH] virt-host-validate: Improve translatability of messages printed by 'virHostMsgCheck()'
by Peter Krempa
Move the word 'Checking' into the appropriate formatting strings and
mark all outstanding ones for translation.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/637
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
tools/virt-host-validate-bhyve.c | 2 +-
tools/virt-host-validate-ch.c | 2 +-
tools/virt-host-validate-common.c | 18 +++++++++---------
tools/virt-host-validate-qemu.c | 4 ++--
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/tools/virt-host-validate-bhyve.c b/tools/virt-host-validate-bhyve.c
index db1cdd8e2c..adb5ae1717 100644
--- a/tools/virt-host-validate-bhyve.c
+++ b/tools/virt-host-validate-bhyve.c
@@ -28,7 +28,7 @@
#include "virt-host-validate-common.h"
#define MODULE_STATUS(mod, err_msg, err_code) \
- virHostMsgCheck("BHYVE", _("for %1$s module"), #mod); \
+ virHostMsgCheck("BHYVE", _("Checking for %1$s module"), #mod); \
if (mod ## _loaded) { \
virHostMsgPass(); \
} else { \
diff --git a/tools/virt-host-validate-ch.c b/tools/virt-host-validate-ch.c
index 9d235ed7ab..3f96423836 100644
--- a/tools/virt-host-validate-ch.c
+++ b/tools/virt-host-validate-ch.c
@@ -57,7 +57,7 @@ int virHostValidateCh(void)
}
if (hasVirtFlag) {
- virHostMsgCheck("CH", "%s", _("for hardware virtualization"));
+ virHostMsgCheck("CH", "%s", _("Checking for hardware virtualization"));
if (hasHwVirt) {
virHostMsgPass();
} else {
diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c
index c8a23e2e99..58d8dbbaa1 100644
--- a/tools/virt-host-validate-common.c
+++ b/tools/virt-host-validate-common.c
@@ -66,7 +66,7 @@ void virHostMsgCheck(const char *prefix,
msg = g_strdup_vprintf(format, args);
va_end(args);
- fprintf(stdout, _("%1$6s: Checking %2$-60s: "), prefix, msg);
+ fprintf(stdout, "%1$6s: %2$-60s: ", prefix, msg);
}
static bool virHostMsgWantEscape(void)
@@ -137,7 +137,7 @@ int virHostValidateDeviceExists(const char *hvname,
virHostValidateLevel level,
const char *hint)
{
- virHostMsgCheck(hvname, "if device %s exists", dev_name);
+ virHostMsgCheck(hvname, _("Checking if device '%1$s' exists"), dev_name);
if (access(dev_name, F_OK) < 0) {
virHostMsgFail(level, "%s", hint);
@@ -154,7 +154,7 @@ int virHostValidateDeviceAccessible(const char *hvname,
virHostValidateLevel level,
const char *hint)
{
- virHostMsgCheck(hvname, "if device %s is accessible", dev_name);
+ virHostMsgCheck(hvname, _("Checking if device '%1$s' is accessible"), dev_name);
if (access(dev_name, R_OK|W_OK) < 0) {
virHostMsgFail(level, "%s", hint);
@@ -173,7 +173,7 @@ int virHostValidateNamespace(const char *hvname,
{
char nspath[100];
- virHostMsgCheck(hvname, "for namespace %s", ns_name);
+ virHostMsgCheck(hvname, _("Checking for namespace '%1$s'"), ns_name);
g_snprintf(nspath, sizeof(nspath), "/proc/self/ns/%s", ns_name);
@@ -256,7 +256,7 @@ int virHostValidateLinuxKernel(const char *hvname,
uname(&uts);
- virHostMsgCheck(hvname, _("for Linux >= %1$d.%2$d.%3$d"),
+ virHostMsgCheck(hvname, _("Checking for Linux >= %1$d.%2$d.%3$d"),
((version >> 16) & 0xff),
((version >> 8) & 0xff),
(version & 0xff));
@@ -302,7 +302,7 @@ int virHostValidateCGroupControllers(const char *hvname,
if (!(controllers & flag))
continue;
- virHostMsgCheck(hvname, "for cgroup '%s' controller support", cg_name);
+ virHostMsgCheck(hvname, _("Checking for cgroup '%1$s' controller support"), cg_name);
if (!virCgroupHasController(group, i)) {
ret = VIR_HOST_VALIDATE_FAILURE(level);
@@ -337,7 +337,7 @@ int virHostValidateIOMMU(const char *hvname,
struct dirent *dent;
int rc;
- virHostMsgCheck(hvname, "%s", _("for device assignment IOMMU support"));
+ virHostMsgCheck(hvname, "%s", _("Checking for device assignment IOMMU support"));
flags = virHostValidateGetCPUFlags();
@@ -423,7 +423,7 @@ int virHostValidateIOMMU(const char *hvname,
if (!S_ISDIR(sb.st_mode))
return 0;
- virHostMsgCheck(hvname, "%s", _("if IOMMU is enabled by kernel"));
+ virHostMsgCheck(hvname, "%s", _("Checking if IOMMU is enabled by kernel"));
if (sb.st_nlink <= 2) {
if (bootarg)
virHostMsgFail(level,
@@ -483,7 +483,7 @@ int virHostValidateSecureGuests(const char *hvname,
else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SEV))
hasAMDSev = true;
- virHostMsgCheck(hvname, "%s", _("for secure guest support"));
+ virHostMsgCheck(hvname, "%s", _("Checking for secure guest support"));
if (ARCH_IS_S390(arch)) {
if (hasFac158) {
if (!virFileIsDir("/sys/firmware/uv")) {
diff --git a/tools/virt-host-validate-qemu.c b/tools/virt-host-validate-qemu.c
index 3eeee516d3..b685fa01ba 100644
--- a/tools/virt-host-validate-qemu.c
+++ b/tools/virt-host-validate-qemu.c
@@ -64,7 +64,7 @@ int virHostValidateQEMU(void)
}
if (hasVirtFlag) {
- virHostMsgCheck("QEMU", "%s", _("for hardware virtualization"));
+ virHostMsgCheck("QEMU", "%s", _("Checking for hardware virtualization"));
if (hasHwVirt) {
virHostMsgPass();
} else {
@@ -86,7 +86,7 @@ int virHostValidateQEMU(void)
}
if (arch == VIR_ARCH_PPC64 || arch == VIR_ARCH_PPC64LE) {
- virHostMsgCheck("QEMU", "%s", _("for PowerPC KVM module loaded"));
+ virHostMsgCheck("QEMU", "%s", _("Checking for PowerPC KVM module loaded"));
if (!virHostKernelModuleIsLoaded("kvm_hv"))
virHostMsgFail(VIR_HOST_VALIDATE_WARN,
--
2.45.0
9 months
[PATCH] Сheck snapshot disk is not NULL when searching it in the VM config
by Fima Shevrin
When creating a snapshot of a VM with multiple hard disks,
the snapshot takes into account the presence of all disks
in the system. If, over time, one of the disks is deleted,
the snapshot will continue to store knowledge of the deleted disk.
This results in the fact that at the moment of deleting the snapshot,
at the validation stage, a disk from the snapshot will be searched which
is not in the VM configuration. As a result, vmdisk variable will
be equal to NULL. Dereferencing a null pointer at the time of calling
virStorageSourceIsSameLocation(vmdisk->src, disk->src) will result in SIGSEGV.
Signed-off-by: Fima Shevrin <efim.shevrin(a)virtuozzo.com>
---
src/qemu/qemu_snapshot.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 09ec959f10..bf93cd485e 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -3806,7 +3806,7 @@ qemuSnapshotDeleteValidate(virDomainObj *vm,
vmdisk = qemuDomainDiskByName(vm->def, snapDisk->name);
disk = qemuDomainDiskByName(snapdef->parent.dom, snapDisk->name);
- if (!virStorageSourceIsSameLocation(vmdisk->src, disk->src)) {
+ if (vmdisk != NULL && !virStorageSourceIsSameLocation(vmdisk->src, disk->src)) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("disk image '%1$s' for internal snapshot '%2$s' is not the same as disk image currently used by VM"),
snapDisk->name, snap->def->name);
--
2.34.1
9 months
Plans for 10.4.0 release (freeze on Tuesday 28 May)
by Jiri Denemark
We are getting close to 10.4.0 release of libvirt. To aim for the
release on Monday 03 Jun I suggest entering the freeze on Tuesday 28
May and tagging RC2 on Thursday 30 May.
I hope this works for everyone.
Jirka
9 months
[PATCH] rpc: avoid leak of GSource in use for interrupting main loop
by Daniel P. Berrangé
We never release the reference on the GSource created for
interrupting the main loop, nor do we remove it from the
main context if our thread is woken up prior to the wakeup
callback firing.
This can result in a leak of GSource objects, along with an
ever growing list of GSources attached to the main context,
which will gradually slow down execution of the loop, as
several operations are O(N) for the number of attached GSource
objects.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/rpc/virnetclient.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 147b0d661a..6d424eb599 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1946,7 +1946,7 @@ static int virNetClientIO(virNetClient *client,
/* Check to see if another thread is dispatching */
if (client->haveTheBuck) {
/* Force other thread to wakeup from poll */
- GSource *wakeup = g_idle_source_new();
+ g_autoptr(GSource) wakeup = g_idle_source_new();
g_source_set_callback(wakeup, virNetClientIOWakeup, client->eventLoop, NULL);
g_source_attach(wakeup, client->eventCtx);
@@ -1968,6 +1968,7 @@ static int virNetClientIO(virNetClient *client,
return -1;
}
+ g_source_destroy(wakeup);
VIR_DEBUG("Woken up from sleep head=%p call=%p",
client->waitDispatch, thiscall);
/* Three reasons we can be woken up
--
2.43.0
9 months
[PATCH] qemu: fix qemu command for pci hostdevs and ramfb='off'
by Jonathon Jongsma
There was no test for this and we mistakenly used 'B' rather than 'T'
when constructing the json value for this parameter. Thus, a value of
'off' was VIR_TRISTATE_SWITCH_OFF=2, which was translated to a boolean
value of 'true'.
Signed-off-by: Jonathon Jongsma <jjongsma(a)redhat.com>
---
src/qemu/qemu_command.c | 2 +-
.../hostdev-pci-display-ramfb.x86_64-latest.args | 1 +
.../hostdev-pci-display-ramfb.x86_64-latest.xml | 6 ++++++
tests/qemuxmlconfdata/hostdev-pci-display-ramfb.xml | 5 +++++
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 63bfeb790e..2d0eddc79e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4798,7 +4798,7 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def,
"p:bootindex", dev->info->effectiveBootIndex,
"S:failover_pair_id", failover_pair_id,
"S:display", qemuOnOffAuto(pcisrc->display),
- "B:ramfb", pcisrc->ramfb,
+ "T:ramfb", pcisrc->ramfb,
NULL) < 0)
return NULL;
diff --git a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.args b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.args
index 6a3bfbe6fb..e6e538ef1c 100644
--- a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.args
+++ b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.args
@@ -29,5 +29,6 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest2/.config \
-audiodev '{"id":"audio1","driver":"none"}' \
-vnc 127.0.0.1:0,audiodev=audio1 \
-device '{"driver":"vfio-pci-nohotplug","host":"0000:06:12.5","id":"hostdev0","display":"on","ramfb":true,"bus":"pci.0","addr":"0x2"}' \
+-device '{"driver":"vfio-pci","host":"0000:06:13.6","id":"hostdev1","display":"off","ramfb":false,"bus":"pci.0","addr":"0x3"}' \
-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
-msg timestamp=on
diff --git a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.xml b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.xml
index 16e8a1dee2..18b9bfb5bf 100644
--- a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.xml
+++ b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.x86_64-latest.xml
@@ -39,6 +39,12 @@
</source>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</hostdev>
+ <hostdev mode='subsystem' type='pci' managed='no' display='off' ramfb='off'>
+ <source>
+ <address domain='0x0000' bus='0x06' slot='0x13' function='0x6'/>
+ </source>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+ </hostdev>
<memballoon model='none'/>
</devices>
</domain>
diff --git a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.xml b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.xml
index 39c84da7e1..d263342b1d 100644
--- a/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.xml
+++ b/tests/qemuxmlconfdata/hostdev-pci-display-ramfb.xml
@@ -25,6 +25,11 @@
<address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/>
</source>
</hostdev>
+ <hostdev mode='subsystem' type='pci' display='off' ramfb='off'>
+ <source>
+ <address domain='0x0000' bus='0x06' slot='0x13' function='0x6'/>
+ </source>
+ </hostdev>
<video>
<model type='none'/>
</video>
--
2.45.0
9 months
[PATCH 0/2] Add support for hotplugging evdev input devices
by Rayhan Faizel
This patch series extends the current evdev device implementation to allow
hotplugging, including live attachment and detachment.
Resolves: https://gitlab.com/libvirt/libvirt/-/issues/529
Rayhan Faizel (2):
qemu: Implement support for hotplugging evdev input devices
qemuhotplugtest: Add testcases for hotplugging evdev input devices
src/qemu/qemu_command.c | 2 +-
src/qemu/qemu_command.h | 3 +
src/qemu/qemu_hotplug.c | 95 +++++++++++++------
tests/qemuhotplugtest.c | 5 +
.../qemuhotplug-input-evdev.xml | 3 +
.../qemuhotplug-base-live+input-evdev.xml | 58 +++++++++++
6 files changed, 137 insertions(+), 29 deletions(-)
create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-input-evdev.xml
create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+input-evdev.xml
--
2.34.1
9 months