[libvirt] [libvirt-glib] More coverage for networking API v2

Fixed the compiler warnings introduced by one of the patches.

Add a wrapper for virInterfaceGetMACString(). --- libvirt-gobject/libvirt-gobject-interface.c | 13 +++++++++++++ libvirt-gobject/libvirt-gobject-interface.h | 1 + libvirt-gobject/libvirt-gobject.sym | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-interface.c b/libvirt-gobject/libvirt-gobject-interface.c index 1fc6656..6b2df59 100644 --- a/libvirt-gobject/libvirt-gobject-interface.c +++ b/libvirt-gobject/libvirt-gobject-interface.c @@ -171,6 +171,19 @@ const gchar *gvir_interface_get_name(GVirInterface *iface) return name; } +const gchar *gvir_interface_get_mac(GVirInterface *iface) +{ + const char *mac; + + g_return_val_if_fail(GVIR_IS_INTERFACE(iface), NULL); + + if (!(mac = virInterfaceGetMACString(iface->priv->handle))) { + gvir_warning("Failed to get interface mac on %p", iface->priv->handle); + return NULL; + } + + return mac; +} /** * gvir_interface_get_config: diff --git a/libvirt-gobject/libvirt-gobject-interface.h b/libvirt-gobject/libvirt-gobject-interface.h index f437bc7..a8776e5 100644 --- a/libvirt-gobject/libvirt-gobject-interface.h +++ b/libvirt-gobject/libvirt-gobject-interface.h @@ -63,6 +63,7 @@ GType gvir_interface_get_type(void); GType gvir_interface_handle_get_type(void); const gchar *gvir_interface_get_name(GVirInterface *iface); +const gchar *gvir_interface_get_mac(GVirInterface *iface); GVirConfigInterface *gvir_interface_get_config(GVirInterface *iface, guint flags, diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index dcda675..29c4349 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -271,4 +271,9 @@ LIBVIRT_GOBJECT_0.2.1 { gvir_storage_pool_set_autostart; } LIBVIRT_GOBJECT_0.2.0; +LIBVIRT_GOBJECT_0.2.2 { + global: + gvir_interface_get_mac; +} LIBVIRT_GOBJECT_0.2.1; + # .... define new API here using predicted next version number .... -- 2.4.2

ACK. On Mon, Jun 29, 2015 at 03:08:51PM +0100, Zeeshan Ali (Khattak) wrote:
Add a wrapper for virInterfaceGetMACString(). --- libvirt-gobject/libvirt-gobject-interface.c | 13 +++++++++++++ libvirt-gobject/libvirt-gobject-interface.h | 1 + libvirt-gobject/libvirt-gobject.sym | 5 +++++ 3 files changed, 19 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-interface.c b/libvirt-gobject/libvirt-gobject-interface.c index 1fc6656..6b2df59 100644 --- a/libvirt-gobject/libvirt-gobject-interface.c +++ b/libvirt-gobject/libvirt-gobject-interface.c @@ -171,6 +171,19 @@ const gchar *gvir_interface_get_name(GVirInterface *iface) return name; }
+const gchar *gvir_interface_get_mac(GVirInterface *iface) +{ + const char *mac; + + g_return_val_if_fail(GVIR_IS_INTERFACE(iface), NULL); + + if (!(mac = virInterfaceGetMACString(iface->priv->handle))) { + gvir_warning("Failed to get interface mac on %p", iface->priv->handle); + return NULL; + } + + return mac; +}
/** * gvir_interface_get_config: diff --git a/libvirt-gobject/libvirt-gobject-interface.h b/libvirt-gobject/libvirt-gobject-interface.h index f437bc7..a8776e5 100644 --- a/libvirt-gobject/libvirt-gobject-interface.h +++ b/libvirt-gobject/libvirt-gobject-interface.h @@ -63,6 +63,7 @@ GType gvir_interface_get_type(void); GType gvir_interface_handle_get_type(void);
const gchar *gvir_interface_get_name(GVirInterface *iface); +const gchar *gvir_interface_get_mac(GVirInterface *iface);
GVirConfigInterface *gvir_interface_get_config(GVirInterface *iface, guint flags, diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index dcda675..29c4349 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -271,4 +271,9 @@ LIBVIRT_GOBJECT_0.2.1 { gvir_storage_pool_set_autostart; } LIBVIRT_GOBJECT_0.2.0;
+LIBVIRT_GOBJECT_0.2.2 { + global: + gvir_interface_get_mac; +} LIBVIRT_GOBJECT_0.2.1; + # .... define new API here using predicted next version number .... -- 2.4.2
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

Add API to query network interfaces from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 226 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 6 +- libvirt-gobject/libvirt-gobject.sym | 5 + 3 files changed, 235 insertions(+), 2 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index cf073a5..20c43fc 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -44,6 +44,7 @@ struct _GVirConnectionPrivate GHashTable *domains; GHashTable *pools; + GHashTable *interfaces; }; G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -252,6 +253,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); } @@ -668,6 +673,11 @@ void gvir_connection_close(GVirConnection *conn) priv->pools = NULL; } + if (priv->interfaces) { + g_hash_table_unref(priv->interfaces); + priv->interfaces = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1588,6 +1598,222 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, } /** + * gvir_connection_fetch_interfaces: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + */ +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *interfaces; + gchar **inactive = NULL; + gint ninactive = 0; + gchar **active = NULL; + gint nactive = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + GError *lerr = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + active = fetch_list(vconn, + "Interfaces", + virConnectNumOfInterfaces, + virConnectListInterfaces, + cancellable, + &nactive, + &lerr); + if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + inactive = fetch_list(vconn, + "Interfaces", + virConnectNumOfDefinedInterfaces, + virConnectListDefinedInterfaces, + cancellable, + &ninactive, + &lerr); + if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < nactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virInterfacePtr viface; + GVirInterface *iface; + + viface = virInterfaceLookupByName(vconn, active[i]); + if (!viface) + continue; + + iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", viface, + NULL)); + virInterfaceFree(viface); + + g_hash_table_insert(interfaces, + active[i], + iface); + } + + for (i = 0 ; i < ninactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virInterfacePtr viface; + GVirInterface *iface; + + viface = virInterfaceLookupByName(vconn, inactive[i]); + if (!viface) + continue; + + iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", viface, + NULL)); + virInterfaceFree(viface); + + g_hash_table_insert(interfaces, + active[i], + iface); + } + + g_mutex_lock(priv->lock); + if (priv->interfaces) + g_hash_table_unref(priv->interfaces); + priv->interfaces = interfaces; + virConnectClose(vconn); + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + for (i = 0 ; i < nactive ; i++) + g_free(active[i]); + g_free(active); + for (i = 0 ; i < ninactive ; i++) + g_free(inactive[i]); + g_free(inactive); + return ret; +} + +/** + * gvir_connection_get_interfaces: + * @conn: a #GVirConnection + * + * Gets a list of all the network interfaces available through @conn. + * + * Return value: (element-type LibvirtGObject.Interface) (transfer full): List + * of #GVirInterface. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_interfaces(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *interfaces = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->interfaces != NULL) { + interfaces = g_hash_table_get_values(priv->interfaces); + g_list_foreach(interfaces, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return interfaces; +} + +GVirInterface *gvir_connection_get_interface(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GVirInterface *iface; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + iface = g_hash_table_lookup(priv->interfaces, name); + if (iface) + g_object_ref(iface); + g_mutex_unlock(priv->lock); + + return iface; +} + +GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, + const gchar *mac) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(mac != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->interfaces); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirInterface *iface = value; + const gchar *thismac = gvir_interface_get_mac(iface); + + if (thismac == NULL) + continue; + + if (strcmp(thismac, mac) == 0) { + g_object_ref(iface); + g_mutex_unlock(priv->lock); + return iface; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 8bca8d4..77079b6 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -144,14 +144,16 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, guint flags, GError **err); -#if 0 +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err); GList *gvir_connection_get_interfaces(GVirConnection *conn); GVirInterface *gvir_connection_get_interface(GVirConnection *conn, const gchar *name); GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr); - +#if 0 GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..b7ce1d5 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,11 @@ LIBVIRT_GOBJECT_0.2.1 { LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces; + gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1; -- 2.4.2

On Mon, Jun 29, 2015 at 03:08:52PM +0100, Zeeshan Ali (Khattak) wrote:
Add API to query network interfaces from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 226 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 6 +- libvirt-gobject/libvirt-gobject.sym | 5 + 3 files changed, 235 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index cf073a5..20c43fc 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -44,6 +44,7 @@ struct _GVirConnectionPrivate
GHashTable *domains; GHashTable *pools; + GHashTable *interfaces; };
G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -252,6 +253,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); }
@@ -668,6 +673,11 @@ void gvir_connection_close(GVirConnection *conn) priv->pools = NULL; }
+ if (priv->interfaces) { + g_hash_table_unref(priv->interfaces); + priv->interfaces = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1588,6 +1598,222 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, }
/** + * gvir_connection_fetch_interfaces: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + */
Some more detailed API doc here would be nice.
+gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *interfaces; + gchar **inactive = NULL; + gint ninactive = 0; + gchar **active = NULL; + gint nactive = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + GError *lerr = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + active = fetch_list(vconn, + "Interfaces", + virConnectNumOfInterfaces, + virConnectListInterfaces, + cancellable, + &nactive, + &lerr);
Would it be possible to use virConnectListAllInterfaces() rather than this awkward split between active/inactive interfaces? (which is also likely to be racy if one interface becomes active between the 2 fetch_list calls).
+ if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + inactive = fetch_list(vconn, + "Interfaces", + virConnectNumOfDefinedInterfaces, + virConnectListDefinedInterfaces, + cancellable, + &ninactive, + &lerr); + if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < nactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virInterfacePtr viface; + GVirInterface *iface; + + viface = virInterfaceLookupByName(vconn, active[i]); + if (!viface) + continue; + + iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", viface, + NULL)); + virInterfaceFree(viface); + + g_hash_table_insert(interfaces, + active[i], + iface); + } + + for (i = 0 ; i < ninactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virInterfacePtr viface; + GVirInterface *iface; + + viface = virInterfaceLookupByName(vconn, inactive[i]); + if (!viface) + continue; + + iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", viface, + NULL)); + virInterfaceFree(viface); + + g_hash_table_insert(interfaces, + active[i],
inactive[i]
+ iface); + } + + g_mutex_lock(priv->lock); + if (priv->interfaces) + g_hash_table_unref(priv->interfaces); + priv->interfaces = interfaces; + virConnectClose(vconn);
Code you used as a basis has the same bug, but this virConnectClose() needs to be done in cleanup: as this must match virConnectRef().
+ g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + for (i = 0 ; i < nactive ; i++) + g_free(active[i]); + g_free(active); + for (i = 0 ; i < ninactive ; i++) + g_free(inactive[i]); + g_free(inactive);
These g_free() should be free() as they were allocated by libvirt.
+ return ret; +} + +/** + * gvir_connection_get_interfaces: + * @conn: a #GVirConnection + * + * Gets a list of all the network interfaces available through @conn.
I'd make it clearer that these are the host-side network interfaces.
+ * + * Return value: (element-type LibvirtGObject.Interface) (transfer full): List + * of #GVirInterface. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_interfaces(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *interfaces = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->interfaces != NULL) { + interfaces = g_hash_table_get_values(priv->interfaces); + g_list_foreach(interfaces, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return interfaces; +} + +GVirInterface *gvir_connection_get_interface(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GVirInterface *iface; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + iface = g_hash_table_lookup(priv->interfaces, name); + if (iface) + g_object_ref(iface); + g_mutex_unlock(priv->lock); + + return iface; +} + +GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, + const gchar *mac) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(mac != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->interfaces); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirInterface *iface = value; + const gchar *thismac = gvir_interface_get_mac(iface); + + if (thismac == NULL) + continue; + + if (strcmp(thismac, mac) == 0) {
Alternatively, could be g_strcmp0(thismac, mac); without the explicit NULL check, but it's fine your way.
+ g_object_ref(iface); + g_mutex_unlock(priv->lock); + return iface; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 8bca8d4..77079b6 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -144,14 +144,16 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, guint flags, GError **err);
-#if 0 +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err); GList *gvir_connection_get_interfaces(GVirConnection *conn); GVirInterface *gvir_connection_get_interface(GVirConnection *conn, const gchar *name); GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr);
- +#if 0 GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..b7ce1d5 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,11 @@ LIBVIRT_GOBJECT_0.2.1 {
LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces;
No async variant ? Christophe
+ gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1;
-- 2.4.2
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

Hi Christophe, Thanks for reviewing.
+gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *interfaces; + gchar **inactive = NULL; + gint ninactive = 0; + gchar **active = NULL; + gint nactive = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + GError *lerr = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + active = fetch_list(vconn, + "Interfaces", + virConnectNumOfInterfaces, + virConnectListInterfaces, + cancellable, + &nactive, + &lerr);
Would it be possible to use virConnectListAllInterfaces() rather than this awkward split between active/inactive interfaces? (which is also likely to be racy if one interface becomes active between the 2 fetch_list calls).
Yeah I was just using existing code as bases for this. I'll change other code too..
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..b7ce1d5 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,11 @@ LIBVIRT_GOBJECT_0.2.1 {
LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces;
No async variant ?
Christophe
+ gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1;
The existing _fetch() methods don't have async variants so I didn't add here either. I'll look into adding those.. -- Regards, Zeeshan Ali (Khattak) ________________________________________ Befriend GNOME: http://www.gnome.org/friends/

On Tue, Jun 30, 2015 at 01:22:18PM +0100, Zeeshan Ali (Khattak) wrote:
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..b7ce1d5 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,11 @@ LIBVIRT_GOBJECT_0.2.1 {
LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces;
No async variant ?
+ gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1;
The existing _fetch() methods don't have async variants so I didn't add here either. I'll look into adding those..
There are gvir_connection_fetch_domains_async() and gvir_connection_fetch_storage_pools_async() , I don't think I would have thought about this otherwise ;) Christophe

Add API to query networks from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 226 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 6 +- libvirt-gobject/libvirt-gobject.sym | 4 + 3 files changed, 234 insertions(+), 2 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index 20c43fc..eea2eed 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -45,6 +45,7 @@ struct _GVirConnectionPrivate GHashTable *domains; GHashTable *pools; GHashTable *interfaces; + GHashTable *networks; }; G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -257,6 +258,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); } @@ -678,6 +683,11 @@ void gvir_connection_close(GVirConnection *conn) priv->interfaces = NULL; } + if (priv->networks) { + g_hash_table_unref(priv->networks); + priv->networks = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1814,6 +1824,222 @@ GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, } /** + * gvir_connection_fetch_networks: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + */ +gboolean gvir_connection_fetch_networks(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *networks; + gchar **inactive = NULL; + gint ninactive = 0; + gchar **active = NULL; + gint nactive = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + GError *lerr = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + active = fetch_list(vconn, + "Networks", + virConnectNumOfNetworks, + virConnectListNetworks, + cancellable, + &nactive, + &lerr); + if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + inactive = fetch_list(vconn, + "Networks", + virConnectNumOfDefinedNetworks, + virConnectListDefinedNetworks, + cancellable, + &ninactive, + &lerr); + if (lerr) { + g_propagate_error(err, lerr); + lerr = NULL; + goto cleanup; + } + + networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < nactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virNetworkPtr vnetwork; + GVirNetwork *network; + + vnetwork = virNetworkLookupByName(vconn, active[i]); + if (!vnetwork) + continue; + + network = GVIR_NETWORK(g_object_new(GVIR_TYPE_NETWORK, + "handle", vnetwork, + NULL)); + virNetworkFree(vnetwork); + + g_hash_table_insert(networks, + (gpointer)gvir_network_get_uuid(network), + network); + } + + for (i = 0 ; i < ninactive ; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + virNetworkPtr vnetwork; + GVirNetwork *network; + + vnetwork = virNetworkLookupByName(vconn, inactive[i]); + if (!vnetwork) + continue; + + network = GVIR_NETWORK(g_object_new(GVIR_TYPE_NETWORK, + "handle", vnetwork, + NULL)); + virNetworkFree(vnetwork); + + g_hash_table_insert(networks, + (gpointer)gvir_network_get_uuid(network), + network); + } + + g_mutex_lock(priv->lock); + if (priv->networks) + g_hash_table_unref(priv->networks); + priv->networks = networks; + virConnectClose(vconn); + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + for (i = 0 ; i < nactive ; i++) + g_free(active[i]); + g_free(active); + for (i = 0 ; i < ninactive ; i++) + g_free(inactive[i]); + g_free(inactive); + return ret; +} + +/** + * gvir_connection_get_networks: + * @conn: a #GVirConnection + * + * Gets a list of all the network networks available through @conn. + * + * Return value: (element-type LibvirtGObject.Network) (transfer full): List + * of #GVirNetwork. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_networks(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *networks = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->networks != NULL) { + networks = g_hash_table_get_values(priv->networks); + g_list_foreach(networks, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return networks; +} + +GVirNetwork *gvir_connection_get_network(GVirConnection *conn, + const gchar *uuid) +{ + GVirConnectionPrivate *priv; + GVirNetwork *network; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(uuid != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + network = g_hash_table_lookup(priv->networks, uuid); + if (network) + g_object_ref(network); + g_mutex_unlock(priv->lock); + + return network; +} + +GVirNetwork *gvir_connection_find_network_by_name(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->networks); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirNetwork *network = value; + const gchar *thisname = gvir_network_get_name(network); + + if (thisname == NULL) + continue; + + if (strcmp(thisname, name) == 0) { + g_object_ref(network); + g_mutex_unlock(priv->lock); + return network; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 77079b6..89b062b 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -153,14 +153,16 @@ GVirInterface *gvir_connection_get_interface(GVirConnection *conn, GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr); -#if 0 +gboolean gvir_connection_fetch_networks(GVirConnection *conn, + GCancellable *cancellable, + GError **err); GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); GVirNetwork *gvir_connection_find_network_by_name(GVirConnection *conn, const gchar *name); - +#if 0 GList *gvir_connection_get_network_filters(GVirConnection *conn); GVirNetworkFilter *gvir_connection_get_network_filter(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index b7ce1d5..085c410 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -274,9 +274,13 @@ LIBVIRT_GOBJECT_0.2.1 { LIBVIRT_GOBJECT_0.2.2 { global: gvir_connection_fetch_interfaces; + gvir_connection_fetch_networks; gvir_connection_find_interface_by_mac; + gvir_connection_find_network_by_name; gvir_connection_get_interface; gvir_connection_get_interfaces; + gvir_connection_get_network; + gvir_connection_get_networks; gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1; -- 2.4.2

Hey, Exactly the same comments/questions as 2/5 apply here, I forgot to ask for API doc for gvir_connection_find_network_by_name and gvir_connection_get_network in the previous commit. Christophe

--- libvirt-gobject/Makefile.am | 5 +- .../libvirt-gobject-network-dhcp-lease-private.h | 34 +++ .../libvirt-gobject-network-dhcp-lease.c | 252 +++++++++++++++++++++ .../libvirt-gobject-network-dhcp-lease.h | 85 +++++++ libvirt-gobject/libvirt-gobject.h | 1 + libvirt-gobject/libvirt-gobject.sym | 13 ++ 6 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease.c create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease.h diff --git a/libvirt-gobject/Makefile.am b/libvirt-gobject/Makefile.am index 7163c7d..8464f04 100644 --- a/libvirt-gobject/Makefile.am +++ b/libvirt-gobject/Makefile.am @@ -13,6 +13,7 @@ GOBJECT_HEADER_FILES = \ libvirt-gobject-domain.h \ libvirt-gobject-interface.h \ libvirt-gobject-network.h \ + libvirt-gobject-network-dhcp-lease.h \ libvirt-gobject-network-filter.h \ libvirt-gobject-node-device.h \ libvirt-gobject-secret.h \ @@ -22,7 +23,8 @@ GOBJECT_HEADER_FILES = \ libvirt-gobject-connection.h \ libvirt-gobject-manager.h noinst_HEADERS = \ - libvirt-gobject-storage-pool-private.h + libvirt-gobject-storage-pool-private.h \ + libvirt-gobject-network-dhcp-lease-private.h GOBJECT_SOURCE_FILES = \ libvirt-gobject-main.c \ libvirt-gobject-domain-snapshot.c \ @@ -32,6 +34,7 @@ GOBJECT_SOURCE_FILES = \ libvirt-gobject-domain.c \ libvirt-gobject-interface.c \ libvirt-gobject-network.c \ + libvirt-gobject-network-dhcp-lease.c \ libvirt-gobject-network-filter.c \ libvirt-gobject-node-device.c \ libvirt-gobject-secret.c \ diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h b/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h new file mode 100644 index 0000000..eaf6c2f --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h @@ -0,0 +1,34 @@ +/* + * libvirt-gobject-network-dhcp-lease-private.h: libvirt gobject integration + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2015 Red Hat, Inc. + * + * 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/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ +#define __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ + +G_BEGIN_DECLS + +GVirNetworkDHCPLease *gvir_network_dhcp_lease_new(virNetworkDHCPLeasePtr handle); + +G_END_DECLS + +#endif /* __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ */ diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c new file mode 100644 index 0000000..57ccf0d --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c @@ -0,0 +1,252 @@ +/* + * libvirt-gobject-network-dhcp-lease.h: libvirt glib integration + * + * Copyright (C) 2008 Daniel P. Berrange + * Copyright (C) 2015 Red Hat, Inc. + * + * 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/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <libvirt/virterror.h> +#include <string.h> + +#include "libvirt-glib/libvirt-glib.h" +#include "libvirt-gobject/libvirt-gobject.h" +#include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h" + +#define GVIR_NETWORK_DHCP_LEASE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeasePrivate)) + +struct _GVirNetworkDHCPLeasePrivate +{ + virNetworkDHCPLeasePtr handle; +}; + +G_DEFINE_TYPE(GVirNetworkDHCPLease, gvir_network_dhcp_lease, G_TYPE_OBJECT); + +enum { + PROP_0, + PROP_HANDLE, +}; + +static void gvir_network_dhcp_lease_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + switch (prop_id) { + case PROP_HANDLE: + g_value_set_pointer(value, priv->handle); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void gvir_network_dhcp_lease_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + switch (prop_id) { + case PROP_HANDLE: + if (priv->handle) + virNetworkDHCPLeaseFree(priv->handle); + priv->handle = g_value_get_pointer(value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + + +static void gvir_network_dhcp_lease_finalize(GObject *object) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + g_debug("Finalize GVirNetworkDHCPLease=%p", lease); + + virNetworkDHCPLeaseFree(priv->handle); + + G_OBJECT_CLASS(gvir_network_dhcp_lease_parent_class)->finalize(object); +} + +static void gvir_network_dhcp_lease_class_init(GVirNetworkDHCPLeaseClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gvir_network_dhcp_lease_finalize; + object_class->get_property = gvir_network_dhcp_lease_get_property; + object_class->set_property = gvir_network_dhcp_lease_set_property; + + g_object_class_install_property(object_class, + PROP_HANDLE, + g_param_spec_pointer("handle", + "Handle", + "The lease handle", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_PRIVATE | + G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private(klass, sizeof(GVirNetworkDHCPLeasePrivate)); +} + + +static void gvir_network_dhcp_lease_init(GVirNetworkDHCPLease *lease) +{ + g_debug("Init GVirNetworkDHCPLease=%p", lease); + + lease->priv = GVIR_NETWORK_DHCP_LEASE_GET_PRIVATE(lease); +} + +GVirNetworkDHCPLease *gvir_network_dhcp_lease_new(virNetworkDHCPLeasePtr handle) +{ + return g_object_new(GVIR_TYPE_NETWORK_DHCP_LEASE, + "handle", handle, + NULL); +} + +/** + * gvir_network_dhcp_lease_get_iface: + * @lease: the lease + * + * Returns: (transfer none): The network interface name. + */ +const gchar *gvir_network_dhcp_lease_get_iface(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->iface; +} + +/** + * gvir_network_dhcp_lease_get_expirytime: + * @lease: the lease + * + * Returns: The expiry time of this lease, as seconds since epoch. + */ +gint64 gvir_network_dhcp_lease_get_expirytime(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), -1); + + return lease->priv->handle->expirytime; +} + +/** + * gvir_network_dhcp_lease_get_ip_type: + * @lease: the lease + * + * Returns: The type of IP, see %GVirIPAddrType for possible values. + */ +gint gvir_network_dhcp_lease_get_ip_type(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), -1); + + return lease->priv->handle->type; +} + +/** + * gvir_network_dhcp_lease_get_mac: + * @lease: the lease + * + * Returns: (transfer none): The MAC address. + */ +const gchar *gvir_network_dhcp_lease_get_mac(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->mac; +} + +/** + * gvir_network_dhcp_lease_get_iaid: + * @lease: the lease + * + * Returns: (transfer none): The IAID. + */ +const gchar *gvir_network_dhcp_lease_get_iaid(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->iaid; +} + +/** + * gvir_network_dhcp_lease_get_ip: + * @lease: the lease + * + * Returns: (transfer none): The IP address. + */ +const gchar *gvir_network_dhcp_lease_get_ip(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->ipaddr; +} + +/** + * gvir_network_dhcp_lease_get_prefix: + * @lease: the lease + * + * Returns: The number of network address bits in the IP address. + */ +guint gvir_network_dhcp_lease_get_prefix(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), 0); + + return lease->priv->handle->prefix; +} + +/** + * gvir_network_dhcp_lease_get_hostname: + * @lease: the lease + * + * Returns: (transfer none): The hostname. + */ +const gchar *gvir_network_dhcp_lease_get_hostname(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->hostname; +} + +/** + * gvir_network_dhcp_lease_get_clientid: + * @lease: the lease + * + * Returns: (transfer none): The client ID or DUID. + */ +const gchar *gvir_network_dhcp_lease_get_clientid(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->clientid; +} diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h new file mode 100644 index 0000000..e10a863 --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h @@ -0,0 +1,85 @@ +/* + * libvirt-gobject-network-dhcp-lease.c: libvirt gobject integration + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2015 Red Hat, Inc. + * + * 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/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#if !defined(__LIBVIRT_GOBJECT_H__) && !defined(LIBVIRT_GOBJECT_BUILD) +#error "Only <libvirt-gobject/libvirt-gobject.h> can be included directly." +#endif + +#ifndef __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ +#define __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ + +G_BEGIN_DECLS + +/** + * GVirIPAddrType: + * @GVIR_IP_ADDR_TYPE_IPV4: IPv4 Address. + * @GVIR_IP_ADDR_TYPE_IPV6: IPv6 Address. + */ +typedef enum { + GVIR_IP_ADDR_TYPE_IPV4 = 0, + GVIR_IP_ADDR_TYPE_IPV6 = 1 +} GVirIPAddrType; + +#define GVIR_TYPE_NETWORK_DHCP_LEASE (gvir_network_dhcp_lease_get_type ()) +#define GVIR_NETWORK_DHCP_LEASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLease)) +#define GVIR_NETWORK_DHCP_LEASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeaseClass)) +#define GVIR_IS_NETWORK_DHCP_LEASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE)) +#define GVIR_IS_NETWORK_DHCP_LEASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GVIR_TYPE_NETWORK_DHCP_LEASE)) +#define GVIR_NETWORK_DHCP_LEASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeaseClass)) + +typedef struct _GVirNetworkDHCPLease GVirNetworkDHCPLease; +typedef struct _GVirNetworkDHCPLeasePrivate GVirNetworkDHCPLeasePrivate; +typedef struct _GVirNetworkDHCPLeaseClass GVirNetworkDHCPLeaseClass; + +struct _GVirNetworkDHCPLease +{ + GObject parent; + + GVirNetworkDHCPLeasePrivate *priv; + + /* Do not add fields to this struct */ +}; + +struct _GVirNetworkDHCPLeaseClass +{ + GObjectClass parent_class; + + gpointer padding[7]; +}; + +GType gvir_network_dhcp_lease_get_type(void); + +const gchar *gvir_network_dhcp_lease_get_iface(GVirNetworkDHCPLease *lease); +gint64 gvir_network_dhcp_lease_get_expirytime(GVirNetworkDHCPLease *lease); +gint gvir_network_dhcp_lease_get_ip_type(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_mac(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_iaid(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_ip(GVirNetworkDHCPLease *lease); +guint gvir_network_dhcp_lease_get_prefix(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_hostname(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_clientid(GVirNetworkDHCPLease *lease); + +G_END_DECLS + +#endif /* __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ */ diff --git a/libvirt-gobject/libvirt-gobject.h b/libvirt-gobject/libvirt-gobject.h index 2b95070..d542482 100644 --- a/libvirt-gobject/libvirt-gobject.h +++ b/libvirt-gobject/libvirt-gobject.h @@ -37,6 +37,7 @@ #include <libvirt-gobject/libvirt-gobject-domain.h> #include <libvirt-gobject/libvirt-gobject-interface.h> #include <libvirt-gobject/libvirt-gobject-network.h> +#include <libvirt-gobject/libvirt-gobject-network-dhcp-lease.h> #include <libvirt-gobject/libvirt-gobject-network-filter.h> #include <libvirt-gobject/libvirt-gobject-node-device.h> #include <libvirt-gobject/libvirt-gobject-secret.h> diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 085c410..e35130b 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -283,6 +283,19 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_connection_get_networks; gvir_interface_get_mac; + + gvir_ip_addr_type_get_type; + gvir_network_dhcp_lease_get_type; + + gvir_network_dhcp_lease_get_clientid; + gvir_network_dhcp_lease_get_expirytime; + gvir_network_dhcp_lease_get_hostname; + gvir_network_dhcp_lease_get_iaid; + gvir_network_dhcp_lease_get_iface; + gvir_network_dhcp_lease_get_ip; + gvir_network_dhcp_lease_get_ip_type; + gvir_network_dhcp_lease_get_mac; + gvir_network_dhcp_lease_get_prefix; } LIBVIRT_GOBJECT_0.2.1; # .... define new API here using predicted next version number .... -- 2.4.2

