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

This API returns the information stored in the DHCP leases file created by dnsmasq for a given virtual network. It contacts the bridge network driver, which parses the leases file. 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 v2 * Since DHCPv6 is supposed to be suported in future, virNetworkGetDHCPLeasesForMAC changed, prefix and virIPAddrType added in virNetworkDHCPLeases struct. 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 driver net-dhcp-leases: Add virsh support daemon/remote.c | 133 +++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 33 ++++++++ python/generator.py | 3 + src/driver.h | 13 +++ src/libvirt.c | 173 ++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 7 ++ src/network/bridge_driver.c | 193 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 150 +++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 50 ++++++++++- src/remote_protocol-structs | 32 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 101 ++++++++++++++++++++++ tools/virsh.pod | 6 ++ 14 files changed, 895 insertions(+), 1 deletion(-) -- 1.7.11.7

Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC and virNetworkDHCPLeaseFree. * virNetworkGetDHCPLeases: returns the dhcp leases information for a given virtual network. The information includes lease expirytime, MAC Address, IP Address, hostname and clientid. * 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 python/generator.py: * Skip the auto-generation for virNetworkGetDHCPLeases * Skip the auto-generation for virNetworkGetDHCPLeasesForMAC * Skip the auto-generation for 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 src/libvirt_private.syms: * Export the symbol: virSocketAddrGetNumNetmaskBits --- include/libvirt/libvirt.h.in | 33 +++++++++ python/generator.py | 3 + src/driver.h | 13 ++++ src/libvirt.c | 173 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 7 ++ 6 files changed, 230 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..d92a720 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,39 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +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 _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; /* MAC address */ + char *ipaddr; /* IP address */ + char *hostname; /* Hostname */ + char *clientid; /* Client ID */ + int type; /* virIPAddrType */ + unsigned int prefix; /* IP address prefix */ +}; + +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + /* * virConnectListAllInterfaces: * diff --git a/python/generator.py b/python/generator.py index a91dde8..e76cbfc 100755 --- a/python/generator.py +++ b/python/generator.py @@ -460,6 +460,8 @@ skip_impl = ( 'virNodeGetCPUMap', 'virDomainMigrate3', 'virDomainMigrateToURI3', + 'virNetworkGetDHCPLeases', + 'virNetworkGetDHCPLeasesForMAC', ) lxc_skip_impl = ( @@ -560,6 +562,7 @@ skip_function = ( "virTypedParamsGetString", "virTypedParamsGetUInt", "virTypedParamsGetULLong", + 'virNetworkDHCPLeaseFree', ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..698e0ca 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1121,6 +1121,17 @@ typedef int int cookieinlen, unsigned int flags, int cancelled); +typedef int +(*virDrvNetworkGetDHCPLeases)(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +typedef int +(*virDrvNetworkGetDHCPLeasesForMAC)(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + typedef struct _virDriver virDriver; typedef virDriver *virDriverPtr; @@ -1451,6 +1462,8 @@ struct _virNetworkDriver { virDrvNetworkSetAutostart networkSetAutostart; virDrvNetworkIsActive networkIsActive; virDrvNetworkIsPersistent networkIsPersistent; + virDrvNetworkGetDHCPLeases networkGetDHCPLeases; + virDrvNetworkGetDHCPLeasesForMAC networkGetDHCPLeasesForMAC; }; diff --git a/src/libvirt.c b/src/libvirt.c index 20a2d4c..aa6a2fe 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -68,6 +68,7 @@ #include "virstring.h" #include "virutil.h" #include "virtypedparam.h" +#include "virmacaddr.h" #ifdef WITH_TEST # include "test/test_driver.h" @@ -21965,3 +21966,175 @@ error: virDispatchError(dom->conn); return -1; } + +/** + * virNetworkGetDHCPLeases: + * @network: pointer to network object + * @leases: pointer to an array of pointers pointing to the obtained leases + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API returns lease info for all network interfaces connected to the + * given virtual network. + * + * 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. + * + * Example of usage: + * + * virNetworkDHCPLeasesPtr *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++) { + * virNetworkDHCPLeasesPtr lease = leases[i]; + * printf("Time(epoch): %lu, MAC address: %s, + * IP address: %s, Hostname: %s, ClientID: %s\n", + * expirytime, lease->mac, + * lease->ipaddr, lease->hostname, lease->clientid); + * } + * + * if (leases) { + * for (i = 0; i < nleases; i++) + * virNetworkDHCPLeaseFree(leases[i]); + * } + * free(leases); + * + */ +int +virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("network=%p, leases=%p, flags=%x", + network, leases, flags); + + virResetLastError(); + + virCheckNonNullArgGoto(network, error); + + if (leases) + *leases = NULL; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(VIR_ERR_INVALID_NETWORK, __FUNCTION__); + virDispatchError(NULL); + return -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; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkGetDHCPLeasesForMAC: + * @network: pointer to network object + * @mac: MAC Address of an interface + * @leases: pointer to an array of pointers pointing to the obtained leases + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API returns the leases info of the interfaces which match with the + * given @mac. There can be multiple leases for a single @mac because this + * API intends to support DHCP v6 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. + */ +int +virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + virMacAddr addr; + + VIR_DEBUG("network=%p, mac=%s, leases=%p, flags=%x", + network, mac, leases, flags); + + virResetLastError(); + + virCheckNonNullArgGoto(network, error); + virCheckNonNullArgGoto(mac, error); + + if (leases) + *leases = NULL; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(VIR_ERR_INVALID_NETWORK, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + /* Validate the MAC address */ + if (mac && virMacAddrParse(mac, &addr) < 0) { + virReportInvalidArg(mac, + _("Given MAC Address doesn't comply " + "with the standard (IEEE 802) format in %s"), + __FUNCTION__); + goto error; + } + + 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; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkDHCPLeaseFree: + * @lease: pointer to a leases object + * + * Frees all the memory occupied by @lease. + */ +void +virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease) +{ + if (!lease) + return; + VIR_FREE(lease->mac); + VIR_FREE(lease->ipaddr); + VIR_FREE(lease->hostname); + VIR_FREE(lease->clientid); + VIR_FREE(lease); +} diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 35f0f1b..7d60c51 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1869,6 +1869,7 @@ virSocketAddrCheckNetmask; virSocketAddrEqual; virSocketAddrFormat; virSocketAddrFormatFull; +virSocketAddrGetNumNetmaskBits; virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index bbdf78a..e952869 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -634,4 +634,11 @@ LIBVIRT_1.1.1 { virDomainSetMemoryStatsPeriod; } LIBVIRT_1.1.0; +LIBVIRT_1.1.3 { + global: + virNetworkGetDHCPLeases; + virNetworkGetDHCPLeasesForMAC; + virNetworkDHCPLeaseFree; +} LIBVIRT_1.1.1; + # .... define new API here using predicted next version number .... -- 1.7.11.7

