[libvirt] [PATCH v6 0/4] Introduce APIs to extract DHCP leases info

This API returns the leases information stored in the DHCP leases file of dnsmasq for a given virtual network. It contacts the bridge network driver, which parses a custom leases file created by libvirt. It supports two methods: 1. Return info for all network interfaces connected to a given virtual network 2. Return information for a particular network interface in a given virtual network by providing its MAC Address v6 * Converted parsing mechanism to JSON. Leases helper program has been added as a separate patch Refer: https://www.redhat.com/archives/libvir-list/2014-May/msg00219.html v5 * Created a helper file to generate custom leases for libvirt. Since dnsmasq doesn't provide the MAC Address in case of DHCPv6, the need for this file was proposed. The design of virNetworkDHCPLeases struct has been updated and the previous use of union has been removed. OOM errors have been taken care of in the remote driver and remote daemon. Discussion on struct design: https://www.redhat.com/archives/libvir-list/2013-October/msg00326.html Discussion on helper file: https://www.redhat.com/archives/libvir-list/2013-October/msg00989.html Refer: http://www.redhat.com/archives/libvir-list/2013-November/msg01085.html v4 * Added support for DHCPv6, updated lease file parsing method Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg01554.html v3 * Mostly small nits, change in MACRO names, use of virSocketAddrGetIpPrefix to retrieve IP prefix from @dom XML. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00832.html v2 * Since DHCPv6 is supposed to be suported in future, virNetworkGetDHCPLeasesForMAC changed, prefix and virIPAddrType added in virNetworkDHCPLeases struct. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00732.html v1 * Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00620.html * The need for these APIs were result of a RFC was proposed on the list. Refer: http://www.redhat.com/archives/libvir-list/2013-July/msg01603.html Nehal J Wani (4): net-dhcp-leases: Implement the public APIs net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network net-dhcp-leases: Add virsh support daemon/remote.c | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 34 +++++++ src/driver.h | 13 +++ src/internal.h | 5 + src/libvirt.c | 179 +++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ src/network/bridge_driver.c | 232 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 186 ++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 51 +++++++++- src/remote_protocol-structs | 38 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 119 ++++++++++++++++++++++ tools/virsh.pod | 6 ++ 13 files changed, 1054 insertions(+), 1 deletion(-) -- 1.9.3

Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC and virNetworkDHCPLeaseFree. * virNetworkGetDHCPLeases: returns the dhcp leases information for a given virtual network. For DHCPv4, the information returned: - Network Interface Name - Expiry Time - MAC address - IAID (NULL) - IPv4 address (with type and prefix) - Hostname (can be NULL) - Client ID (can be NULL) For DHCPv6, the information returned: - Network Interface Name - Expiry Time - MAC address - IAID (can be NULL, only in rare cases) - IPv6 address (with type and prefix) - Hostname (can be NULL) - Client DUID Note: @mac, @iaid, @ipaddr, @clientid are in ASCII form, not raw bytes. Note: @expirytime can 0, in case the lease is for infinite time. * virNetworkGetDHCPLeasesForMAC: returns the dhcp leases information for a given virtual network and specified MAC Address. * virNetworkDHCPLeaseFree: allows the upper layer application to free the network interface object conveniently. There is no support for flags, so user is expected to pass 0 for both the APIs. include/libvirt/libvirt.h.in: * Define virNetworkGetDHCPLeases * Define virNetworkGetDHCPLeasesForMAC * Define virNetworkDHCPLeaseFree src/driver.h: * Define networkGetDHCPLeases * Define networkGetDHCPLeasesForMAC src/libvirt.c: * Implement virNetworkGetDHCPLeases * Implement virNetworkGetDHCPLeasesForMAC * Implement virNetworkDHCPLeaseFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 34 ++++++++ src/driver.h | 13 ++++ src/libvirt.c | 179 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ 4 files changed, 232 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 127de11..6533449 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -5142,6 +5142,40 @@ typedef enum { #endif } virNetworkEventID; +typedef enum { + VIR_IP_ADDR_TYPE_IPV4, + VIR_IP_ADDR_TYPE_IPV6, + +#ifdef VIR_ENUM_SENTINELS + VIR_IP_ADDR_TYPE_LAST +#endif +} virIPAddrType; + +typedef struct _virNetworkDHCPLease virNetworkDHCPLease; +typedef virNetworkDHCPLease *virNetworkDHCPLeasePtr; +struct _virNetworkDHCPLease { + char *interface; /* Network interface name */ + long long expirytime; /* Seconds since epoch */ + int type; /* virIPAddrType */ + char *mac; /* MAC address */ + char *iaid; /* IAID */ + char *ipaddr; /* IP address */ + unsigned int prefix; /* IP address prefix */ + char *hostname; /* Hostname */ + char *clientid; /* Client ID or DUID */ +}; + +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasePtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasePtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasePtr **leases, + unsigned int flags); + /** * virConnectNetworkEventGenericCallback: * @conn: the connection pointer diff --git a/src/driver.h b/src/driver.h index 5ac89d6..d0f6105 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1173,6 +1173,17 @@ typedef int unsigned int nmountpoints, unsigned int flags); +typedef int +(*virDrvNetworkGetDHCPLeases)(virNetworkPtr network, + virNetworkDHCPLeasePtr **leases, + unsigned int flags); + +typedef int +(*virDrvNetworkGetDHCPLeasesForMAC)(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasePtr **leases, + unsigned int flags); + typedef struct _virDriver virDriver; typedef virDriver *virDriverPtr; @@ -1524,6 +1535,8 @@ struct _virNetworkDriver { virDrvNetworkSetAutostart networkSetAutostart; virDrvNetworkIsActive networkIsActive; virDrvNetworkIsPersistent networkIsPersistent; + virDrvNetworkGetDHCPLeases networkGetDHCPLeases; + virDrvNetworkGetDHCPLeasesForMAC networkGetDHCPLeasesForMAC; }; diff --git a/src/libvirt.c b/src/libvirt.c index 6c4a124..0282069 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -20910,3 +20910,182 @@ virDomainSetTime(virDomainPtr dom, virDispatchError(dom->conn); return -1; } + +/** + * virNetworkGetDHCPLeases: + * @network: Pointer to network object + * @leases: Pointer to a variable to store the array containing details on + * obtained leases, or NULL if the list is not required (just returns + * number of leases). + * @flags: Extra flags, not used yet, so callers should always pass 0 + * + * For DHCPv4, the information returned: + * - Network Interface Name + * - Expiry Time + * - MAC address + * - IAID (NULL) + * - IPv4 address (with type and prefix) + * - Hostname (can be NULL) + * - Client ID (can be NULL) + * + * For DHCPv6, the information returned: + * - Network Interface Name + * - Expiry Time + * - MAC address + * - IAID (can be NULL, only in rare cases) + * - IPv6 address (with type and prefix) + * - Hostname (can be NULL) + * - Client DUID + * + * Note: @mac, @iaid, @ipaddr, @clientid are in ASCII form, not raw bytes. + * Note: @expirytime can 0, in case the lease is for infinite time. + * + * Returns the number of leases found or -1 and sets @leases to NULL in + * case of error. On success, the array stored into @leases is guaranteed to + * have an extra allocated element set to NULL but not included in the return + * count, to make iteration easier. The caller is responsible for calling + * virNetworkDHCPLeaseFree() on each array element, then calling free() on @leases. + * + * See also virNetworkGetDHCPLeasesForMAC() as a convenience for filtering + * the list to a single MAC address. + * + * Example of usage: + * + * virNetworkDHCPLeasePtr *leases = NULL; + * virNetworkPtr network = ... obtain a network pointer here ...; + * size_t i; + * int nleases; + * unsigned int flags = 0; + * + * nleases = virNetworkGetDHCPLeases(network, &leases, flags); + * if (nleases < 0) + * error(); + * + * ... do something with returned values, for example: + * + * for (i = 0; i < nleases; i++) { + * virNetworkDHCPLeasePtr lease = leases[i]; + * + * printf("Time(epoch): %lu, MAC address: %s, " + * "IP address: %s, Hostname: %s, ClientID: %s\n", + * leas->expirytime, lease->mac, lease->ipaddr, + * lease->hostname, lease->clientid); + * + * virNetworkDHCPLeaseFree(leases[i]); + * } + * + * free(leases); + * + */ +int +virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("network=%p, leases=%p, flags=%x", + network, leases, flags); + + virResetLastError(); + + if (leases) + *leases = NULL; + + virCheckNetworkReturn(network, -1); + + conn = network->conn; + + if (conn->networkDriver && conn->networkDriver->networkGetDHCPLeases) { + int ret; + ret = conn->networkDriver->networkGetDHCPLeases(network, leases, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkGetDHCPLeasesForMAC: + * @network: Pointer to network object + * @mac: ASCII formatted MAC address of an interface + * @leases: Pointer to a variable to store the array containing details on + * obtained leases, or NULL if the list is not required (just returns + * number of leases). + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API fetches leases info of the interface which matches with the + * given @mac. There can be multiple leases for a single @mac because this + * API supports DHCPv6 too. + * + * Returns the number of leases found or -1 and sets @leases to NULL in case of + * error. On success, the array stored into @leases is guaranteed to have an + * extra allocated element set to NULL but not included in the return count, + * to make iteration easier. The caller is responsible for calling + * virNetworkDHCPLeaseFree() on each array element, then calling free() on @leases. + * + * See virNetworkGetDHCPLeases() for more details on list contents. + */ +int +virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DEBUG("network=%p, mac=%s, leases=%p, flags=%x", + network, mac, leases, flags); + + virResetLastError(); + + if (leases) + *leases = NULL; + + virCheckNonNullArgGoto(mac, error); + + virCheckNetworkReturn(network, -1); + + conn = network->conn; + + if (conn->networkDriver && + conn->networkDriver->networkGetDHCPLeasesForMAC) { + int ret; + ret = conn->networkDriver->networkGetDHCPLeasesForMAC(network, mac, + leases, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkDHCPLeaseFree: + * @lease: pointer to a leases object + * + * Frees all the memory occupied by @lease. + */ +void +virNetworkDHCPLeaseFree(virNetworkDHCPLeasePtr lease) +{ + if (!lease) + return; + VIR_FREE(lease->interface); + VIR_FREE(lease->mac); + VIR_FREE(lease->iaid); + VIR_FREE(lease->ipaddr); + VIR_FREE(lease->hostname); + VIR_FREE(lease->clientid); + VIR_FREE(lease); +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index cce6bdf..0ffbfd6 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -658,5 +658,11 @@ LIBVIRT_1.2.5 { virDomainSetTime; } LIBVIRT_1.2.3; +LIBVIRT_1.2.7 { + global: + virNetworkDHCPLeaseFree; + virNetworkGetDHCPLeases; + virNetworkGetDHCPLeasesForMAC; +} LIBVIRT_1.2.6; # .... define new API here using predicted next version number .... -- 1.9.3

On Mon, Jun 16, 2014 at 03:44:53AM +0530, Nehal J Wani wrote:
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index cce6bdf..0ffbfd6 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -658,5 +658,11 @@ LIBVIRT_1.2.5 { virDomainSetTime; } LIBVIRT_1.2.3;
+LIBVIRT_1.2.7 { + global: + virNetworkDHCPLeaseFree; + virNetworkGetDHCPLeases; + virNetworkGetDHCPLeasesForMAC; +} LIBVIRT_1.2.6;
We've not released 1.2.6 yet, so you should be using a 1.2.5 {} 1.2.5 block not 1.2.7 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 :|

Implement RPC calls for virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeasesForMAC * Define helper function remoteSerializeDHCPLease src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeasesForMAC * Define helper function remoteSerializeDHCPLease src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_NETWORK_GET_DHCP_LEASES * Define structs remote_network_dhcp_leases, remote_network_get_dhcp_leases_args, remote_network_get_dhcp_leases_ret * New RPC procedure: REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC * Define structs remote_network_dhcp_leases_for_mac, remote_network_get_dhcp_leases_for_mac_args, remote_network_get_dhcp_leases_for_mac_ret src/remote_protocol-structs * New structs added src/rpc/gendispatch.pl * Add exception (s/Dhcp/DHCP) for auto-generating names of the remote functions in daemon/remote_dispatch.h --- daemon/remote.c | 185 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 186 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 51 +++++++++++- src/remote_protocol-structs | 38 +++++++++ src/rpc/gendispatch.pl | 1 + 5 files changed, 460 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 34c96c9..3e37d9e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -6115,6 +6115,191 @@ remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED, return rv; } +/* Copy contents of virNetworkDHCPLeasePtr to remote_network_dhcp_lease */ +static int +remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasePtr lease_src) +{ + char **mac_tmp = NULL; + char **iaid_tmp = NULL; + char **hostname_tmp = NULL; + char **clientid_tmp = NULL; + + if (VIR_ALLOC(mac_tmp) < 0 || + VIR_ALLOC(iaid_tmp) < 0 || + VIR_ALLOC(hostname_tmp) < 0 || + VIR_ALLOC(clientid_tmp) < 0) + goto error; + + lease_dst->expirytime = lease_src->expirytime; + lease_dst->type = lease_src->type; + lease_dst->prefix = lease_src->prefix; + + if (VIR_STRDUP(lease_dst->interface, lease_src->interface) < 0 || + VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0 || + VIR_STRDUP(*mac_tmp, lease_src->mac) < 0 || + VIR_STRDUP(*iaid_tmp, lease_src->iaid) < 0 || + VIR_STRDUP(*hostname_tmp, lease_src->hostname) < 0 || + VIR_STRDUP(*clientid_tmp, lease_src->clientid) < 0) + goto error; + + lease_dst->mac = *mac_tmp ? mac_tmp : NULL; + lease_dst->iaid = *iaid_tmp ? iaid_tmp : NULL; + lease_dst->hostname = *hostname_tmp ? hostname_tmp : NULL; + lease_dst->clientid = *clientid_tmp ? clientid_tmp : NULL; + + return 0; + + error: + VIR_FREE(*mac_tmp); + VIR_FREE(*iaid_tmp); + VIR_FREE(*hostname_tmp); + VIR_FREE(*clientid_tmp); + VIR_FREE(mac_tmp); + VIR_FREE(iaid_tmp); + VIR_FREE(hostname_tmp); + VIR_FREE(clientid_tmp); + VIR_FREE(lease_dst->ipaddr); + VIR_FREE(lease_dst->interface); + return -1; +} + + +static int +remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_args *args, + remote_network_get_dhcp_leases_ret *ret) +{ + int rv = -1; + size_t i; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasePtr *leases = NULL; + virNetworkPtr net = NULL; + int nleases = 0; + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(net = get_nonnull_network(priv->conn, args->net))) + goto cleanup; + + if ((nleases = virNetworkGetDHCPLeases(net, + args->need_results ? &leases : NULL, + args->flags)) < 0) + goto cleanup; + + if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + nleases, REMOTE_NETWORK_DHCP_LEASES_MAX); + goto cleanup; + } + + if (leases && nleases) { + if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0) + goto cleanup; + + ret->leases.leases_len = nleases; + + for (i = 0; i < nleases; i++) { + if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0) + goto cleanup; + } + + } else { + ret->leases.leases_len = 0; + ret->leases.leases_val = NULL; + } + + ret->ret = nleases; + + rv = 0; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + VIR_FREE(leases); + } + virNetworkFree(net); + return rv; +} + + +static int +remoteDispatchNetworkGetDHCPLeasesForMAC(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_for_mac_args *args, + remote_network_get_dhcp_leases_for_mac_ret *ret) +{ + int rv = -1; + size_t i; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasePtr *leases = NULL; + virNetworkPtr net = NULL; + int nleases = 0; + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(net = get_nonnull_network(priv->conn, args->net))) + goto cleanup; + + if ((nleases = virNetworkGetDHCPLeasesForMAC(net, args->mac, + args->need_results ? &leases : NULL, + args->flags)) < 0) + goto cleanup; + + if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + nleases, REMOTE_NETWORK_DHCP_LEASES_MAX); + return -1; + } + + if (leases && nleases) { + if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0) + goto cleanup; + + ret->leases.leases_len = nleases; + + for (i = 0; i < nleases; i++) { + if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0) + goto cleanup; + } + + } else { + ret->leases.leases_len = 0; + ret->leases.leases_val = NULL; + } + + ret->ret = nleases; + + rv = 0; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + VIR_FREE(leases); + } + virNetworkFree(net); + return rv; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 85fe597..d532904 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7469,6 +7469,190 @@ remoteDomainGetTime(virDomainPtr dom, } +/* Copy contents of remote_network_dhcp_lease to virNetworkDHCPLeasePtr */ +static int +remoteSerializeDHCPLease(virNetworkDHCPLeasePtr lease_dst, remote_network_dhcp_lease *lease_src) +{ + lease_dst->expirytime = lease_src->expirytime; + lease_dst->type = lease_src->type; + lease_dst->prefix = lease_src->prefix; + + if (VIR_STRDUP(lease_dst->interface, lease_src->interface) < 0) + goto error; + + if (VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0) + goto error; + + if (lease_src->mac) { + if (VIR_STRDUP(lease_dst->mac, *lease_src->mac) < 0) + goto error; + } else + lease_src->mac = NULL; + + if (lease_src->iaid) { + if (VIR_STRDUP(lease_dst->iaid, *lease_src->iaid) < 0) + goto error; + } else + lease_src->iaid = NULL; + + if (lease_src->hostname) { + if (VIR_STRDUP(lease_dst->hostname, *lease_src->hostname) < 0) + goto error; + } else + lease_src->hostname = NULL; + + if (lease_src->clientid) { + if (VIR_STRDUP(lease_dst->clientid, *lease_src->clientid) < 0) + goto error; + } else + lease_src->clientid = NULL; + + return 0; + + error: + virNetworkDHCPLeaseFree(lease_dst); + return -1; +} + + +static int +remoteNetworkGetDHCPLeases(virNetworkPtr net, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + int rv = -1; + size_t i; + struct private_data *priv = net->conn->networkPrivateData; + remote_network_get_dhcp_leases_args args; + remote_network_get_dhcp_leases_ret ret; + + virNetworkDHCPLeasePtr *leases_ret = NULL; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.flags = flags; + args.need_results = !!leases; + + memset(&ret, 0, sizeof(ret)); + + if (call(net->conn, priv, 0, REMOTE_PROC_NETWORK_GET_DHCP_LEASES, + (xdrproc_t)xdr_remote_network_get_dhcp_leases_args, (char *)&args, + (xdrproc_t)xdr_remote_network_get_dhcp_leases_ret, (char *)&ret) == -1) { + goto done; + } + + if (ret.leases.leases_len > REMOTE_NETWORK_DHCP_LEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCP_LEASES_MAX); + goto cleanup; + } + + if (leases) { + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len + 1) < 0) { + goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + if (remoteSerializeDHCPLease(leases_ret[i], &ret.leases.leases_val[i]) < 0) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + } + + rv = ret.ret; + + cleanup: + if (leases_ret) { + for (i = 0; i < ret.leases.leases_len; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + VIR_FREE(leases_ret); + } + xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_leases_ret, + (char *) &ret); + + done: + remoteDriverUnlock(priv); + return rv; +} + + +static int +remoteNetworkGetDHCPLeasesForMAC(virNetworkPtr net, + const char *mac, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + int rv = -1; + size_t i; + struct private_data *priv = net->conn->networkPrivateData; + remote_network_get_dhcp_leases_for_mac_args args; + remote_network_get_dhcp_leases_for_mac_ret ret; + + virNetworkDHCPLeasePtr *leases_ret = NULL; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.mac = (char *) mac; + args.flags = flags; + args.need_results = !!leases; + + memset(&ret, 0, sizeof(ret)); + + if (call(net->conn, priv, 0, REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC, + (xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_args, (char *)&args, + (xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_ret, (char *)&ret) == -1) { + goto done; + } + + if (ret.leases.leases_len > REMOTE_NETWORK_DHCP_LEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCP_LEASES_MAX); + goto cleanup; + } + + if (leases) { + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len + 1) < 0) { + goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + if (remoteSerializeDHCPLease(leases_ret[i], &ret.leases.leases_val[i]) < 0) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + } + + rv = ret.ret; + + cleanup: + if (leases_ret) { + for (i = 0; i < ret.leases.leases_len; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + VIR_FREE(leases_ret); + } + xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_ret, + (char *) &ret); + + done: + remoteDriverUnlock(priv); + return rv; +} + + /* get_nonnull_domain and get_nonnull_network turn an on-wire * (name, uuid) pair into virDomainPtr or virNetworkPtr object. * These can return NULL if underlying memory allocations fail, @@ -7832,6 +8016,8 @@ static virNetworkDriver network_driver = { .networkSetAutostart = remoteNetworkSetAutostart, /* 0.3.0 */ .networkIsActive = remoteNetworkIsActive, /* 0.7.3 */ .networkIsPersistent = remoteNetworkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = remoteNetworkGetDHCPLeases, /* 1.2.6 */ + .networkGetDHCPLeasesForMAC = remoteNetworkGetDHCPLeasesForMAC, /* 1.2.6 */ }; static virInterfaceDriver interface_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 1f9d583..cc83386 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -238,6 +238,9 @@ const REMOTE_CONNECT_CPU_MODELS_MAX = 8192; /* Upper limit on number of mountpoints to frozen */ const REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX = 256; +/* Upper limit on the maximum number of leases in one lease file */ +const REMOTE_NETWORK_DHCP_LEASES_MAX = 65536; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2999,6 +3002,40 @@ struct remote_domain_fsthaw_ret { int filesystems; }; +struct remote_network_dhcp_lease { + remote_nonnull_string interface; + hyper expirytime; + int type; + remote_string mac; + remote_string iaid; + remote_nonnull_string ipaddr; + unsigned int prefix; + remote_string hostname; + remote_string clientid; +}; + +struct remote_network_get_dhcp_leases_args { + remote_nonnull_network net; + int need_results; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCP_LEASES_MAX>; + unsigned int ret; +}; + +struct remote_network_get_dhcp_leases_for_mac_args { + remote_nonnull_network net; + remote_nonnull_string mac; + int need_results; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_for_mac_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCP_LEASES_MAX>; + unsigned int ret; +}; /*----- Protocol. -----*/ @@ -5338,5 +5375,17 @@ enum remote_procedure { * @generate: both * @acl: domain:set_time */ - REMOTE_PROC_DOMAIN_SET_TIME = 338 + REMOTE_PROC_DOMAIN_SET_TIME = 338, + + /** + * @generate: none + * @acl: network:read + */ + REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 339, + + /** + * @generate: none + * @acl: network:read + */ + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 340 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 5b22049..49f9b13 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2463,6 +2463,42 @@ struct remote_domain_fsthaw_args { struct remote_domain_fsthaw_ret { int filesystems; }; +struct remote_network_dhcp_lease { + remote_nonnull_string interface; + int64_t expirytime; + int type; + remote_string mac; + remote_string iaid; + remote_nonnull_string ipaddr; + u_int prefix; + remote_string hostname; + remote_string clientid; +}; +struct remote_network_get_dhcp_leases_args { + remote_nonnull_network net; + int need_results; + u_int flags; +}; +struct remote_network_get_dhcp_leases_ret { + struct { + u_int leases_len; + remote_network_dhcp_lease * leases_val; + } leases; + u_int ret; +}; +struct remote_network_get_dhcp_leases_for_mac_args { + remote_nonnull_network net; + remote_nonnull_string mac; + int need_results; + u_int flags; +}; +struct remote_network_get_dhcp_leases_for_mac_ret { + struct { + u_int leases_len; + remote_network_dhcp_lease * leases_val; + } leases; + u_int ret; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2802,4 +2838,6 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_FSTHAW = 336, REMOTE_PROC_DOMAIN_GET_TIME = 337, REMOTE_PROC_DOMAIN_SET_TIME = 338, + REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 339, + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 340, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 9cd620e..d820d0e 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -68,6 +68,7 @@ sub fixup_name { $name =~ s/Fsthaw$/FSThaw/; $name =~ s/Scsi/SCSI/; $name =~ s/Wwn$/WWN/; + $name =~ s/Dhcp$/DHCP/; return $name; } -- 1.9.3

Query the network driver for the path of the custom leases file for the given virtual network and parse it to retrieve info. src/network/bridge_driver.c: * Implement networkGetDHCPLeases * Implement networkGetDHCPLeasesForMAC * Implement networkGetDHCPLeasesHelper --- src/network/bridge_driver.c | 232 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 4fc4c9a..361f36f 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -73,9 +73,17 @@ #include "viraccessapicheck.h" #include "network_event.h" #include "virhook.h" +#include "virjson.h" #define VIR_FROM_THIS VIR_FROM_NETWORK +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024) + VIR_LOG_INIT("network.bridge_driver"); static void networkDriverLock(virNetworkDriverStatePtr driver) @@ -3360,6 +3368,228 @@ static int networkSetAutostart(virNetworkPtr net, return ret; } +static int +networkGetDHCPLeasesHelper(virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasePtr **leases) +{ + size_t i, j; + size_t nleases = 0; + int rv = -1; + int size = 0; + int custom_lease_file_len = 0; + bool need_results = !!leases; + long long currtime = 0; + long long expirytime_tmp = -1; + bool ipv6 = false; + char *lease_entries = NULL; + char *custom_lease_file = NULL; + const char *ip_tmp = NULL; + const char *mac_tmp = NULL; + virJSONValuePtr lease_tmp = NULL; + virJSONValuePtr leases_array = NULL; + virNetworkIpDefPtr ipdef_tmp = NULL; + virNetworkDHCPLeasePtr lease = NULL; + virNetworkDHCPLeasePtr *leases_ret = NULL; + + /* Retrieve custom leases file location */ + custom_lease_file = networkDnsmasqLeaseFileNameCustom(obj->def->bridge); + + /* Read entire contents */ + if ((custom_lease_file_len = virFileReadAll(custom_lease_file, + VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX, + &lease_entries)) < 0) { + /* Even though src/network/leaseshelper.c guarantees the existence of + * leases file (even if no leases are present), and the control reaches + * here, instead of reporting error, return 0 leases */ + rv = 0; + goto error; + } + + if (custom_lease_file_len) { + if (!(leases_array = virJSONValueFromString(lease_entries))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid json in file: %s"), custom_lease_file); + goto error; + } + + if ((size = virJSONValueArraySize(leases_array)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("couldn't fetch array of leases")); + goto error; + } + } + + currtime = (long long) time(NULL); + + for (i = 0; i < size; i++) { + if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to parse json")); + goto error; + } + + if (!(mac_tmp = virJSONValueObjectGetString(lease_tmp, "mac-address"))) { + /* leaseshelper program guarantees that lease will be stored only if + * mac-address is known otherwise not */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("found lease without mac-address")); + goto error; + } + + if (mac && virMacAddrCompare(mac, mac_tmp)) { + virJSONValueFree(lease_tmp); + continue; + } + + if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp) < 0) { + /* A lease cannot be present without expiry-time */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("found lease without expiry-time")); + goto error; + } + + /* Do not report expired lease */ + if (expirytime_tmp < currtime) + continue; + + if (need_results) { + if (VIR_ALLOC(lease) < 0) + goto error; + + lease->expirytime = expirytime_tmp; + + if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) { + /* A lease without ip-address makes no sense */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("found lease without ip-address")); + goto error; + } + + /* Unlike IPv4, IPv6 uses ':' instead of '.' as separator */ + ipv6 = strchr(ip_tmp, ':') ? true : false; + lease->type = ipv6 ? VIR_IP_ADDR_TYPE_IPV6 : VIR_IP_ADDR_TYPE_IPV4; + + /* Obtain prefix */ + for (j = 0; j < obj->def->nips; j++) { + ipdef_tmp = &obj->def->ips[j]; + + if (ipv6 && VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address, + AF_INET6)) { + lease->prefix = ipdef_tmp->prefix; + break; + } + if (!ipv6 && VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address, + AF_INET)) { + lease->prefix = virSocketAddrGetIpPrefix(&ipdef_tmp->address, + &ipdef_tmp->netmask, + ipdef_tmp->prefix); + break; + } + } + + if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) || + (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) || + (VIR_STRDUP(lease->interface, obj->def->bridge) < 0)) + goto error; + + /* Fields that can be NULL */ + if ((VIR_STRDUP(lease->iaid, + virJSONValueObjectGetString(lease_tmp, "iaid")) < 0) || + (VIR_STRDUP(lease->clientid, + virJSONValueObjectGetString(lease_tmp, "client-id")) < 0) || + (VIR_STRDUP(lease->hostname, + virJSONValueObjectGetString(lease_tmp, "hostname")) < 0)) + goto error; + + if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0) + goto error; + + } else { + nleases++; + } + + VIR_FREE(lease); + } + + if (need_results && mac && !leases_ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no lease with matching MAC address: %s"), mac); + goto error; + } + + if (leases_ret) { + /* NULL terminated array */ + ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1)); + *leases = leases_ret; + leases_ret = NULL; + } + + rv = nleases; + + cleanup: + VIR_FREE(lease); + VIR_FREE(custom_lease_file); + virJSONValueFree(leases_array); + return rv; + + error: + if (leases_ret) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + VIR_FREE(leases_ret); + } + goto cleanup; +} + +static int +networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + if (!(obj = networkObjFromNetwork(network))) + return rv; + + if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(obj, NULL, leases); + + cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +static int +networkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasePtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + if (!(obj = networkObjFromNetwork(network))) + return rv; + + if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(obj, mac, leases); + + cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} static virNetworkDriver networkDriver = { "Network", @@ -3386,6 +3616,8 @@ static virNetworkDriver networkDriver = { .networkSetAutostart = networkSetAutostart, /* 0.2.1 */ .networkIsActive = networkIsActive, /* 0.7.3 */ .networkIsPersistent = networkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */ + .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.2.6 */ }; static virStateDriver networkStateDriver = { -- 1.9.3

Use virNetworkGetDHCPLeases and virNetworkGetDHCPLeasesForMAC in virsh. The new feature supports the follwing methods: 1. Retrieve leases info for a given virtual network 2. Retrieve leases info for given network interface tools/virsh-domain-monitor.c * Introduce new command : net-dhcp-leases Example Usage: net-dhcp-leases <network> [mac] virsh # net-dhcp-leases --network default6 Expiry Time MAC address Protocol IP address Hostname Client ID or DUID ------------------------------------------------------------------------------------------------------------------- 2014-06-16 03:40:14 52:54:00:85:90:e2 ipv4 192.168.150.231/24 fedora20-test 01:52:54:00:85:90:e2 2014-06-16 03:40:17 52:54:00:85:90:e2 ipv6 2001:db8:ca2:2:1::c0/64 fedora20-test 00:04:b1:d8:86:42:e1:6a:aa:cf:d5:86:94:23:6f:94:04:cd 2014-06-16 03:34:42 52:54:00:e8:73:eb ipv4 192.168.150.181/24 ubuntu14-vm - 2014-06-16 03:34:46 52:54:00:e8:73:eb ipv6 2001:db8:ca2:2:1::5b/64 - 00:01:00:01:1b:30:c6:aa:52:54:00:e8:73:eb tools/virsh.pod * Document new command src/internal.h * Introduce new macro: EMPTYSTR --- src/internal.h | 5 +++ tools/virsh-network.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++ 3 files changed, 130 insertions(+) diff --git a/src/internal.h b/src/internal.h index 0b36de9..ece5379 100644 --- a/src/internal.h +++ b/src/internal.h @@ -246,6 +246,11 @@ */ # define NULLSTR(s) ((s) ? (s) : "<null>") +/* + * Similar to NULLSTR, but print '-' to make it more user friendly. + */ +# define EMPTYSTR(s) ((s) ? (s) : "-") + /** * TODO: * diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 4b0df62..2d5b9be 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1285,6 +1285,119 @@ cmdNetworkEvent(vshControl *ctl, const vshCmd *cmd) } +/* + * "net-dhcp-leases" command + */ +static const vshCmdInfo info_network_dhcp_leases[] = { + {.name = "help", + .data = N_("print lease info for a given network") + }, + {.name = "desc", + .data = N_("Print lease info for a given network") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_network_dhcp_leases[] = { + {.name = "network", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("network name or uuid") + }, + {.name = "mac", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_NONE, + .help = N_("MAC address") + }, + {.name = NULL} +}; + +static int +vshNetworkDHCPLeaseSorter(const void *a, const void *b) +{ + int rv = -1; + + virNetworkDHCPLeasePtr *lease1 = (virNetworkDHCPLeasePtr *) a; + virNetworkDHCPLeasePtr *lease2 = (virNetworkDHCPLeasePtr *) b; + + if (*lease1 && !*lease2) + return -1; + + if (!*lease1) + return *lease2 != NULL; + + rv = vshStrcasecmp((*lease1)->mac, (*lease2)->mac); + return rv; +} + +static bool +cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + const char *mac = NULL; + virNetworkDHCPLeasePtr *leases = NULL; + int nleases = 0; + bool ret = false; + size_t i; + unsigned int flags = 0; + virNetworkPtr network = NULL; + + if (vshCommandOptString(cmd, "mac", &mac) < 0) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) + return false; + + nleases = mac ? virNetworkGetDHCPLeasesForMAC(network, mac, &leases, flags) + : virNetworkGetDHCPLeases(network, &leases, flags); + + if (nleases < 0) { + vshError(ctl, _("Failed to get leases info for %s"), name); + goto cleanup; + } + + /* Sort the list according to MAC Address/IAID */ + qsort(leases, nleases, sizeof(*leases), vshNetworkDHCPLeaseSorter); + + vshPrintExtra(ctl, " %-20s %-18s %-9s %-25s %-15s %s\n%s%s\n", + _("Expiry Time"), _("MAC address"), _("Protocol"), + _("IP address"), _("Hostname"), _("Client ID or DUID"), + "----------------------------------------------------------", + "---------------------------------------------------------"); + + for (i = 0; i < nleases; i++) { + const char *type = NULL; + char *cidr_format = NULL; + virNetworkDHCPLeasePtr lease = leases[i]; + time_t expirytime_tmp = lease->expirytime; + struct tm ts; + char expirytime[32]; + ts = *localtime_r(&expirytime_tmp, &ts); + strftime(expirytime, sizeof(expirytime), "%Y-%m-%d %H:%M:%S", &ts); + + type = (lease->type == VIR_IP_ADDR_TYPE_IPV4) ? "ipv4" : + (lease->type == VIR_IP_ADDR_TYPE_IPV6) ? "ipv6" : ""; + + ignore_value(virAsprintf(&cidr_format, "%s/%d", + lease->ipaddr, lease->prefix)); + + vshPrintExtra(ctl, " %-20s %-18s %-9s %-25s %-15s %s\n", + expirytime, EMPTYSTR(lease->mac), EMPTYSTR(type), cidr_format, + EMPTYSTR(lease->hostname), EMPTYSTR(lease->clientid)); + } + + ret = true; + + cleanup: + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + VIR_FREE(leases); + } + virNetworkFree(network); + return ret; +} + const vshCmdDef networkCmds[] = { {.name = "net-autostart", .handler = cmdNetworkAutostart, @@ -1310,6 +1423,12 @@ const vshCmdDef networkCmds[] = { .info = info_network_destroy, .flags = 0 }, + {.name = "net-dhcp-leases", + .handler = cmdNetworkDHCPLeases, + .opts = opts_network_dhcp_leases, + .info = info_network_dhcp_leases, + .flags = 0, + }, {.name = "net-dumpxml", .handler = cmdNetworkDumpXML, .opts = opts_network_dumpxml, diff --git a/tools/virsh.pod b/tools/virsh.pod index 35cf878..87b77c7 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2498,6 +2498,12 @@ If I<--current> is specified, affect the current network state. Both I<--live> and I<--config> flags may be given, but I<--current> is exclusive. Not specifying any flag is the same as specifying I<--current>. +=item B<net-dhcp-leases> I<network> [I<mac>] + +Get a list of dhcp leases for all network interfaces connected to the given +virtual I<network> or limited output just for one interface if I<mac> is +specified. + =back =head1 INTERFACE COMMANDS -- 1.9.3

On Mon, Jun 16, 2014 at 3:44 AM, Nehal J Wani <nehaljw.kkd1@gmail.com> wrote:
This API returns the leases information stored in the DHCP leases file of dnsmasq for a given virtual network. It contacts the bridge network driver, which parses a custom leases file created by libvirt.
It supports two methods:
1. Return info for all network interfaces connected to a given virtual network 2. Return information for a particular network interface in a given virtual network by providing its MAC Address
v6 * Converted parsing mechanism to JSON. Leases helper program has been added as a separate patch Refer: https://www.redhat.com/archives/libvir-list/2014-May/msg00219.html
v5 * Created a helper file to generate custom leases for libvirt. Since dnsmasq doesn't provide the MAC Address in case of DHCPv6, the need for this file was proposed. The design of virNetworkDHCPLeases struct has been updated and the previous use of union has been removed. OOM errors have been taken care of in the remote driver and remote daemon. Discussion on struct design: https://www.redhat.com/archives/libvir-list/2013-October/msg00326.html Discussion on helper file: https://www.redhat.com/archives/libvir-list/2013-October/msg00989.html Refer: http://www.redhat.com/archives/libvir-list/2013-November/msg01085.html
v4 * Added support for DHCPv6, updated lease file parsing method Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg01554.html
v3 * Mostly small nits, change in MACRO names, use of virSocketAddrGetIpPrefix to retrieve IP prefix from @dom XML. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00832.html
v2 * Since DHCPv6 is supposed to be suported in future, virNetworkGetDHCPLeasesForMAC changed, prefix and virIPAddrType added in virNetworkDHCPLeases struct. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00732.html
v1 * Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00620.html
* The need for these APIs were result of a RFC was proposed on the list. Refer: http://www.redhat.com/archives/libvir-list/2013-July/msg01603.html
Nehal J Wani (4): net-dhcp-leases: Implement the public APIs net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network net-dhcp-leases: Add virsh support
daemon/remote.c | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 34 +++++++ src/driver.h | 13 +++ src/internal.h | 5 + src/libvirt.c | 179 +++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ src/network/bridge_driver.c | 232 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 186 ++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 51 +++++++++- src/remote_protocol-structs | 38 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 119 ++++++++++++++++++++++ tools/virsh.pod | 6 ++ 13 files changed, 1054 insertions(+), 1 deletion(-)
-- 1.9.3
Ping! -- Nehal J Wani

Nehal J Wani (4): net-dhcp-leases: Implement the public APIs net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network net-dhcp-leases: Add virsh support
daemon/remote.c | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 34 +++++++ src/driver.h | 13 +++ src/internal.h | 5 + src/libvirt.c | 179 +++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ src/network/bridge_driver.c | 232 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 186 ++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 51 +++++++++- src/remote_protocol-structs | 38 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 119 ++++++++++++++++++++++ tools/virsh.pod | 6 ++ 13 files changed, 1054 insertions(+), 1 deletion(-)
Ping!
I tried to apply this locally to test it, but I'm afraid it has some nasty conflicts with the huge pages APIs that were added last week that were not going to be quick to resolve. Could you rebase & repost it and I'll promise to review it then. 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 Mon, Jun 23, 2014 at 9:36 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
Nehal J Wani (4): net-dhcp-leases: Implement the public APIs net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network net-dhcp-leases: Add virsh support
daemon/remote.c | 185 ++++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 34 +++++++ src/driver.h | 13 +++ src/internal.h | 5 + src/libvirt.c | 179 +++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 6 ++ src/network/bridge_driver.c | 232 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 186 ++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 51 +++++++++- src/remote_protocol-structs | 38 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 119 ++++++++++++++++++++++ tools/virsh.pod | 6 ++ 13 files changed, 1054 insertions(+), 1 deletion(-)
Ping!
I tried to apply this locally to test it, but I'm afraid it has some nasty conflicts with the huge pages APIs that were added last week that were not going to be quick to resolve. Could you rebase & repost it and I'll promise to review it then.
Sure, I'll rebase and re-post. Thanks for advance-review :-) -- Nehal J Wani
participants (2)
-
Daniel P. Berrange
-
Nehal J Wani