Hey, Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel). Maybe more descriptive doc for some of the fields (client id, iaid, ...) could be useful? Or are they just obvious for someone familiar with dhcp? On Mon, Jun 29, 2015 at 03:08:54PM +0100, Zeeshan Ali (Khattak) wrote:
diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c new file mode 100644 index 0000000..57ccf0d --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c @@ -0,0 +1,252 @@ +/* + * libvirt-gobject-network-dhcp-lease.h: libvirt glib integration
This is the .c file, not the .h file. Christophe

On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
Maybe more descriptive doc for some of the fields (client id, iaid, ...) could be useful? Or are they just obvious for someone familiar with dhcp?
I mostly copied those docs from libvirt docs. I myself don't know/remember what those are. :) But I guess if someone using this API is reading those, they'd know what they are or find out. -- Regards, Zeeshan Ali (Khattak) ________________________________________ Befriend GNOME: http://www.gnome.org/friends/

On Tue, Jun 30, 2015 at 01:25:28PM +0100, Zeeshan Ali (Khattak) wrote:
On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
I agree - IMHO acronyms should always be capitalized in our APIs - use of Cpu is a bug (which we can't fix), but we should not add more of such bugs. Likewise MAC, rather than Mac Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Jun 30, 2015 at 01:28:19PM +0100, Daniel P. Berrange wrote:
On Tue, Jun 30, 2015 at 01:25:28PM +0100, Zeeshan Ali (Khattak) wrote:
On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
I agree - IMHO acronyms should always be capitalized in our APIs - use of Cpu is a bug (which we can't fix), but we should not add more of such bugs. Likewise MAC, rather than Mac
Fine with me then. Do you mean even in method names, or just in type names? Christophe

On Tue, Jun 30, 2015 at 02:38:24PM +0200, Christophe Fergeau wrote:
On Tue, Jun 30, 2015 at 01:28:19PM +0100, Daniel P. Berrange wrote:
On Tue, Jun 30, 2015 at 01:25:28PM +0100, Zeeshan Ali (Khattak) wrote:
On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
I agree - IMHO acronyms should always be capitalized in our APIs - use of Cpu is a bug (which we can't fix), but we should not add more of such bugs. Likewise MAC, rather than Mac
Fine with me then. Do you mean even in method names, or just in type names?
Just types - for method names we use lowercase + underscores everywhere which is fine as its in keeping with GLib common practice. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Jun 30, 2015 at 01:48:41PM +0100, Daniel P. Berrange wrote:
On Tue, Jun 30, 2015 at 02:38:24PM +0200, Christophe Fergeau wrote:
On Tue, Jun 30, 2015 at 01:28:19PM +0100, Daniel P. Berrange wrote:
On Tue, Jun 30, 2015 at 01:25:28PM +0100, Zeeshan Ali (Khattak) wrote:
On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
I agree - IMHO acronyms should always be capitalized in our APIs - use of Cpu is a bug (which we can't fix), but we should not add more of such bugs. Likewise MAC, rather than Mac
Fine with me then. Do you mean even in method names, or just in type names?
Just types - for method names we use lowercase + underscores everywhere which is fine as its in keeping with GLib common practice.
We could have some typedef xxxCpuyyy xxxCPUyyy; if we want to 'fix' these wrong capitalizations. Christophe

On Tue, Jun 30, 2015 at 01:25:28PM +0100, Zeeshan Ali (Khattak) wrote:
On Tue, Jun 30, 2015 at 12:41 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
Hey,
Looks good to me, I'd name the type GVirNetworkDhcpLease rather than GVirNetworkDHCPLease, this is consistent with GVirConfigCapabilitiesCpuModel (and not CPUModel).
Hm.. I was trying to keep it consistent with the underlying 'virNetworkDHCPLease'.
I know, I'd favour consistency in the libvirt-glib API.
Maybe more descriptive doc for some of the fields (client id, iaid, ...) could be useful? Or are they just obvious for someone familiar with dhcp?
I mostly copied those docs from libvirt docs. I myself don't know/remember what those are. :) But I guess if someone using this API is reading those, they'd know what they are or find out.
Fwiw, I find libvirt documentation to be a bit more explicit.. (in virNetworkGetDHCPLeases ). Just realized now, but wouldn't we be better off with gvir_network_dhcp_lease_get_client_id; gvir_network_dhcp_lease_get_expiry_time; instead of gvir_network_dhcp_lease_get_clientid; gvir_network_dhcp_lease_get_expirytime; ?

--- libvirt-gobject/libvirt-gobject-network.c | 53 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-network.h | 4 +++ libvirt-gobject/libvirt-gobject.sym | 3 ++ 3 files changed, 60 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-network.c b/libvirt-gobject/libvirt-gobject-network.c index b1b38a0..650a164 100644 --- a/libvirt-gobject/libvirt-gobject-network.c +++ b/libvirt-gobject/libvirt-gobject-network.c @@ -29,6 +29,7 @@ #include "libvirt-glib/libvirt-glib.h" #include "libvirt-gobject/libvirt-gobject.h" #include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h" #define GVIR_NETWORK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK, GVirNetworkPrivate)) @@ -224,3 +225,55 @@ GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, free(xml); return conf; } + +/** + * gvir_network_get_dhcp_leases: + * @network: the network + * @mac: (allow-none): The optional ASCII formatted MAC address of an interface + * @flags: the flags + * @err: Place-holder for possible errors + * + * This function fetches leases info of guests in the specified network. If the + * optional parameter @mac is specified, the returned list will contain only + * lease info about a specific guest interface with @mac. There can be multiple + * leases for a single @mac because this API supports DHCPv6 too. + * + * Returns: (element-type LibvirtGObject.NetworkDHCPLease) (transfer full): the + * list of network leases. Each object in the returned list should be unreffed + * with g_object_unref() and the list itself using g_list_free, when no longer + * needed. + */ +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err) +{ + virNetworkDHCPLeasePtr *leases; + GList *ret = NULL; + int num_leases, i; + + g_return_val_if_fail(GVIR_IS_NETWORK(network), NULL); + g_return_val_if_fail(err == NULL || *err == NULL, NULL); + + num_leases = virNetworkGetDHCPLeases(network->priv->handle, mac, &leases, flags); + if (num_leases < 0) { + gvir_set_error_literal(err, GVIR_NETWORK_ERROR, + 0, + "Unable to get network DHCP leases"); + return NULL; + } + + if (num_leases == 0) + return NULL; + + for (i = 0; i < num_leases; i++) { + GVirNetworkDHCPLease *lease; + + lease = gvir_network_dhcp_lease_new(leases[i]); + ret = g_list_prepend(ret, lease); + } + ret = g_list_reverse(ret); + free(leases); + + return ret; +} diff --git a/libvirt-gobject/libvirt-gobject-network.h b/libvirt-gobject/libvirt-gobject-network.h index 9f746c0..5617ed6 100644 --- a/libvirt-gobject/libvirt-gobject-network.h +++ b/libvirt-gobject/libvirt-gobject-network.h @@ -71,6 +71,10 @@ const gchar *gvir_network_get_uuid(GVirNetwork *network); GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, guint flags, GError **err); +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err); G_END_DECLS diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index e35130b..7518422 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -285,6 +285,9 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_interface_get_mac; gvir_ip_addr_type_get_type; + + gvir_network_get_dhcp_leases; + gvir_network_dhcp_lease_get_type; gvir_network_dhcp_lease_get_clientid; -- 2.4.2