On 13/09/13 05:53, Nehal J Wani wrote:
Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC and virNetworkDHCPLeaseFree.
* virNetworkGetDHCPLeases: returns the dhcp leases information for a given virtual network. The information includes lease expirytime, MAC Address, IP Address, hostname and clientid.
Trivial, but "type" and "prefix" are new in this set.
* 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
python/generator.py: * Skip the auto-generation for virNetworkGetDHCPLeases * Skip the auto-generation for virNetworkGetDHCPLeasesForMAC * Skip the auto-generation for 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
src/libvirt_private.syms: * Export the symbol: virSocketAddrGetNumNetmaskBits
--- include/libvirt/libvirt.h.in | 33 +++++++++ python/generator.py | 3 + src/driver.h | 13 ++++ src/libvirt.c | 173 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 7 ++ 6 files changed, 230 insertions(+)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..d92a720 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,39 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef enum { + VIR_IP_ADDR_TYPE_IPV4, + VIR_IP_ADDR_TYPE_IPV6, + +#ifdef VIR_ENUM_SENTINELS + VIR_IP_ADDR_TYPE_LAST +#endif +} virIPAddrType; +
Okay, assuming that this set of API will be pushed before the interfaceAddresses API, this is fine.
+typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; /* MAC address */ + char *ipaddr; /* IP address */ + char *hostname; /* Hostname */ + char *clientid; /* Client ID */ + int type; /* virIPAddrType */ + unsigned int prefix; /* IP address prefix */ +}; + +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + /* * virConnectListAllInterfaces: * diff --git a/python/generator.py b/python/generator.py index a91dde8..e76cbfc 100755 --- a/python/generator.py +++ b/python/generator.py @@ -460,6 +460,8 @@ skip_impl = ( 'virNodeGetCPUMap', 'virDomainMigrate3', 'virDomainMigrateToURI3', + 'virNetworkGetDHCPLeases', + 'virNetworkGetDHCPLeasesForMAC', )
lxc_skip_impl = ( @@ -560,6 +562,7 @@ skip_function = ( "virTypedParamsGetString", "virTypedParamsGetUInt", "virTypedParamsGetULLong", + 'virNetworkDHCPLeaseFree', )
lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..698e0ca 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1121,6 +1121,17 @@ typedef int int cookieinlen, unsigned int flags, int cancelled); +typedef int +(*virDrvNetworkGetDHCPLeases)(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +typedef int +(*virDrvNetworkGetDHCPLeasesForMAC)(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); +
typedef struct _virDriver virDriver; typedef virDriver *virDriverPtr; @@ -1451,6 +1462,8 @@ struct _virNetworkDriver { virDrvNetworkSetAutostart networkSetAutostart; virDrvNetworkIsActive networkIsActive; virDrvNetworkIsPersistent networkIsPersistent; + virDrvNetworkGetDHCPLeases networkGetDHCPLeases; + virDrvNetworkGetDHCPLeasesForMAC networkGetDHCPLeasesForMAC; };
diff --git a/src/libvirt.c b/src/libvirt.c index 20a2d4c..aa6a2fe 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -68,6 +68,7 @@ #include "virstring.h" #include "virutil.h" #include "virtypedparam.h" +#include "virmacaddr.h"
#ifdef WITH_TEST # include "test/test_driver.h" @@ -21965,3 +21966,175 @@ error: virDispatchError(dom->conn); return -1; } + +/** + * virNetworkGetDHCPLeases: + * @network: pointer to network object + * @leases: pointer to an array of pointers pointing to the obtained leases + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API returns lease info for all network interfaces connected to the + * given virtual network. + * + * 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. + * + * Example of usage: + * + * virNetworkDHCPLeasesPtr *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++) { + * virNetworkDHCPLeasesPtr lease = leases[i]; + * printf("Time(epoch): %lu, MAC address: %s,
Missed the terminating " character.
+ * IP address: %s, Hostname: %s, ClientID: %s\n", + * expirytime, lease->mac,
lease->expirytime
+ * lease->ipaddr, lease->hostname, lease->clientid); + * } + * + * if (leases) { + * for (i = 0; i < nleases; i++) + * virNetworkDHCPLeaseFree(leases[i]); + * } + * free(leases); + * + */ +int +virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + VIR_DEBUG("network=%p, leases=%p, flags=%x", + network, leases, flags); + + virResetLastError(); + + virCheckNonNullArgGoto(network, error); + + if (leases) + *leases = NULL; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(VIR_ERR_INVALID_NETWORK, __FUNCTION__); + virDispatchError(NULL); + return -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; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkGetDHCPLeasesForMAC: + * @network: pointer to network object + * @mac: MAC Address of an interface + * @leases: pointer to an array of pointers pointing to the obtained leases + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API returns the leases info of the interfaces which match with the
s/interfaces/interface/, s/match/matches/,
+ * given @mac. There can be multiple leases for a single @mac because this + * API intends to support DHCP v6 too.
s/DHCP v6/DHCPv6/,
+ * + * 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. + */ +int +virNetworkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + virConnectPtr conn; + virMacAddr addr; + + VIR_DEBUG("network=%p, mac=%s, leases=%p, flags=%x", + network, mac, leases, flags); + + virResetLastError(); + + virCheckNonNullArgGoto(network, error); + virCheckNonNullArgGoto(mac, error); + + if (leases) + *leases = NULL; + + if (!VIR_IS_CONNECTED_NETWORK(network)) { + virLibNetworkError(VIR_ERR_INVALID_NETWORK, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + /* Validate the MAC address */ + if (mac && virMacAddrParse(mac, &addr) < 0) { + virReportInvalidArg(mac, + _("Given MAC Address doesn't comply " + "with the standard (IEEE 802) format in %s"), + __FUNCTION__); + goto error; + } + + 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; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(network->conn); + return -1; +} + +/** + * virNetworkDHCPLeaseFree: + * @lease: pointer to a leases object + * + * Frees all the memory occupied by @lease. + */ +void +virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease) +{ + if (!lease) + return; + VIR_FREE(lease->mac); + VIR_FREE(lease->ipaddr); + VIR_FREE(lease->hostname); + VIR_FREE(lease->clientid); + VIR_FREE(lease); +} diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 35f0f1b..7d60c51 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1869,6 +1869,7 @@ virSocketAddrCheckNetmask; virSocketAddrEqual; virSocketAddrFormat; virSocketAddrFormatFull; +virSocketAddrGetNumNetmaskBits;
Mistake, I don't see virSocketAddrGetNumNetmaskBits is ever used in this patch. ACK with the nits fixed. Osier

