[libvirt] [PATCH 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 * 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 | 128 +++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 22 +++++ python/generator.py | 3 + src/driver.h | 13 +++ src/libvirt.c | 166 ++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 7 ++ src/network/bridge_driver.c | 222 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 117 +++++++++++++++++++++++ src/remote/remote_protocol.x | 48 +++++++++- src/remote_protocol-structs | 27 ++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-network.c | 92 ++++++++++++++++++ tools/virsh.pod | 6 ++ 13 files changed, 851 insertions(+), 1 deletion(-) -- 1.7.11.7

Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeaseForMAC 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. * virNetworkGetDHCPLeaseForMAC: returns the dhcp lease 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 virNetworkGetDHCPLeaseForMAC * Define virNetworkDHCPLeaseFree python/generator.py: * Skip the auto-generation for virNetworkGetDHCPLeases * Skip the auto-generation for virNetworkGetDHCPLeaseForMAC * Skip the auto-generation for virNetworkDHCPLeaseFree src/driver.h: * Define networkGetDHCPLeases * Define networkGetDHCPLeaseForMAC src/libvirt.c: * Implement virNetworkGetDHCPLeases * Implement virNetworkGetDHCPLeaseForMAC * Implement virNetworkDHCPLeaseFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 22 ++++++ python/generator.py | 3 + src/driver.h | 13 ++++ src/libvirt.c | 166 +++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 7 ++ 5 files changed, 211 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +}; + +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr leases, + unsigned int flags); + /* * virConnectListAllInterfaces: * diff --git a/python/generator.py b/python/generator.py index a91dde8..708657a 100755 --- a/python/generator.py +++ b/python/generator.py @@ -460,6 +460,8 @@ skip_impl = ( 'virNodeGetCPUMap', 'virDomainMigrate3', 'virDomainMigrateToURI3', + 'virNetworkGetDHCPLeases', + 'virNetworkGetDHCPLeaseForMAC', ) 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..4c835b2 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 +(*virDrvNetworkGetDHCPLeaseForMAC)(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; + virDrvNetworkGetDHCPLeaseForMAC networkGetDHCPLeaseForMAC; }; diff --git a/src/libvirt.c b/src/libvirt.c index 665b30b..63afdac 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" @@ -21961,3 +21962,168 @@ 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(nleaseswork, &leases, flags); + * if (ret < 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; +} + +/** + * virNetworkGetDHCPLeaseForMAC: + * @network: pointer to network object + * @mac: MAC Address of an interface + * @lease: pointer to the obtained lease + * @flags: extra flags, not used yet, so callers should always pass 0 + * + * The API returns the lease info of the interface which matches + * the given @mac + * + * Returns 1 on success, -1 otherwise. The caller is responsible for calling + * virNetworkDHCPLeaseFree to free the lease pointer @lease. + */ +int +virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr lease, + unsigned int flags) +{ + virConnectPtr conn; + virMacAddr addr; + + VIR_DEBUG("network=%p, mac=%s, lease=%p, flags=%x", + network, mac, lease, flags); + + virResetLastError(); + + virCheckNonNullArgGoto(network, error); + virCheckNonNullArgGoto(mac, error); + + 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->networkGetDHCPLeaseForMAC) { + int ret; + ret = conn->networkDriver->networkGetDHCPLeaseForMAC(network, mac, + lease, 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_public.syms b/src/libvirt_public.syms index bbdf78a..40b592f 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; + virNetworkGetDHCPLeaseForMAC; + virNetworkDHCPLeaseFree; +} LIBVIRT_1.1.1; + # .... define new API here using predicted next version number .... -- 1.7.11.7

On Wed, Sep 11, 2013 at 09:00:09PM +0530, Nehal J Wani wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +};
This is missing int type; /* virIPAddrType */ since it can be IPv4 or IPv6 in general. Also we have no 'prefix' field here. Although the 'prefix' is present in the network XML config, I think it would be useful to include it here too, for parity with the virDomainInterfaceIPAddress struct
+ +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr leases,
This should be '**leases' as with the other method. While our dnsmasq setup only supports a single lease, for IPv4, that is not suitably generic. We may well need to support DHCP v6 in the future which would mean we had multiple leases to return per MAC address.
+ unsigned int flags); + /* * virConnectListAllInterfaces: *
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 Wed, Sep 11, 2013 at 9:25 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
On Wed, Sep 11, 2013 at 09:00:09PM +0530, Nehal J Wani wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +};
This is missing
int type; /* virIPAddrType */
since it can be IPv4 or IPv6 in general.
Also we have no 'prefix' field here. Although the 'prefix' is present in the network XML config, I think it would be useful to include it here too, for parity with the virDomainInterfaceIPAddress struct
The virNetworkDHCPLeases struct was made according to the lease parameters returned by dnsmasq. Are you suggesting that libvirt might shift to some other DHCP server in future? Also, in case the DHCP server doesn't return the IP address type and/or prefix, in that case, should these values be NULL, when returned to the user?
+ +void virNetworkDHCPLeaseFree(virNetworkDHCPLeasesPtr lease); + +int virNetworkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); + +int virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr leases,
This should be '**leases' as with the other method. While our dnsmasq setup only supports a single lease, for IPv4, that is not suitably generic. We may well need to support DHCP v6 in the future which would mean we had multiple leases to return per MAC address.
+ unsigned int flags); + /* * virConnectListAllInterfaces: *
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 :|
-- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com

On Wed, Sep 11, 2013 at 10:35:04PM +0530, Nehal J Wani wrote:
On Wed, Sep 11, 2013 at 9:25 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
On Wed, Sep 11, 2013 at 09:00:09PM +0530, Nehal J Wani wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +};
This is missing
int type; /* virIPAddrType */
since it can be IPv4 or IPv6 in general.
Also we have no 'prefix' field here. Although the 'prefix' is present in the network XML config, I think it would be useful to include it here too, for parity with the virDomainInterfaceIPAddress struct
The virNetworkDHCPLeases struct was made according to the lease parameters returned by dnsmasq. Are you suggesting that libvirt might shift to some other DHCP server in future? Also, in case the DHCP server doesn't return the IP address type and/or prefix, in that case, should these values be NULL, when returned to the user?
When doing API design we must *not* make assumptions about the current impl that libvirt happens to have. We must always think of possible future changes. The DHCP server doesn't need to return prefix - we have that available in virNetworkDefPtr. As for IP address type, we can currently hardcode that as IPV4, since we know dnsmasq only uses that. If we later make use of DHCPv6 we can worry about distinguishing them at that point 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 09/11/2013 01:14 PM, Daniel P. Berrange wrote:
On Wed, Sep 11, 2013 at 10:35:04PM +0530, Nehal J Wani wrote:
On Wed, Sep 11, 2013 at 9:25 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
On Wed, Sep 11, 2013 at 09:00:09PM +0530, Nehal J Wani wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +}; This is missing
int type; /* virIPAddrType */
since it can be IPv4 or IPv6 in general.
Also we have no 'prefix' field here. Although the 'prefix' is present in the network XML config, I think it would be useful to include it here too, for parity with the virDomainInterfaceIPAddress struct
The virNetworkDHCPLeases struct was made according to the lease parameters returned by dnsmasq. Are you suggesting that libvirt might shift to some other DHCP server in future? Also, in case the DHCP server doesn't return the IP address type and/or prefix, in that case, should these values be NULL, when returned to the user? When doing API design we must *not* make assumptions about the current impl that libvirt happens to have. We must always think of possible future changes.
I may be mistaken, but I thought I remembered someone talking about an alternate implementation using ISC dhcpd instead of dnsmasq. A concrete example of this is that in earlier versions of libvirt (and still for earlier versions of dnsmasq even with current libvirt) we use(d) radvd for ipv6 autoconf, but in newer libvirt with newer versions of dnsmasq, we use the autoconf support that is now built into dnsmasq. The libvirt network configuration remains the same; This is possible because the configuration is agnostic to the underlying implementation.
The DHCP server doesn't need to return prefix - we have that available in virNetworkDefPtr. As for IP address type, we can currently hardcode that as IPV4, since we know dnsmasq only uses that.
commit 2d5cd1d724084d9975b2514fb31776627acbe997 Author: Gene Czarcinski <gene@czarc.net> Date: Thu Dec 6 12:20:38 2012 -0500 network: add support for DHCPv6 I haven't used it, but as far as I know it works (if it doesn't then Gene is in a heap of trouble :-)
If we later make use of DHCPv6 we can worry about distinguishing them at that point