On Mon, Jun 29, 2015 at 03:08:55PM +0100, Zeeshan Ali (Khattak) wrote:
--- libvirt-gobject/libvirt-gobject-network.c | 53 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-network.h | 4 +++ libvirt-gobject/libvirt-gobject.sym | 3 ++ 3 files changed, 60 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-network.c b/libvirt-gobject/libvirt-gobject-network.c index b1b38a0..650a164 100644 --- a/libvirt-gobject/libvirt-gobject-network.c +++ b/libvirt-gobject/libvirt-gobject-network.c @@ -29,6 +29,7 @@ #include "libvirt-glib/libvirt-glib.h" #include "libvirt-gobject/libvirt-gobject.h" #include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h"
#define GVIR_NETWORK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK, GVirNetworkPrivate)) @@ -224,3 +225,55 @@ GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, free(xml); return conf; } + +/** + * gvir_network_get_dhcp_leases: + * @network: the network + * @mac: (allow-none): The optional ASCII formatted MAC address of an interface + * @flags: the flags
This should be documented as not being used, and needing to be 0 together with a runtime precondition in the method impl.
+ * @err: Place-holder for possible errors + * + * This function fetches leases info of guests in the specified network. If the + * optional parameter @mac is specified, the returned list will contain only + * lease info about a specific guest interface with @mac. There can be multiple + * leases for a single @mac because this API supports DHCPv6 too. + * + * Returns: (element-type LibvirtGObject.NetworkDHCPLease) (transfer full): the + * list of network leases. Each object in the returned list should be unreffed + * with g_object_unref() and the list itself using g_list_free, when no longer + * needed. + */ +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err) +{ + virNetworkDHCPLeasePtr *leases; + GList *ret = NULL; + int num_leases, i; + + g_return_val_if_fail(GVIR_IS_NETWORK(network), NULL); + g_return_val_if_fail(err == NULL || *err == NULL, NULL); + + num_leases = virNetworkGetDHCPLeases(network->priv->handle, mac, &leases, flags); + if (num_leases < 0) { + gvir_set_error_literal(err, GVIR_NETWORK_ERROR, + 0, + "Unable to get network DHCP leases"); + return NULL; + } + + if (num_leases == 0) + return NULL; + + for (i = 0; i < num_leases; i++) { + GVirNetworkDHCPLease *lease; + + lease = gvir_network_dhcp_lease_new(leases[i]); + ret = g_list_prepend(ret, lease); + } + ret = g_list_reverse(ret); + free(leases); + + return ret; +} diff --git a/libvirt-gobject/libvirt-gobject-network.h b/libvirt-gobject/libvirt-gobject-network.h index 9f746c0..5617ed6 100644 --- a/libvirt-gobject/libvirt-gobject-network.h +++ b/libvirt-gobject/libvirt-gobject-network.h @@ -71,6 +71,10 @@ const gchar *gvir_network_get_uuid(GVirNetwork *network); GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, guint flags, GError **err); +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err);
G_END_DECLS
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index e35130b..7518422 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -285,6 +285,9 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_interface_get_mac;
gvir_ip_addr_type_get_type; + + gvir_network_get_dhcp_leases; +
This needs to come after the gvir_network_dhcp_* symbols or this breaks make distcheck ('make -C libvirt-gobject check-symsorting' from the toplevel directory). Looks good otherwise. Christophe
participants (3)
-
Christophe Fergeau
-
Daniel P. Berrange
-
Zeeshan Ali (Khattak)