Implement RPC calls for virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeasesForMAC src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeasesForMAC 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 | 133 ++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 150 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 50 ++++++++++++++- src/remote_protocol-structs | 32 +++++++++ src/rpc/gendispatch.pl | 1 + 5 files changed, 365 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 2aff7c1..de03739 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5137,7 +5137,140 @@ cleanup: return rv; } +static int +remoteSerializeNetworkDHCPLeases(virNetworkDHCPLeasesPtr *leases, + int nleases, + remote_network_get_dhcp_leases_ret *ret) +{ + size_t i; + + if (nleases > REMOTE_NETWORK_DHCPLEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + nleases, REMOTE_NETWORK_DHCPLEASES_MAX); + return -1; + } + + if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0) + goto error; + + ret->leases.leases_len = nleases; + + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeasesPtr lease = leases[i]; + remote_network_dhcp_lease *lease_ret = &(ret->leases.leases_val[i]); + lease_ret->expirytime = lease->expirytime; + lease_ret->type = lease->type; + lease_ret->prefix = lease->prefix; + + if ((VIR_STRDUP(lease_ret->mac, lease->mac) < 0) || + (VIR_STRDUP(lease_ret->ipaddr, lease->ipaddr) < 0) || + (VIR_STRDUP(lease_ret->hostname, lease->hostname) < 0) || + (VIR_STRDUP(lease_ret->clientid, lease->clientid) < 0)) + goto error; + } + + return 0; + +error: + if (ret->leases.leases_val) { + for (i = 0; i < nleases; i++) { + remote_network_dhcp_lease *lease_ret = &(ret->leases.leases_val[i]); + virNetworkDHCPLeaseFree((virNetworkDHCPLeasesPtr)lease_ret); + } + } + 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; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasesPtr *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, &leases, args->flags)) < 0) + goto cleanup; + + if (remoteSerializeNetworkDHCPLeases(leases, nleases, ret) < 0) + goto cleanup; + rv = nleases; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + size_t i; + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeaseFree(leases[i]); + } + } + VIR_FREE(leases); + 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; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasesPtr *leases = NULL; + virNetworkPtr net = NULL; + int nleases = 0; + const char *mac = NULL; + + 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; + + mac = args->mac ? *args->mac : NULL; + + if ((nleases = virNetworkGetDHCPLeasesForMAC(net, mac, &leases, args->flags)) < 0) + goto cleanup; + + if (remoteSerializeNetworkDHCPLeases(leases, nleases, + (remote_network_get_dhcp_leases_ret *)ret) < 0) + goto cleanup; + + rv = nleases; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + size_t i; + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeaseFree(leases[i]); + } + } + VIR_FREE(leases); + return rv; +} /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 62e77a5..693de42 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6599,6 +6599,154 @@ done: return rv; } +static int +remoteNetworkGetDHCPLeasesForMAC(virNetworkPtr net, + const char *mac, + virNetworkDHCPLeasesPtr **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; + + virNetworkDHCPLeasesPtr *leases_ret; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.mac = mac ? (char **)&mac : NULL; + args.flags = flags; + + 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_DHCPLEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCPLEASES_MAX); + return -1; + goto cleanup; + } + + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len) < 0) { + goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + virNetworkDHCPLeasesPtr lease = leases_ret[i]; + remote_network_dhcp_lease *lease_ret = &(ret.leases.leases_val[i]); + lease->expirytime = lease_ret->expirytime; + lease->type = lease_ret->type; + lease->prefix = lease_ret->prefix; + + if ((VIR_STRDUP(lease->mac, lease_ret->mac) < 0) || + (VIR_STRDUP(lease->ipaddr, lease_ret->ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, lease_ret->hostname) < 0) || + (VIR_STRDUP(lease->clientid, lease_ret->clientid) < 0)) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + rv = ret.leases.leases_len; + +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; +} + +static int +remoteNetworkGetDHCPLeases(virNetworkPtr net, + virNetworkDHCPLeasesPtr **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; + + virNetworkDHCPLeasesPtr *leases_ret; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.flags = flags; + + 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_DHCPLEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCPLEASES_MAX); + return -1; + goto cleanup; + } + + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len) < 0) { + goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + virNetworkDHCPLeasesPtr lease = leases_ret[i]; + remote_network_dhcp_lease *lease_ret = &(ret.leases.leases_val[i]); + lease->expirytime = lease_ret->expirytime; + lease->type = lease_ret->type; + lease->prefix = lease_ret->prefix; + + if ((VIR_STRDUP(lease->mac, lease_ret->mac) < 0) || + (VIR_STRDUP(lease->ipaddr, lease_ret->ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, lease_ret->hostname) < 0) || + (VIR_STRDUP(lease->clientid, lease_ret->clientid) < 0)) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + rv = ret.leases.leases_len; + +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 void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -6958,6 +7106,8 @@ static virNetworkDriver network_driver = { .networkSetAutostart = remoteNetworkSetAutostart, /* 0.3.0 */ .networkIsActive = remoteNetworkIsActive, /* 0.7.3 */ .networkIsPersistent = remoteNetworkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = remoteNetworkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeasesForMAC = remoteNetworkGetDHCPLeasesForMAC, /* 1.1.3 */ }; static virInterfaceDriver interface_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 85ad9ba..c455038 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -232,6 +232,11 @@ const REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX = 64; /* Upper limit on number of job stats */ const REMOTE_DOMAIN_JOB_STATS_MAX = 16; +/* + * Upper limit on the maximum number of leases in one lease file + */ +const REMOTE_NETWORK_DHCPLEASES_MAX = 32768; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2835,6 +2840,35 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_string devAlias; }; +struct remote_network_dhcp_lease { + hyper expirytime; + remote_nonnull_string mac; + remote_nonnull_string ipaddr; + remote_nonnull_string hostname; + remote_nonnull_string clientid; + int type; + unsigned int prefix; +}; + +struct remote_network_get_dhcp_leases_args { + remote_nonnull_network net; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCPLEASES_MAX>; +}; + +struct remote_network_get_dhcp_leases_for_mac_args { + remote_nonnull_network net; + remote_string mac; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_for_mac_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCPLEASES_MAX>; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -4998,5 +5032,19 @@ enum remote_procedure { * @generate: both * @acl: none */ - REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311 + REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311, + + /** + * @generate: none + * @priority: high + * @acl: network:read + */ + REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 312, + + /** + * @generate: none + * @priority: high + * @acl: network:read + */ + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 313 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 4e27aae..9b625e8 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2316,6 +2316,36 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_domain dom; remote_nonnull_string devAlias; }; +struct remote_network_dhcp_lease { + int64_t expirytime; + remote_nonnull_string mac; + remote_nonnull_string ipaddr; + remote_nonnull_string hostname; + remote_nonnull_string clientid; + int type; + u_int prefix; +}; +struct remote_network_get_dhcp_leases_args { + remote_nonnull_network net; + u_int flags; +}; +struct remote_network_get_dhcp_leases_ret { + struct { + u_int leases_len; + remote_network_dhcp_lease * leases_val; + } leases; +}; +struct remote_network_get_dhcp_leases_for_mac_args { + remote_nonnull_network net; + remote_string mac; + u_int flags; +}; +struct remote_network_get_dhcp_leases_for_mac_ret { + struct { + u_int leases_len; + remote_network_dhcp_lease * leases_val; + } leases; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2628,4 +2658,6 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_CREATE_XML_WITH_FILES = 309, REMOTE_PROC_DOMAIN_CREATE_WITH_FILES = 310, REMOTE_PROC_DOMAIN_EVENT_DEVICE_REMOVED = 311, + REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 312, + REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 313, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index ceb1ad8..5a503cf 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -66,6 +66,7 @@ sub fixup_name { $name =~ s/Fstrim$/FSTrim/; $name =~ s/Scsi/SCSI/; $name =~ s/Wwn$/WWN/; + $name =~ s/Dhcp$/DHCP/; return $name; } -- 1.7.11.7

On 13/09/13 05:53, Nehal J Wani wrote:
Implement RPC calls for virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC
daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeasesForMAC
src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeasesForMAC
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 | 133 ++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 150 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 50 ++++++++++++++- src/remote_protocol-structs | 32 +++++++++ src/rpc/gendispatch.pl | 1 + 5 files changed, 365 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c index 2aff7c1..de03739 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5137,7 +5137,140 @@ cleanup: return rv; }
+static int +remoteSerializeNetworkDHCPLeases(virNetworkDHCPLeasesPtr *leases, + int nleases, + remote_network_get_dhcp_leases_ret *ret) +{ + size_t i; + + if (nleases > REMOTE_NETWORK_DHCPLEASES_MAX) {
I think REMOTE_NETWORK_DHCP_LEASES_MAX is better.
+ virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + nleases, REMOTE_NETWORK_DHCPLEASES_MAX); + return -1; + } + + if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0) + goto error;
If you "return -1;" here....
+ + ret->leases.leases_len = nleases; + + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeasesPtr lease = leases[i]; + remote_network_dhcp_lease *lease_ret = &(ret->leases.leases_val[i]); + lease_ret->expirytime = lease->expirytime; + lease_ret->type = lease->type; + lease_ret->prefix = lease->prefix; + + if ((VIR_STRDUP(lease_ret->mac, lease->mac) < 0) || + (VIR_STRDUP(lease_ret->ipaddr, lease->ipaddr) < 0) || + (VIR_STRDUP(lease_ret->hostname, lease->hostname) < 0) || + (VIR_STRDUP(lease_ret->clientid, lease->clientid) < 0)) + goto error; + } + + return 0; + +error: + if (ret->leases.leases_val) {
then no need for this checking.
+ for (i = 0; i < nleases; i++) { + remote_network_dhcp_lease *lease_ret = &(ret->leases.leases_val[i]); + virNetworkDHCPLeaseFree((virNetworkDHCPLeasesPtr)lease_ret); + } + } + 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; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasesPtr *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, &leases, args->flags)) < 0) + goto cleanup; + + if (remoteSerializeNetworkDHCPLeases(leases, nleases, ret) < 0) + goto cleanup;
+ rv = nleases; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + size_t i; + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeaseFree(leases[i]); + } + }
Network object "net" is leaked. [1]
+ VIR_FREE(leases); + 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; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeasesPtr *leases = NULL; + virNetworkPtr net = NULL; + int nleases = 0; + const char *mac = NULL; + + 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; + + mac = args->mac ? *args->mac : NULL; + + if ((nleases = virNetworkGetDHCPLeasesForMAC(net, mac, &leases, args->flags)) < 0) + goto cleanup; + + if (remoteSerializeNetworkDHCPLeases(leases, nleases, + (remote_network_get_dhcp_leases_ret *)ret) < 0) + goto cleanup; + + rv = nleases; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + if (leases) { + size_t i; + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeaseFree(leases[i]); + } + } + VIR_FREE(leases);
Same as [1]
+ return rv; +}
/*----- Helpers. -----*/
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 62e77a5..693de42 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6599,6 +6599,154 @@ done: return rv; }
+static int +remoteNetworkGetDHCPLeasesForMAC(virNetworkPtr net, + const char *mac, + virNetworkDHCPLeasesPtr **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; + + virNetworkDHCPLeasesPtr *leases_ret; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.mac = mac ? (char **)&mac : NULL; + args.flags = flags; + + 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_DHCPLEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCPLEASES_MAX);
Likewise, s/DHCPLEASES/DHCP_LEASES/,
+ return -1; + goto cleanup; + } + + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len) < 0) {
[2] The API declares the returned array is NULL terminated, but here it doesn't, you should allocate one more element for it: VIR_ALLOC_N(leases_ret, ret.leases.leases_len + 1)
+ goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + virNetworkDHCPLeasesPtr lease = leases_ret[i]; + remote_network_dhcp_lease *lease_ret = &(ret.leases.leases_val[i]); + lease->expirytime = lease_ret->expirytime; + lease->type = lease_ret->type; + lease->prefix = lease_ret->prefix; + + if ((VIR_STRDUP(lease->mac, lease_ret->mac) < 0) || + (VIR_STRDUP(lease->ipaddr, lease_ret->ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, lease_ret->hostname) < 0) || + (VIR_STRDUP(lease->clientid, lease_ret->clientid) < 0)) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + rv = ret.leases.leases_len; + +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; +} + +static int +remoteNetworkGetDHCPLeases(virNetworkPtr net, + virNetworkDHCPLeasesPtr **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; + + virNetworkDHCPLeasesPtr *leases_ret; + remoteDriverLock(priv); + + make_nonnull_network(&args.net, net); + args.flags = flags; + + 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_DHCPLEASES_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of leases is %d, which exceeds max limit: %d"), + ret.leases.leases_len, REMOTE_NETWORK_DHCPLEASES_MAX);
s/DHCPLEASES/DHCP_LEASES/,
+ return -1; + goto cleanup; + } + + if (ret.leases.leases_len && + VIR_ALLOC_N(leases_ret, ret.leases.leases_len) < 0) {
Same problem as [2]
+ goto cleanup; + } + + for (i = 0; i < ret.leases.leases_len; i++) { + if (VIR_ALLOC(leases_ret[i]) < 0) + goto cleanup; + + virNetworkDHCPLeasesPtr lease = leases_ret[i]; + remote_network_dhcp_lease *lease_ret = &(ret.leases.leases_val[i]); + lease->expirytime = lease_ret->expirytime; + lease->type = lease_ret->type; + lease->prefix = lease_ret->prefix; + + if ((VIR_STRDUP(lease->mac, lease_ret->mac) < 0) || + (VIR_STRDUP(lease->ipaddr, lease_ret->ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, lease_ret->hostname) < 0) || + (VIR_STRDUP(lease->clientid, lease_ret->clientid) < 0)) + goto cleanup; + } + + *leases = leases_ret; + leases_ret = NULL; + rv = ret.leases.leases_len; + +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 void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -6958,6 +7106,8 @@ static virNetworkDriver network_driver = { .networkSetAutostart = remoteNetworkSetAutostart, /* 0.3.0 */ .networkIsActive = remoteNetworkIsActive, /* 0.7.3 */ .networkIsPersistent = remoteNetworkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = remoteNetworkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeasesForMAC = remoteNetworkGetDHCPLeasesForMAC, /* 1.1.3 */ };
static virInterfaceDriver interface_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 85ad9ba..c455038 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -232,6 +232,11 @@ const REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX = 64; /* Upper limit on number of job stats */ const REMOTE_DOMAIN_JOB_STATS_MAX = 16;
+/* + * Upper limit on the maximum number of leases in one lease file + */ +const REMOTE_NETWORK_DHCPLEASES_MAX = 32768; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN];
@@ -2835,6 +2840,35 @@ struct remote_domain_event_device_removed_msg { remote_nonnull_string devAlias; };
+struct remote_network_dhcp_lease { + hyper expirytime; + remote_nonnull_string mac; + remote_nonnull_string ipaddr; + remote_nonnull_string hostname; + remote_nonnull_string clientid; + int type; + unsigned int prefix; +}; + +struct remote_network_get_dhcp_leases_args { + remote_nonnull_network net; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCPLEASES_MAX>;
Likewise.
+}; + +struct remote_network_get_dhcp_leases_for_mac_args { + remote_nonnull_network net; + remote_string mac; + unsigned int flags; +}; + +struct remote_network_get_dhcp_leases_for_mac_ret { + remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCPLEASES_MAX>;
Likewise. Osier

By querying the driver for the path of the leases file for the given virtual network and parsing it to retrieve info. src/network/bridge_driver.c: * Implement networkGetDHCPLeases * Implement networkGetDHCPLeasesForMAC * Implement networkGetDHCPLeasesHelper --- src/network/bridge_driver.c | 193 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 3a8be90..2cdea56 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -109,6 +109,36 @@ static int networkPlugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); static int networkUnplugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); +/** + * VIR_NETWORK_DHCPLEASE_LENGTH_MAX: + * + * Macro providing the maximum length of an entry in the leases file + * Refer: http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2013q3/007402.html + */ +#define VIR_NETWORK_DHCPLEASE_LENGTH_MAX 2048 + +/** + * VIR_NETWORK_DHCPLEASE_PARAMS: + * + * Macro providing the maximum number of parameters in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCPLEASE_FIELDS 5 + +static int networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +static int networkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +static int networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); static virNetworkDriverStatePtr driverState = NULL; @@ -2980,6 +3010,167 @@ cleanup: return ret; } +static int +networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + obj = networkObjFromNetwork(network); + + if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, NULL, leases, flags); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +static int +networkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + obj = networkObjFromNetwork(network); + + if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, mac, leases, flags); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +/* This function parese the leases file generated by dnsmasq. + * Example content: + * :::::::::::::: + * /var/lib/libvirt/dnsmasq/TestNetwork1.leases + * :::::::::::::: + * 1379024255 52:54:00:20:70:3d 192.168.105.240 * * + * 1379023351 52:54:00:b1:70:19 192.168.105.201 * * + */ +static int +networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + size_t i = 0; + char *leasefile; + FILE *fp = NULL; + size_t nleases = 0; + char **leaseparams; + virNetworkDHCPLeasesPtr *leases_ret = NULL; + char dhcpentry[VIR_NETWORK_DHCPLEASE_LENGTH_MAX]; + + virCheckFlags(0, -1); + + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, "%s", + _("no network with matching name")); + return -1; + } + + /* Retrive leases file location */ + leasefile = networkDnsmasqLeaseFileNameDefault(network->name); + if (!(fp = fopen(leasefile, "r"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to open leases file: %s"), leasefile); + goto error; + } + + while (fgets(dhcpentry, sizeof(dhcpentry), fp) != NULL) { + virNetworkDHCPLeasesPtr lease = NULL; + + /* Remove newline */ + dhcpentry[strlen(dhcpentry) - 1] = '\0'; + + /* split the lease line */ + leaseparams = virStringSplit(dhcpentry, " ", VIR_NETWORK_DHCPLEASE_FIELDS); + + if (virStringListLength(leaseparams) != VIR_NETWORK_DHCPLEASE_FIELDS) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of lease params aren't equal to: %d"), + VIR_NETWORK_DHCPLEASE_FIELDS); + goto error; + } + + if (mac && STRNEQ(mac, leaseparams[1])) + continue; + + /* We don't know the total number of leases yet */ + if (VIR_EXPAND_N(leases_ret, nleases, 1) < 0) + goto error; + + if (VIR_ALLOC(leases_ret[nleases - 1]) < 0) + goto error; + + lease = leases_ret[nleases - 1]; + + /* Convert expirytime here */ + if (virStrToLong_ll(leaseparams[0], NULL, 10, &(lease->expirytime)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to convert lease expiry time to integer: %s"), + leaseparams[0]); + goto error; + } + + /* Hardcoded, as dnsmasq uses ipv4 */ + lease->type = VIR_IP_ADDR_TYPE_IPV4; + lease->prefix = virSocketAddrGetNumNetmaskBits(&obj->def->ips->netmask); + + if ((VIR_STRDUP(lease->mac, leaseparams[1]) < 0) || + (VIR_STRDUP(lease->ipaddr, leaseparams[2]) < 0) || + (VIR_STRDUP(lease->hostname, leaseparams[3]) < 0) || + (VIR_STRDUP(lease->clientid, leaseparams[4]) < 0)) + goto error; + } + + if (mac && !leases_ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no lease with matching MAC address: %s"), mac); + goto error; + } + + if (leases_ret) { + /* trim the array to the final size */ + ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1)); + *leases = leases_ret; + leases_ret = NULL; + rv = nleases; + } + +cleanup: + VIR_FORCE_FCLOSE(fp); + VIR_FREE(leasefile); + return rv; + +error: + if (leases_ret) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + } + VIR_FREE(leases_ret); + goto cleanup; +} static virNetworkDriver networkDriver = { "Network", @@ -3004,6 +3195,8 @@ static virNetworkDriver networkDriver = { .networkSetAutostart = networkSetAutostart, /* 0.2.1 */ .networkIsActive = networkIsActive, /* 0.7.3 */ .networkIsPersistent = networkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.1.3 */ }; static virStateDriver networkStateDriver = { -- 1.7.11.7