On Wed, Sep 11, 2013 at 02:18:04PM -0400, Laine Stump wrote:
On 09/11/2013 01:14 PM, Daniel P. Berrange wrote:
On Wed, Sep 11, 2013 at 10:35:04PM +0530, Nehal J Wani wrote:
On Wed, Sep 11, 2013 at 9:25 PM, Daniel P. Berrange <berrange@redhat.com> wrote:
On Wed, Sep 11, 2013 at 09:00:09PM +0530, Nehal J Wani wrote:
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..3885baf 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,28 @@ int virConnectNumOfDefinedInterfaces (virConnectPtr conn); int virConnectListDefinedInterfaces (virConnectPtr conn, char **const names, int maxnames); + +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { + long long expirytime; + char *mac; + char *ipaddr; + char *hostname; + char *clientid; +}; This is missing
int type; /* virIPAddrType */
since it can be IPv4 or IPv6 in general.
Also we have no 'prefix' field here. Although the 'prefix' is present in the network XML config, I think it would be useful to include it here too, for parity with the virDomainInterfaceIPAddress struct
The virNetworkDHCPLeases struct was made according to the lease parameters returned by dnsmasq. Are you suggesting that libvirt might shift to some other DHCP server in future? Also, in case the DHCP server doesn't return the IP address type and/or prefix, in that case, should these values be NULL, when returned to the user? When doing API design we must *not* make assumptions about the current impl that libvirt happens to have. We must always think of possible future changes.
I may be mistaken, but I thought I remembered someone talking about an alternate implementation using ISC dhcpd instead of dnsmasq.
A concrete example of this is that in earlier versions of libvirt (and still for earlier versions of dnsmasq even with current libvirt) we use(d) radvd for ipv6 autoconf, but in newer libvirt with newer versions of dnsmasq, we use the autoconf support that is now built into dnsmasq. The libvirt network configuration remains the same; This is possible because the configuration is agnostic to the underlying implementation.
The DHCP server doesn't need to return prefix - we have that available in virNetworkDefPtr. As for IP address type, we can currently hardcode that as IPV4, since we know dnsmasq only uses that.
commit 2d5cd1d724084d9975b2514fb31776627acbe997 Author: Gene Czarcinski <gene@czarc.net> Date: Thu Dec 6 12:20:38 2012 -0500
network: add support for DHCPv6
I haven't used it, but as far as I know it works (if it doesn't then Gene is in a heap of trouble :-)
Ah, then we need to support multiple addresses per MAC already then 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, virNetworkGetDHCPLeaseForMAC daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeaseForMAC src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeaseForMAC 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_LEASE_FOR_MAC * Define structs remote_network_dhcp_lease_for_mac, remote_network_get_dhcp_lease_for_mac_args, remote_network_get_dhcp_lease_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 | 128 +++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 117 +++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 48 +++++++++++++++- src/remote_protocol-structs | 27 +++++++++ src/rpc/gendispatch.pl | 1 + 5 files changed, 320 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 2aff7c1..13be327 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5137,7 +5137,135 @@ 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; + + 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 +remoteDispatchNetworkGetDHCPLeaseForMAC(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_lease_for_mac_args *args, + remote_network_get_dhcp_lease_for_mac_ret *ret) +{ + int rv = -1; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virNetworkDHCPLeases lease; + virNetworkPtr net = NULL; + const char *mac; + remote_network_dhcp_lease *lease_ret = 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 ((rv = virNetworkGetDHCPLeaseForMAC(net, mac, &lease, + args->flags)) < 0) + goto cleanup; + + lease_ret = &ret->lease; + lease_ret->expirytime = lease.expirytime; + + 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)) + rv = -1; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + return rv; +} /*----- Helpers. -----*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 62e77a5..f2cf2fc 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6599,6 +6599,121 @@ done: return rv; } +static int +remoteNetworkGetDHCPLeaseForMAC(virNetworkPtr net, + const char *mac, + virNetworkDHCPLeasesPtr lease, + unsigned int flags) +{ + int rv = -1; + struct private_data *priv = net->conn->networkPrivateData; + remote_network_get_dhcp_lease_for_mac_args args; + remote_network_get_dhcp_lease_for_mac_ret 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_LEASE_FOR_MAC, + (xdrproc_t)xdr_remote_network_get_dhcp_lease_for_mac_args, (char *)&args, + (xdrproc_t)xdr_remote_network_get_dhcp_lease_for_mac_ret, (char *)&ret) == -1) { + goto done; + } + + lease->expirytime = ret.lease.expirytime; + + if ((VIR_STRDUP(lease->mac, ret.lease.mac) < 0) || + (VIR_STRDUP(lease->ipaddr, ret.lease.ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, ret.lease.hostname) < 0) || + (VIR_STRDUP(lease->clientid, ret.lease.clientid) < 0)) + goto cleanup; + + rv = 1; + +cleanup: + xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_lease_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; + + 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 +7073,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 */ + .networkGetDHCPLeaseForMAC = remoteNetworkGetDHCPLeaseForMAC, /* 1.1.3 */ }; static virInterfaceDriver interface_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index a1c23da..75d2c60 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 = 1024; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -2835,6 +2840,33 @@ 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; +}; + +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_lease_for_mac_args { + remote_nonnull_network net; + remote_string mac; + unsigned int flags; +}; + +struct remote_network_get_dhcp_lease_for_mac_ret { + remote_network_dhcp_lease lease; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -4998,5 +5030,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_LEASE_FOR_MAC = 313 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 4e27aae..d8b7237 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2316,6 +2316,31 @@ 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; +}; +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_lease_for_mac_args { + remote_nonnull_network net; + remote_string mac; + u_int flags; +}; +struct remote_network_get_dhcp_lease_for_mac_ret { + remote_network_dhcp_lease lease; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -2628,4 +2653,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_LEASE_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 Wed, Sep 11, 2013 at 09:00:10PM +0530, Nehal J Wani wrote:
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index a1c23da..75d2c60 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 = 1024;
I think this needs to be significantly larger. People I know are already trying to run 8000 containers on a single host + network. 32768 might be a suitable level to start with. 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 :|

+ + 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; + + 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; + } +
This above code is reported so many times in the patch, in networkGetDHCPLeaseForMAC, remoteNetworkGetDHCPLeaseForMAC, remoteNetworkGetDHCPLeases, remoteDispatchNetworkGetDHCPLeaseForMAC and remoteSerializeNetworkDHCPLeases. Hence I was wondering, whether it would be useful to introduce a helper function, say virNetworkDHCPLeaseCopy, which would copy lease contents from one lease pointer to another, something like: /** * virNetworkDHCPLeaseCopy: * @dst: pointer to the destination lease object * @src: pointer to the source lease object * * Copies contents of @src to @dst. * * Returns 0 on success, -1 otherwise. */ int virNetworkDHCPLeaseCopy(virNetworkDHCPLeasesPtr dst, virNetworkDHCPLeasesPtr src) { dst->expirytime = src->expirytime; if ((VIR_STRDUP(dst->macaddr, src->macaddr) < 0) || (VIR_STRDUP(dst->ipaddr, src->ipaddr) < 0) || (VIR_STRDUP(dst->hostname, src->hostname) < 0) || (VIR_STRDUP(dst->clientid, src->clientid) < 0)) return -1; return 0; } But the issue with this is that it wants the user to allocate memory to the dst pointer (As the code in remote protocols does). Also, will it be ever used by the users? If not, then should we be introducing this function to some place in /src/util, so that code redundancy can be removed? -- Nehal J Wani

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 networkGetDHCPLeaseForMAC * Implement networkGetDHCPLeasesHelper --- src/network/bridge_driver.c | 222 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 3a8be90..e5923eb 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -109,6 +109,35 @@ 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 networkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr lease, + unsigned int flags); + +static int networkGetDHCPLeasesHelper(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags); static virNetworkDriverStatePtr driverState = NULL; @@ -2980,6 +3009,197 @@ cleanup: return ret; } +static int +networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkDriverStatePtr driver = network->conn->networkPrivateData; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + networkDriverLock(driver); + obj = virNetworkFindByName(&driver->networks, network->name); + networkDriverUnlock(driver); + + if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, NULL, leases, flags); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} + +static int +networkGetDHCPLeaseForMAC(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr lease, + unsigned int flags) +{ + virNetworkDHCPLeasesPtr *leases = NULL; + int nleases = 0; + int rv = -1; + size_t i; + + virNetworkDriverStatePtr driver = network->conn->networkPrivateData; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + networkDriverLock(driver); + obj = virNetworkFindByName(&driver->networks, network->name); + networkDriverUnlock(driver); + + if (virNetworkGetDHCPLeaseForMACEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + if ((nleases = networkGetDHCPLeasesHelper(network, mac, + &leases, flags)) <= 0) + goto error; + + if (nleases > 1) { + /* Hmm, can DHCP give more than one lease for same MAC? */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Something is wrong. MAC address " + "can't repeat in the leases")); + goto error; + } + + lease->expirytime = leases[0]->expirytime; + + if ((VIR_STRDUP(lease->mac, leases[0]->mac) < 0) || + (VIR_STRDUP(lease->ipaddr, leases[0]->ipaddr) < 0) || + (VIR_STRDUP(lease->hostname, leases[0]->hostname) < 0) || + (VIR_STRDUP(lease->clientid, leases[0]->clientid) < 0)) + goto error; + + rv = nleases; + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; + +error: + if (leases) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases[i]); + } + VIR_FREE(leases); + goto cleanup; +} + +static int +networkGetDHCPLeasesHelper(virNetworkPtr network, + const char *mac, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + char *leasefile; + char **leaseparams; + char dhcpentry[VIR_NETWORK_DHCPLEASE_LENGTH_MAX]; + FILE *fp = NULL; + int rv = -1; + + virNetworkDHCPLeasesPtr *leases_ret = NULL; + size_t nleases = 0; + size_t i = 0; + + + 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; + } + + 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) + break; + } + + 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 +3224,8 @@ static virNetworkDriver networkDriver = { .networkSetAutostart = networkSetAutostart, /* 0.2.1 */ .networkIsActive = networkIsActive, /* 0.7.3 */ .networkIsPersistent = networkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeaseForMAC = networkGetDHCPLeaseForMAC, /* 1.1.3 */ }; static virStateDriver networkStateDriver = { -- 1.7.11.7

Use virNetworkGetDHCPLeases and virNetworkGetDHCPLeaseForMAC 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 IP address Hostname ClientId ---------------------------------------------------------------------------------- 11-09-2013 03:53:11 52:54:00:89:4e:97 192.168.101.130 f18 * 11-09-2013 03:45:20 52:54:00:fe:4c:4f 192.168.101.197 * * tools/virsh.pod * Document new command --- tools/virsh-network.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 ++++ 2 files changed, 98 insertions(+) diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8ddd5ca..6319d29 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1129,6 +1129,92 @@ 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; + virNetworkDHCPLeases lease_mac; + 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 ? virNetworkGetDHCPLeaseForMAC(network, mac, &lease_mac, flags) + :virNetworkGetDHCPLeases(network, &leases, flags); + + if (nleases < 0) { + vshError(ctl, _("Failed to get leases info for %s"), name); + goto cleanup; + } + + vshPrintExtra(ctl, " %-20s %-20s %-17s %-12s %s\n%s%s\n", + _("Expiry Time"), _("MAC address"), + _("IP address"), _("Hostname"), _("ClientId"), + "--------------------------------------------", + "--------------------------------------------"); + + for (i = 0; i < nleases; i++) { + virNetworkDHCPLeasesPtr lease = mac ? &lease_mac : 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); + + vshPrintExtra(ctl, " %-20s %-20s %-17s %-12s %s\n", + expirytime, lease->mac, lease->ipaddr, + 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 +1295,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
participants (3)
-
Daniel P. Berrange
-
Laine Stump
-
Nehal J Wani