From 61d699de0603ca49a67cc898a219cce2613b82ba Mon Sep 17 00:00:00 2001
From: K Shiva Kiran <shiva_kr(a)riseup.net>
Date: Tue, 27 Jun 2023 20:48:52 +0530
Subject: [libvirt PATCH v2 2/4] Adding Public Get and Set APIs for
Network Metadata
This patch introduces public Get and Set APIs for modifying <title>,
<description> and <metadata> elements of the Network object.
- Added enum to select one of the above elements to operate on.
- Added error code and messages for missing metadata.
- Added public API implementation.
- Added driver support.
- Defined wire protocol format.
---
This is a v2 of:
https://listman.redhat.com/archives/libvir-list/2023-July/240666.html
include/libvirt/libvirt-network.h | 29 ++++++
include/libvirt/virterror.h | 1 +
src/driver-network.h | 16 +++
src/libvirt-network.c | 167 ++++++++++++++++++++++++++++++
src/libvirt_public.syms | 6 ++
src/remote/remote_driver.c | 2 +
src/remote/remote_protocol.x | 36 ++++++-
src/remote_protocol-structs | 19 ++++
src/util/virerror.c | 3 +
9 files changed, 278 insertions(+), 1 deletion(-)
diff --git a/include/libvirt/libvirt-network.h
b/include/libvirt/libvirt-network.h
index 90cde0cf24..147dc8c6b8 100644
--- a/include/libvirt/libvirt-network.h
+++ b/include/libvirt/libvirt-network.h
@@ -547,4 +547,33 @@ virNetworkPortFree(virNetworkPortPtr port);
int
virNetworkPortRef(virNetworkPortPtr port);
+/**
+ * virNetworkMetadataType:
+ *
+ * Since: 9.6.0
+ */
+typedef enum {
+ VIR_NETWORK_METADATA_DESCRIPTION = 0, /* Operate on <description>
(Since: 9.6.0) */
+ VIR_NETWORK_METADATA_TITLE = 1, /* Operate on <title> (Since:
9.6.0) */
+ VIR_NETWORK_METADATA_ELEMENT = 2, /* Operate on <metadata>
(Since: 9.6.0) */
+
+# ifdef VIR_ENUM_SENTINELS
+ VIR_NETWORK_METADATA_LAST /* (Since: 9.6.0) */
+# endif
+} virNetworkMetadataType;
+
+int
+virNetworkSetMetadata(virNetworkPtr network,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags);
+
+char *
+virNetworkGetMetadata(virNetworkPtr network,
+ int type,
+ const char *uri,
+ unsigned int flags);
+
#endif /* LIBVIRT_NETWORK_H */
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index df13e4f11e..55bc4431d9 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -348,6 +348,7 @@ typedef enum {
VIR_ERR_NO_HOSTNAME = 108, /* no domain's hostname found
(Since: 6.1.0) */
VIR_ERR_CHECKPOINT_INCONSISTENT = 109, /* checkpoint can't be used
(Since: 6.10.0) */
VIR_ERR_MULTIPLE_DOMAINS = 110, /* more than one matching
domain found (Since: 7.1.0) */
+ VIR_ERR_NO_NETWORK_METADATA = 111, /* Network metadata is not
present (Since: 9.6.0) */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_NUMBER_LAST /* (Since: 5.0.0) */
diff --git a/src/driver-network.h b/src/driver-network.h
index 99efd4c8aa..1d19b013c9 100644
--- a/src/driver-network.h
+++ b/src/driver-network.h
@@ -161,6 +161,20 @@ typedef int
virNetworkPortPtr **ports,
unsigned int flags);
+typedef int
+(*virDrvNetworkSetMetadata)(virNetworkPtr network,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags);
+
+typedef char *
+(*virDrvNetworkGetMetadata)(virNetworkPtr network,
+ int type,
+ const char *uri,
+ unsigned int flags);
+
typedef struct _virNetworkDriver virNetworkDriver;
/**
@@ -202,4 +216,6 @@ struct _virNetworkDriver {
virDrvNetworkPortGetParameters networkPortGetParameters;
virDrvNetworkPortDelete networkPortDelete;
virDrvNetworkListAllPorts networkListAllPorts;
+ virDrvNetworkSetMetadata networkSetMetadata;
+ virDrvNetworkGetMetadata networkGetMetadata;
};
diff --git a/src/libvirt-network.c b/src/libvirt-network.c
index 236dfe2f5d..2dd11cf205 100644
--- a/src/libvirt-network.c
+++ b/src/libvirt-network.c
@@ -1915,3 +1915,170 @@ virNetworkPortRef(virNetworkPortPtr port)
virObjectRef(port);
return 0;
}
+
+
+/**
+ * virNetworkSetMetadata:
+ * @network: a network object
+ * @type: type of metadata, from virNetworkMetadataType
+ * @metadata: new metadata text
+ * @key: XML namespace key, or NULL
+ * @uri: XML namespace URI, or NULL
+ * @flags: bitwise-OR of virNetworkUpdateFlags
+ *
+ * Sets the appropriate network element given by @type to the
+ * value of @metadata. A @type of VIR_NETWORK_METADATA_DESCRIPTION
+ * is free-form text; VIR_NETWORK_METADATA_TITLE is free-form, but no
+ * newlines are permitted, and should be short (although the length is
+ * not enforced). For these two options @key and @uri are irrelevant and
+ * must be set to NULL.
+ *
+ * For type VIR_NETWORK_METADATA_ELEMENT @metadata must be well-formed
+ * XML belonging to namespace defined by @uri with local name @key.
+ *
+ * Passing NULL for @metadata says to remove that element from the
+ * network XML (passing the empty string leaves the element present).
+ *
+ * The resulting metadata will be present in virNetworkGetXMLDesc(),
+ * as well as quick access through virNetworkGetMetadata().
+ *
+ * @flags controls whether the live network state, persistent
configuration,
+ * or both will be modified.
+ *
+ * Returns 0 on success, -1 in case of failure.
+ *
+ * Since: 9.6.0
+ */
+int
+virNetworkSetMetadata(virNetworkPtr network,
+ int type,
+ const char *metadata,
+ const char *key,
+ const char *uri,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DEBUG("network=%p, type=%d, metadata='%s', key='%s',
uri='%s',
flags=0x%x",
+ network, type, NULLSTR(metadata), NULLSTR(key), NULLSTR(uri),
+ flags);
+
+ virResetLastError();
+
+ virCheckNetworkReturn(network, -1);
+ conn = network->conn;
+
+ virCheckReadOnlyGoto(conn->flags, error);
+
+ switch (type) {
+ case VIR_NETWORK_METADATA_TITLE:
+ if (metadata && strchr(metadata, '\n')) {
+ virReportInvalidArg(metadata, "%s",
+ _("metadata title can't contain "
+ "newlines"));
+ goto error;
+ }
+ G_GNUC_FALLTHROUGH;
+ case VIR_NETWORK_METADATA_DESCRIPTION:
+ virCheckNullArgGoto(uri, error);
+ virCheckNullArgGoto(key, error);
+ break;
+ case VIR_NETWORK_METADATA_ELEMENT:
+ virCheckNonNullArgGoto(uri, error);
+ if (metadata)
+ virCheckNonNullArgGoto(key, error);
+ break;
+ default:
+ /* For future expansion */
+ break;
+ }
+
+ if (conn->networkDriver->networkSetMetadata) {
+ int ret;
+ ret = conn->networkDriver->networkSetMetadata(network, type,
metadata, key, uri,
+ flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(network->conn);
+ return -1;
+}
+
+
+/**
+ * virNetworkGetMetadata:
+ * @network: a network object
+ * @type: type of metadata, from virNetworkMetadataType
+ * @uri: XML namespace identifier
+ * @flags: bitwise-OR of virNetworkUpdateFlags
+ *
+ * Retrieves the appropriate network element given by @type.
+ * If VIR_NETWORK_METADATA_ELEMENT is requested parameter @uri
+ * must be set to the name of the namespace the requested elements
+ * belong to, otherwise must be NULL.
+ *
+ * If an element of the network XML is not present, the resulting
+ * error will be VIR_ERR_NO_NETWORK_METADATA. This method forms
+ * a shortcut for seeing information from virNetworkSetMetadata()
+ * without having to go through virNetworkGetXMLDesc().
+ *
+ * @flags controls whether the live network state or persistent
+ * configuration will be queried.
+ *
+ * Returns the metadata string on success (caller must free),
+ * or NULL in case of failure.
+ *
+ * Since: 9.6.0
+ */
+char *
+virNetworkGetMetadata(virNetworkPtr network,
+ int type,
+ const char *uri,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DEBUG("network=%p, type=%d, uri='%s', flags=0x%x",
+ network, type, NULLSTR(uri), flags);
+
+ virResetLastError();
+
+ virCheckNetworkReturn(network, NULL);
+
+ VIR_EXCLUSIVE_FLAGS_GOTO(VIR_NETWORK_UPDATE_AFFECT_LIVE,
+ VIR_NETWORK_UPDATE_AFFECT_CONFIG,
+ error);
+
+ switch (type) {
+ case VIR_NETWORK_METADATA_TITLE:
+ case VIR_NETWORK_METADATA_DESCRIPTION:
+ virCheckNullArgGoto(uri, error);
+ break;
+ case VIR_NETWORK_METADATA_ELEMENT:
+ virCheckNonNullArgGoto(uri, error);
+ break;
+ default:
+ /* For future expansion */
+ break;
+ }
+
+ conn = network->conn;
+
+ if (conn->networkDriver->networkGetMetadata) {
+ char *ret;
+ if (!(ret = conn->networkDriver->networkGetMetadata(network,
type, uri, flags)))
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(network->conn);
+ return NULL;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 80742f268e..4523700a0f 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -932,4 +932,10 @@ LIBVIRT_9.0.0 {
virDomainFDAssociate;
} LIBVIRT_8.5.0;
+LIBVIRT_9.6.0 {
+ global:
+ virNetworkGetMetadata;
+ virNetworkSetMetadata;
+} LIBVIRT_9.0.0;
+
# .... define new API here using predicted next version number ....
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 65ec239fb7..4e277f668a 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -8160,6 +8160,8 @@ static virNetworkDriver network_driver = {
.networkPortSetParameters = remoteNetworkPortSetParameters, /*
5.5.0 */
.networkPortGetParameters = remoteNetworkPortGetParameters, /*
5.5.0 */
.networkPortDelete = remoteNetworkPortDelete, /* 5.5.0 */
+ .networkSetMetadata = remoteNetworkSetMetadata, /* 9.6.0 */
+ .networkGetMetadata = remoteNetworkGetMetadata, /* 9.6.0 */
};
static virInterfaceDriver interface_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 5d86a51116..7ff059e393 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3323,6 +3323,26 @@ struct remote_network_event_lifecycle_msg {
int detail;
};
+struct remote_network_set_metadata_args {
+ remote_nonnull_network network;
+ int type;
+ remote_string metadata;
+ remote_string key;
+ remote_string uri;
+ unsigned int flags;
+};
+
+struct remote_network_get_metadata_args {
+ remote_nonnull_network network;
+ int type;
+ remote_string uri;
+ unsigned int flags;
+};
+
+struct remote_network_get_metadata_ret {
+ remote_nonnull_string metadata;
+};
+
struct remote_connect_storage_pool_event_register_any_args {
int eventID;
remote_storage_pool pool;
@@ -6974,5 +6994,19 @@ enum remote_procedure {
* @generate: none
* @acl: domain:write
*/
- REMOTE_PROC_DOMAIN_FD_ASSOCIATE = 443
+ REMOTE_PROC_DOMAIN_FD_ASSOCIATE = 443,
+
+ /**
+ * @generate: both
+ * @acl: network:write
+ * @acl:
network:save:!VIR_NETWORK_UPDATE_AFFECT_CONFIG|VIR_NETWORK_UPDATE_AFFECT_LIVE
+ * @acl: network:save:VIR_NETWORK_UPDATE_AFFECT_CONFIG
+ */
+ REMOTE_PROC_NETWORK_SET_METADATA = 444,
+
+ /**
+ * @generate: both
+ * @acl: network:read
+ */
+ REMOTE_PROC_NETWORK_GET_METADATA = 445
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 3c6c230a16..c07e0af1e6 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2687,6 +2687,23 @@ struct remote_network_event_lifecycle_msg {
int event;
int detail;
};
+struct remote_network_set_metadata_args {
+ remote_nonnull_network network;
+ int type;
+ remote_string metadata;
+ remote_string key;
+ remote_string uri;
+ u_int flags;
+};
+struct remote_network_get_metadata_args {
+ remote_nonnull_network network;
+ int type;
+ remote_string uri;
+ u_int flags;
+};
+struct remote_network_get_metadata_ret {
+ remote_nonnull_string metadata;
+};
struct remote_connect_storage_pool_event_register_any_args {
int eventID;
remote_storage_pool pool;
@@ -3717,4 +3734,6 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_RESTORE_PARAMS = 441,
REMOTE_PROC_DOMAIN_ABORT_JOB_FLAGS = 442,
REMOTE_PROC_DOMAIN_FD_ASSOCIATE = 443,
+ REMOTE_PROC_NETWORK_SET_METADATA = 444,
+ REMOTE_PROC_NETWORK_GET_METADATA = 445,
};
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 453f19514e..227a182417 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -1287,6 +1287,9 @@ static const virErrorMsgTuple virErrorMsgStrings[] = {
[VIR_ERR_MULTIPLE_DOMAINS] = {
N_("multiple matching domains found"),
N_("multiple matching domains found: %1$s") },
+ [VIR_ERR_NO_NETWORK_METADATA] = {
+ N_("metadata not found"),
+ N_("metadata not found: %1$s") },
};
G_STATIC_ASSERT(G_N_ELEMENTS(virErrorMsgStrings) == VIR_ERR_NUMBER_LAST);
--
2.41.0