Just realized that obj should be non-null. Small diff to fix this: diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2cdea56..3e93893 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -3020,7 +3020,8 @@ networkGetDHCPLeases(virNetworkPtr network, virCheckFlags(0, -1); - obj = networkObjFromNetwork(network); + if (!(obj = networkObjFromNetwork(network))) + return rv; if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) goto cleanup; @@ -3044,7 +3045,8 @@ networkGetDHCPLeasesForMAC(virNetworkPtr network, virCheckFlags(0, -1); - obj = networkObjFromNetwork(network); + if (!(obj = networkObjFromNetwork(network))) + return rv; if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) goto cleanup;

On 13/09/13 17:10, Nehal J Wani wrote:
Just realized that obj should be non-null. Small diff to fix this:
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2cdea56..3e93893 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -3020,7 +3020,8 @@ networkGetDHCPLeases(virNetworkPtr network, virCheckFlags(0, -1); - obj = networkObjFromNetwork(network); + if (!(obj = networkObjFromNetwork(network))) + return rv; if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) goto cleanup; @@ -3044,7 +3045,8 @@ networkGetDHCPLeasesForMAC(virNetworkPtr network, virCheckFlags(0, -1); - obj = networkObjFromNetwork(network); + if (!(obj = networkObjFromNetwork(network))) + return rv; if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) goto cleanup;
Don't have to paste the diff in mail context, and attach the diff meanwhile.

On 13/09/13 05:53, Nehal J Wani wrote:
By querying the driver for the path of the leases file for the given virtual network and parsing it to retrieve info.
src/network/bridge_driver.c: * Implement networkGetDHCPLeases * Implement networkGetDHCPLeasesForMAC * Implement networkGetDHCPLeasesHelper
--- src/network/bridge_driver.c | 193 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 3a8be90..2cdea56 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -109,6 +109,36 @@ static int networkPlugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); static int networkUnplugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); +/** + * VIR_NETWORK_DHCPLEASE_LENGTH_MAX: + * + * Macro providing the maximum length of an entry in the leases file + * Refer: http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2013q3/007402.html + */ +#define VIR_NETWORK_DHCPLEASE_LENGTH_MAX 2048 + +/** + * VIR_NETWORK_DHCPLEASE_PARAMS: + * + * Macro providing the maximum number of parameters in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCPLEASE_FIELDS 5
s/DHCPLEASE/DHCP_LEASE/,
+ +static int networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +static int networkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +static int networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags);
Not a big deal, but these function declarations can be removed.
static virNetworkDriverStatePtr driverState = NULL;
@@ -2980,6 +3010,167 @@ cleanup: return ret; }
+static int +networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + obj = networkObjFromNetwork(network); + + if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, NULL, leases, flags); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +static int +networkGetDHCPLeasesForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + obj = networkObjFromNetwork(network); + + if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, mac, leases, flags); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +/* This function parese the leases file generated by dnsmasq.
s/generated by/of/,
+ * Example content: + * :::::::::::::: + * /var/lib/libvirt/dnsmasq/TestNetwork1.leases + * ::::::::::::::
Not good comment style, especially when the real comment has ":" character, I'd like write it as: * An example of leases file content: * * 1379024255 52:54:00:20:70:3d 192.168.105.240 * * * 1379023351 52:54:00:b1:70:19 192.168.105.201 * *
+ * 1379024255 52:54:00:20:70:3d 192.168.105.240 * * + * 1379023351 52:54:00:b1:70:19 192.168.105.201 * * + */ +static int +networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + size_t i = 0; + char *leasefile; + FILE *fp = NULL; + size_t nleases = 0; + char **leaseparams;
To be consistent with the macro name, this should be lease_fields or leasefields.
+ virNetworkDHCPLeasesPtr *leases_ret = NULL; + char dhcpentry[VIR_NETWORK_DHCPLEASE_LENGTH_MAX];
s/DHCPLEASE/DHCP_LEASE/,
+ + virCheckFlags(0, -1); +
Redundant flags checking. You already did it in both networkGetDHCPLeases and networkGetDHCPLeasesForMAC
+ if (!network) { + virReportError(VIR_ERR_NO_NETWORK, "%s", + _("no network with matching name")); + return -1; + } + + /* Retrive leases file location */ + leasefile = networkDnsmasqLeaseFileNameDefault(network->name); + if (!(fp = fopen(leasefile, "r"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to open leases file: %s"), leasefile); + goto error;
s/error/cleanup/, since you don't have to free the lease_ret if fails at this point.
+ } + + while (fgets(dhcpentry, sizeof(dhcpentry), fp) != NULL) { + virNetworkDHCPLeasesPtr lease = NULL; + + /* Remove newline */ + dhcpentry[strlen(dhcpentry) - 1] = '\0'; + + /* split the lease line */ + leaseparams = virStringSplit(dhcpentry, " ", VIR_NETWORK_DHCPLEASE_FIELDS); + + if (virStringListLength(leaseparams) != VIR_NETWORK_DHCPLEASE_FIELDS) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Number of lease params aren't equal to: %d"), + VIR_NETWORK_DHCPLEASE_FIELDS); + goto error; + } + + if (mac && STRNEQ(mac, leaseparams[1])) + continue; + + /* We don't know the total number of leases yet */
This comment can be removed, it doesn't tell what the code does clearly, instead, it's confused. The code explain itself clearly.
+ if (VIR_EXPAND_N(leases_ret, nleases, 1) < 0) + goto error; + + if (VIR_ALLOC(leases_ret[nleases - 1]) < 0) + goto error; + + lease = leases_ret[nleases - 1]; + + /* Convert expirytime here */ + if (virStrToLong_ll(leaseparams[0], NULL, 10, &(lease->expirytime)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to convert lease expiry time to integer: %s"), + leaseparams[0]); + goto error; + } + + /* Hardcoded, as dnsmasq uses ipv4 */ + lease->type = VIR_IP_ADDR_TYPE_IPV4; + lease->prefix = virSocketAddrGetNumNetmaskBits(&obj->def->ips->netmask);
Hm, virSocketAddrGetNumNetmaskBits is used as a general purpose function, but its name is too specific. But it doesn't relate with this patch.
+ + if ((VIR_STRDUP(lease->mac, leaseparams[1]) < 0) || + (VIR_STRDUP(lease->ipaddr, leaseparams[2]) < 0) || + (VIR_STRDUP(lease->hostname, leaseparams[3]) < 0) || + (VIR_STRDUP(lease->clientid, leaseparams[4]) < 0)) + goto error; + } + + if (mac && !leases_ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no lease with matching MAC address: %s"), mac); + goto error; + } + + if (leases_ret) { + /* trim the array to the final size */
Confused comment, you are not trimming anything. Consider about: /* NULL terminated array */
+ ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1)); + *leases = leases_ret; + leases_ret = NULL; + rv = nleases; + } + +cleanup: + VIR_FORCE_FCLOSE(fp); + VIR_FREE(leasefile); + return rv; + +error: + if (leases_ret) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + } + VIR_FREE(leases_ret); + goto cleanup; +}
static virNetworkDriver networkDriver = { "Network", @@ -3004,6 +3195,8 @@ static virNetworkDriver networkDriver = { .networkSetAutostart = networkSetAutostart, /* 0.2.1 */ .networkIsActive = networkIsActive, /* 0.7.3 */ .networkIsPersistent = networkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.1.3 */ };
static virStateDriver networkStateDriver = {

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 default Expiry Time MAC address Protocol IP address Hostname ClientId ------------------------------------------------------------------------------------------------ 13-09-2013 03:45:31 52:54:00:20:70:3d ipv4 192.168.105.240/24 f18 * 13-09-2013 03:32:31 52:54:00:b1:70:19 ipv4 192.168.105.201/24 LDAP * tools/virsh.pod * Document new command --- tools/virsh-network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++ 2 files changed, 107 insertions(+) diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8ddd5ca..571bf2e 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1129,6 +1129,101 @@ cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) return ret; } +/* + * "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 bool +cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + const char *mac = NULL; + virNetworkDHCPLeasesPtr *leases = NULL; + int nleases = 0; + bool ret = false; + size_t i; + unsigned int flags = 0; + virNetworkPtr network = NULL; + + if (vshCommandOptString(cmd, "mac", &mac) < 0) + goto cleanup; + + if (!(network = vshCommandOptNetworkBy(ctl, cmd, &name, + VSH_BYNAME | VSH_BYUUID))) + goto cleanup; + + 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; + } + + vshPrintExtra(ctl, " %-20s %-20s %-10s %-20s %-12s %s\n%s%s\n", + _("Expiry Time"), _("MAC address"), _("Protocol"), + _("IP address"), _("Hostname"), _("ClientId"), + "------------------------------------------------", + "------------------------------------------------"); + + for (i = 0; i < nleases; i++) { + const char *type = NULL; + virNetworkDHCPLeasesPtr 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), "%d-%m-%Y %H:%M:%S", &ts); + + switch (lease->type) { + case VIR_IP_ADDR_TYPE_IPV4: + type = "ipv4"; + break; + case VIR_IP_ADDR_TYPE_IPV6: + type = "ipv6"; + break; + } + + vshPrintExtra(ctl, " %-20s %-20s %-10s %s/%-5d %-12s %s\n", + expirytime, lease->mac, type, lease->ipaddr, + lease->prefix, lease->hostname, lease->clientid); + } + + ret = true; + +cleanup: + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + } + VIR_FREE(leases); + if (network) + virNetworkFree(network); + return ret; +} const vshCmdDef networkCmds[] = { {.name = "net-autostart", @@ -1209,5 +1304,11 @@ const vshCmdDef networkCmds[] = { .info = info_network_uuid, .flags = 0 }, + {.name = "net-dhcp-leases", + .handler = cmdNetworkDHCPLeases, + .opts = opts_network_dhcp_leases, + .info = info_network_dhcp_leases, + .flags = 0 + }, {.name = NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 0ae5178..b87f646 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2325,6 +2325,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.7.11.7

On 13/09/13 05:53, Nehal J Wani wrote:
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 default
Expiry Time MAC address Protocol IP address Hostname ClientId ------------------------------------------------------------------------------------------------ 13-09-2013 03:45:31 52:54:00:20:70:3d ipv4 192.168.105.240/24 f18 * 13-09-2013 03:32:31 52:54:00:b1:70:19 ipv4 192.168.105.201/24 LDAP *
tools/virsh.pod * Document new command
--- tools/virsh-network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++ 2 files changed, 107 insertions(+)
diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8ddd5ca..571bf2e 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1129,6 +1129,101 @@ cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd)
return ret; } +/* + * "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 bool +cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + const char *mac = NULL; + virNetworkDHCPLeasesPtr *leases = NULL; + int nleases = 0; + bool ret = false; + size_t i; + unsigned int flags = 0; + virNetworkPtr network = NULL; + + if (vshCommandOptString(cmd, "mac", &mac) < 0) + goto cleanup;
If you "return false;" here
+ + if (!(network = vshCommandOptNetworkBy(ctl, cmd, &name, + VSH_BYNAME | VSH_BYUUID))) + goto cleanup;
and here. Then you can call virNetworkFree directly at "cleanup" label, without the checking.
+ + nleases = mac ? virNetworkGetDHCPLeasesForMAC(network, mac, &leases, flags) + :virNetworkGetDHCPLeases(network, &leases, flags);
: virNetoworkGetDHCPLeases(network, ^leases, flags);
+ + if (nleases < 0) { + vshError(ctl, _("Failed to get leases info for %s"), name); + goto cleanup; + } + + vshPrintExtra(ctl, " %-20s %-20s %-10s %-20s %-12s %s\n%s%s\n", + _("Expiry Time"), _("MAC address"), _("Protocol"), + _("IP address"), _("Hostname"), _("ClientId"), + "------------------------------------------------", + "------------------------------------------------"); + + for (i = 0; i < nleases; i++) { + const char *type = NULL; + virNetworkDHCPLeasesPtr 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), "%d-%m-%Y %H:%M:%S", &ts); + + switch (lease->type) { + case VIR_IP_ADDR_TYPE_IPV4: + type = "ipv4"; + break; + case VIR_IP_ADDR_TYPE_IPV6: + type = "ipv6"; + break; + } + + vshPrintExtra(ctl, " %-20s %-20s %-10s %s/%-5d %-12s %s\n", + expirytime, lease->mac, type, lease->ipaddr, + lease->prefix, lease->hostname, lease->clientid); + } + + ret = true; + +cleanup: + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + } + VIR_FREE(leases); + if (network) + virNetworkFree(network); + return ret; +}
const vshCmdDef networkCmds[] = { {.name = "net-autostart", @@ -1209,5 +1304,11 @@ const vshCmdDef networkCmds[] = { .info = info_network_uuid, .flags = 0 }, + {.name = "net-dhcp-leases", + .handler = cmdNetworkDHCPLeases, + .opts = opts_network_dhcp_leases, + .info = info_network_dhcp_leases, + .flags = 0 + }, {.name = NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 0ae5178..b87f646 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2325,6 +2325,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
participants (2)
-
Nehal J Wani
-
Osier Yang