[libvirt] Unable to setup qemu-guest-agent
Could anyone please list out the steps required to run the command $virsh qemu-agent-command Steps that I followed: 1. Clone the latest source code of libvirt 2. Create a vm of f18 (source:liveCD) 3. Edit f18 domain xml and add this: channel type='unix' source mode='bind' path='/var/lib/libvirt/qemu/f16x86_64.agent'/ target type='virtio' name='org.qemu.guest_agent.0'/ /channel 4. On host: #./tools/virsh start f18 5. On guest: #yum install qemu-guest-agent -y 6. On host: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' Expected Response: {return:[{name:lo,ip- addresses:[{ip-address-type:ipv4,ip-address:127.0.0.1,prefix:8},{ip-address-type:ipv6,ip-address:::1,prefix:128}],hardware-address:00:00:00:00:00:00},{name:eth0,ip-addresses:[{ip-address-type:ipv4,ip-address:192.168.122.62,prefix:24},{ip-address-type:ipv6,ip-address:fe80::5054:ff:fe14:9998,prefix:64}],hardware-address:52:54:00:14:99:98}]} Actual result: error: unknown procedure: 3 Where am I going wrong? -- Nehal J. Wani UG2, BTech CS+MS(CL) IIIT-Hyderabad http://commanlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] Unable to setup qemu-guest-agent
The error: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' error: unknown procedure: 3 Comes when I clone from $git clone git://libvirt.org/libvirt.git But when I download http://libvirt.org/sources/libvirt-1.0.6.tar.gz and make, I get: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' (null) On 6/17/13, Osier Yang jy...@redhat.com wrote: On 17/06/13 14:00, Nehal J. Wani wrote: Could anyone please list out the steps required to run the command $virsh qemu-agent-command Steps that I followed: 1. Clone the latest source code of libvirt 2. Create a vm of f18 (source:liveCD) 3. Edit f18 domain xml and add this: channel type='unix' source mode='bind' path='/var/lib/libvirt/qemu/f16x86_64.agent'/ target type='virtio' name='org.qemu.guest_agent.0'/ /channel 4. On host: #./tools/virsh start f18 5. On guest: #yum install qemu-guest-agent -y 6. On host: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' Expected Response: {return:[{name:lo,ip- addresses:[{ip-address-type:ipv4,ip-address:127.0.0.1,prefix:8},{ip-address-type:ipv6,ip-address:::1,prefix:128}],hardware-address:00:00:00:00:00:00},{name:eth0,ip-addresses:[{ip-address-type:ipv4,ip-address:192.168.122.62,prefix:24},{ip-address-type:ipv6,ip-address:fe80::5054:ff:fe14:9998,prefix:64}],hardware-address:52:54:00:14:99:98}]} Actual result: error: unknown procedure: 3 What's your running libvirtd's version? It sounds like it's old enough without the API used by qemu-guest-agent. Osier -- Nehal J. Wani UG2, BTech CS+MS(CL) IIIT-Hyderabad http://commanlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] Unable to setup qemu-guest-agent
I was able to solve the error. It was a stupid mistake. There was a mismatch between versions of virsh and the libvirt daemon. On Mon, Jun 17, 2013 at 3:56 PM, Michal Privoznik mpriv...@redhat.comwrote: On 17.06.2013 09:21, Nehal J. Wani wrote: The error: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' error: unknown procedure: 3 Comes when I clone from $git clone git://libvirt.org/libvirt.git But when I download http://libvirt.org/sources/libvirt-1.0.6.tar.gz and make, I get: # ./tools/virsh qemu-agent-command f18 '{execute:guest-network-get-interfaces}' (null) Unfortunately, the patch which dispatches errors from qemu-agent-command has been submitted after the 1.0.6 release: commit 0eb2f8aa90d26e75ce5d9449da03bb553da85d2d Author: Peter Krempa pkre...@redhat.com AuthorDate: Mon Jun 3 16:12:52 2013 +0200 Commit: Peter Krempa pkre...@redhat.com CommitDate: Mon Jun 3 17:25:33 2013 +0200 libvirt-qemu: Dispatch errors from virDomainQemuAgentCommand() The original implementation didn't follow the established pattern and did not dispatch errors in case of failure. So if you could try out building the libvirt from git and get the real error. Or if you want to use the 1.0.6 release, you'll find the error message in the libvirtd log. Michal -- Nehal J. Wani UG2, BTech CS+MS(CL) IIIT-Hyderabad http://commanlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] RFC: Introduce API to query IP addresses for given domain
Hello, fellow developers! I am a GSoC candidate this year working for libvirt.org. My project is Introduce API to query IP addresses for given domain. The discussion regarding this feature had started here: http://www.mail-archive.com/libvir-list@redhat.com/msg51857.html and then Michal had sent a patch too (refer: http://www.mail-archive.com/libvir-list@redhat.com/msg57141.html). But it was not pushed upstream due to lack of extensibility. So far I've come up with an API and I want to get your opinion before I start writing the rest so I don't follow the wrong direction. Following are the valid commands: domifaddr domain-name domifaddr domain-name interface-name domifaddr domain-name interface-name method domifaddr domain-name method methods: (i) Querying qemu-guest-agent (ii) Getting info from dnsmasq.leases file (iii) Using the nwfilter to snoop the traffic If no method is mentioned, qemu-guest-agent will be used. Previous attempts by Michal had used structs and xml. Structs bring in restrictions and xml has to be parsed. Hence I am not planning to continue with either of these. As a start, I would like to know your comments about my API which queries the qemu-guest-agent and returns the results in virTypedParameter **params. Format(JSON) in which the qemu guest agent returns info: [{name:lo, ip-addresses: [{ip-address-type:ipv4,ip-address:127.0.0.1,prefix:8}, {ip-address-type:ipv6,ip-address:::1,prefix:128}], hardware-address:00:00:00:00:00:00}, {name:eth0, ip-addresses: [{ip-address-type:ipv4,ip-address:192.168.122.42,prefix:24}, {ip-address-type:ipv6,ip-address:fe80::5054:ff:fe09:d240,prefix:64}], hardware-address:52:54:00:09:d2:40}] //Possible 1-D Structure (A little hassle to maintain) params[0] = {iface-count,int,2} params[1] = {iface-name,string,lo} params[2] = {iface-hwaddr,string,00:00:00:00:00:00} params[3] = {iface-addr-count,int,2} params[4] = {iface-addr-type,string,ipv4} params[5] = {iface-addr,string,127.0.0.1} params[6] = {iface-addr-prefix,int,8} params[7] = {iface-addr-type,string,ipv6} params[8] = {iface-addr,string,::1} params[9] = {iface-addr-prefix,int,128} //2D Structure: (Not very hasslefree, but easier to maintain as one interface per row) params[0] = {iface-name,string,lo}{iface-hwaddr,string,00:00:00:00:00:00}{iface-addr-type,string,ipv4}{iface-addr,string,127.0.0.1}{iface-addr-prefix,int,8}{iface-addr-type,string,ipv6}{iface-addr,string,::1}{iface-addr-prefix,int,128} params[1] = {iface-name,string,eth0}{iface-hwaddr,string,52:54:00:09:d2:40}{iface-addr-type,string,ipv4}{iface-addr,string,192.168.122.42}{iface-addr-prefix,int,8}{iface-addr-type,string,ipv6}{iface-addr,string,fe80::5054:ff:fe09:d240}{iface-addr-prefix,int,64} Function definitions that I intend to use are: static int remoteDispatchDomainInterfacesAddresses( virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, remote_domain_interfaces_addresses_args *args, remote_domain_interfaces_addresses_ret *ret) int virDomainInterfacesAddresses (virDomainPtr dom, virTypedParameterPtr *params, int *nparams, unsigned int flags); typedef int (*virDrvDomainInterfacesAddresses) (virDomainPtr dom, virTypedParameterPtr *params, int *nparams, unsigned int flags); int virDomainInterfacesAddresses (virDomainPtr dom, virTypedParameterPtr *params, int *nparams, unsigned int flags) int qemuAgentGetInterfaces(qemuAgentPtr mon, virTypedParameterPtr *params, int *nparams) int qemuAgentGetInterfaces(qemuAgentPtr mon, virTypedParameterPtr *params, int *nparams); static int qemuDomainInterfacesAddresses(virDomainPtr dom, virTypedParameterPtr *params, int *nparams, unsigned int flags) static int remoteDomainInterfacesAddresses(virDomainPtr dom, virTypedParameterPtr *params, int *nparams, unsigned int flags) static bool cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) Also, It will be helpful to know whether we want the client to first query for the number of parameters and then send the request or have the server side allocate appropriate memory and return the result once in for all. In the latter case, I'll be using something of the kind virTypedParameterPtr ***params. Thanking You, Nehal J. Wani UG2, BTech
Re: [libvirt] RFC: Introduce API to query IP addresses for given domain
Following will be the methods: (i) Querying qemu-guest-agent (ii) Getting info from dnsmasq.leases file (iii) Using the nwfilter to snoop the traffic Valid values: domifaddr domain-name qemu-ga domifaddr domain-name dnsmasq domifaddr domain-name snoop Suggestions are welcome for the 'name' of values of the option 'method'. The main idea behind using virTypedParameter: It gives us extensibility - as long as we tell the user how many interfaces and how many parameters per interface, then we can add more parameters per interface. If we use structs, then extensibility is lost. If we use XML, then first JSON output is parsed into XML, then XML is parsed. More effort is involved. As I think the previous patches by Michal were not pushed upstream due to lack of extensibility. On Tue, Jul 2, 2013 at 4:03 PM, Daniel P. Berrange berra...@redhat.comwrote: On Fri, Jun 28, 2013 at 03:56:10PM +0530, Nehal J. Wani wrote: Hello, fellow developers! I am a GSoC candidate this year working for libvirt.org. My project is Introduce API to query IP addresses for given domain. The discussion regarding this feature had started here: http://www.mail-archive.com/libvir-list@redhat.com/msg51857.html and then Michal had sent a patch too (refer: http://www.mail-archive.com/libvir-list@redhat.com/msg57141.html). But it was not pushed upstream due to lack of extensibility. So far I've come up with an API and I want to get your opinion before I start writing the rest so I don't follow the wrong direction. Following are the valid commands: domifaddr domain-name domifaddr domain-name interface-name domifaddr domain-name interface-name method domifaddr domain-name method What are valid values for 'method' here ? methods: (i) Querying qemu-guest-agent (ii) Getting info from dnsmasq.leases file (iii) Using the nwfilter to snoop the traffic If no method is mentioned, qemu-guest-agent will be used. Previous attempts by Michal had used structs and xml. Structs bring in restrictions and xml has to be parsed. Hence I am not planning to continue with either of these. As a start, I would like to know your comments about my API which queries the qemu-guest-agent and returns the results in virTypedParameter **params. Format(JSON) in which the qemu guest agent returns info: [{name:lo, ip-addresses: [{ip-address-type:ipv4,ip-address:127.0.0.1,prefix:8}, {ip-address-type:ipv6,ip-address:::1,prefix:128}], hardware-address:00:00:00:00:00:00}, {name:eth0, ip-addresses: [{ip-address-type:ipv4,ip-address:192.168.122.42,prefix:24}, {ip-address-type:ipv6,ip-address:fe80::5054:ff:fe09:d240,prefix:64}], hardware-address:52:54:00:09:d2:40}] //Possible 1-D Structure (A little hassle to maintain) params[0] = {iface-count,int,2} params[1] = {iface-name,string,lo} params[2] = {iface-hwaddr,string,00:00:00:00:00:00} params[3] = {iface-addr-count,int,2} params[4] = {iface-addr-type,string,ipv4} params[5] = {iface-addr,string,127.0.0.1} params[6] = {iface-addr-prefix,int,8} params[7] = {iface-addr-type,string,ipv6} params[8] = {iface-addr,string,::1} params[9] = {iface-addr-prefix,int,128} //2D Structure: (Not very hasslefree, but easier to maintain as one interface per row) params[0] = {iface-name,string,lo}{iface-hwaddr,string,00:00:00:00:00:00}{iface-addr-type,string,ipv4}{iface-addr,string,127.0.0.1}{iface-addr-prefix,int,8}{iface-addr-type,string,ipv6}{iface-addr,string,::1}{iface-addr-prefix,int,128} params[1] = {iface-name,string,eth0}{iface-hwaddr,string,52:54:00:09:d2:40}{iface-addr-type,string,ipv4}{iface-addr,string,192.168.122.42}{iface-addr-prefix,int,8}{iface-addr-type,string,ipv6}{iface-addr,string,fe80::5054:ff:fe09:d240}{iface-addr-prefix,int,64} IMHO both of these approaches to encoding the data in virTypedParameter are seriously unpleasant for an app to deal with. Now this is a true for virTypedParameter in general, but I think that the need to deal with a list of objects here, each containing a list of typed parameters makes it even worse than normal. I wouldn't really like this as an application developer. Looking at this possible approach of virTypedParameter, I'm think I am preferring either the XML or fixed struct approach to this API as was proposed in the past, with a bias towards a fixed struct for simplicity of use by app developers. Regards, Danuiel -- |: 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 UG2, BTech CS+MS(CL) IIIT-Hyderabad http://commanlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https
Re: [libvirt] RFC: Introduce API to query IP addresses for given domain
Eric, could you please share your opinion as to what should be more appropriate to use for this functionality: Structs/XML/VirTypedParams ? On Tue, Jul 2, 2013 at 7:25 PM, Osier Yang jy...@redhat.com wrote: On 02/07/13 18:33, Daniel P. Berrange wrote: On Fri, Jun 28, 2013 at 03:56:10PM +0530, Nehal J. Wani wrote: Hello, fellow developers! I am a GSoC candidate this year working for libvirt.org. My project is Introduce API to query IP addresses for given domain. The discussion regarding this feature had started here: http://www.mail-archive.com/**libvir-list@redhat.com/**msg51857.htmlhttp://www.mail-archive.com/libvir-list@redhat.com/msg51857.htmland then Michal had sent a patch too (refer: http://www.mail-archive.com/**libvir-list@redhat.com/**msg57141.htmlhttp://www.mail-archive.com/libvir-list@redhat.com/msg57141.html). But it was not pushed upstream due to lack of extensibility. So far I've come up with an API and I want to get your opinion before I start writing the rest so I don't follow the wrong direction. Following are the valid commands: domifaddr domain-name domifaddr domain-name interface-name domifaddr domain-name interface-name method domifaddr domain-name method What are valid values for 'method' here ? methods: (i) Querying qemu-guest-agent (ii) Getting info from dnsmasq.leases file (iii) Using the nwfilter to snoop the traffic If no method is mentioned, qemu-guest-agent will be used. Previous attempts by Michal had used structs and xml. Structs bring in restrictions and xml has to be parsed. Hence I am not planning to continue with either of these. As a start, I would like to know your comments about my API which queries the qemu-guest-agent and returns the results in virTypedParameter **params. Format(JSON) in which the qemu guest agent returns info: [{name:lo, ip-addresses: [{ip-address-type:ipv4,**ip-address:127.0.0.1,* *prefix:8}, {ip-address-type:ipv6,ip-** address:::1,prefix:128}], hardware-address:00:00:00:**00:00:00}, {name:eth0, ip-addresses: [{ip-address-type:ipv4,** ip-address:192.168.122.42,**prefix:24}, {ip-address-type:ipv6,ip-** address:fe80::5054:ff:fe09:**d240,prefix:64}], hardware-address:52:54:00:**09:d2:40}] //Possible 1-D Structure (A little hassle to maintain) params[0] = {iface-count,int,2} params[1] = {iface-name,string,lo} params[2] = {iface-hwaddr,string,00:00:**00:00:00:00} params[3] = {iface-addr-count,int,2} params[4] = {iface-addr-type,string,**ipv4} params[5] = {iface-addr,string,127.0.0.**1} params[6] = {iface-addr-prefix,int,8} params[7] = {iface-addr-type,string,**ipv6} params[8] = {iface-addr,string,::1} params[9] = {iface-addr-prefix,int,128} //2D Structure: (Not very hasslefree, but easier to maintain as one interface per row) params[0] = {iface-name,string,lo}{**iface-hwaddr,string,00:00:** 00:00:00:00}{iface-addr-**type,string,ipv4}{iface-** addr,string,127.0.0.1}{**iface-addr-prefix,int,8}{** iface-addr-type,string,ipv6**}{iface-addr,string,::1}{** iface-addr-prefix,int,128} params[1] = {iface-name,string,eth0}{**iface-hwaddr,string,52:54: **00:09:d2:40}{iface-addr-**type,string,ipv4}{iface-** addr,string,192.168.122.42}**{iface-addr-prefix,int,8}{** iface-addr-type,string,ipv6**}{iface-addr,string,fe80::** 5054:ff:fe09:d240}{iface-**addr-prefix,int,64} IMHO both of these approaches to encoding the data in virTypedParameter are seriously unpleasant for an app to deal with. Now this is a true for virTypedParameter in general, but I think that the need to deal with a list of objects here, each containing a list of typed parameters makes it even worse than normal. I wouldn't really like this as an application developer. Looking at this possible approach of virTypedParameter, I'm think I am preferring either the XML or fixed struct approach to this API as was proposed in the past, with a bias towards a fixed struct for simplicity of use by app developers. agreed. after seeing the trouble caused by multiple addrs, i'm not sure about using virTypedParameter too. even if we have an array type value, it still looks like not easy to use for api user, one has to know how many elements of the array too. Regards, Danuiel -- Nehal J. Wani UG2, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] RFC: Introduce API to return configuration/state paths of the network driver
Currently, there is no API which returns configuration/state paths of the network driver. Although it is a private implementation of the network driver, I don't see any harm in making the locations public because although the locations might change, there will always be a location for these files. There is a need for this API to implement method 2 of the API to query ip addresses of a given domain, refer: http://www.mail-archive.com/libvir-list@redhat.com/msg79793.html . It is required to parse the leases file generated by dnsmasq. So, this API will be used by the qemu driver, but it can also be made public, so that, if a user wants to know get some information from a configuration file, he can get the location from libvirt and analyze it on his own. Right now, there is an alternate way to get the info: by using networkDnsmasqLeaseFileNameDefault, defined in /src/network/bridge_driver.c Since this function is static, it is part of the private implementation and not visible outside. To make it public, the following hack is possible: diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index a7ff602..7274861 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -124,7 +124,7 @@ static int networkUnplugBandwidth(virNetworkObjPtr net, static struct network_driver *driverState = NULL; -static char * +char * networkDnsmasqLeaseFileNameDefault(const char *netname) { char *leasefile; diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 50258b5..40e3990 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -49,6 +49,8 @@ int networkDnsmasqConfContents(virNetworkObjPtr network, char **configstr, dnsmasqContext *dctx, dnsmasqCapsPtr caps); +char * networkDnsmasqLeaseFileNameDefault(const char *netname) +ATTRIBUTE_NONNULL(1); # else /* Define no-op replacements that don't drag in any link dependencies. */ # define networkAllocateActualDevice(iface) 0 @@ -57,6 +59,7 @@ int networkDnsmasqConfContents(virNetworkObjPtr network, # define networkGetNetworkAddress(netname, netaddr) (-2) # define networkDnsmasqConfContents(network, pidfile, configstr, \ dctx, caps) 0 +# define networkDnsmasqLeaseFileNameDefault(netname) 0 # endif typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname); Similar hack has been used so that networkAllocateActualDevice() can be called from qemu_command.c. Although the above method works, we want to have a formal API and not leave things like a hack. /* * @conn: connection object * @params: array to populate on output * @nparams: number of parameters that will be filled * @flags: not supported, user should pass 0 for now * return 0 on success -1 otherwise * Valid parameter field names: * VIR_NETWORK_CONFIG_DIR, VIR_NETWORK_AUTOSTART_DIR, VIR_STATE_DIR, * VIR_PID_DIR, VIR_DNSMASQ_STATE_DIR, VIR_RADVD_STATE_DIR * All the above will of the type VIR_TYPED_PARAM_STRING */ int virNetworkGetConfigFileName(virConnectPtr conn, virTypedParameterPtr params, int nparams, unsigned int flags) Nehal J. Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] RFC: Introduce API to return configuration/state paths of the network driver
On Wed, Aug 14, 2013 at 4:29 AM, Eric Blake ebl...@redhat.com wrote: On 08/13/2013 04:48 PM, Eric Blake wrote: virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, unsigned char *macaddr, I personally think the public API should stick to stringized representations. Yes, it's less friendly to machine code, but internally, our src/util/virmacaddr.h helps transfer between stringized and binary. Furthermore, we already have other API that operates on stringized versions, but none that operates on raw (see virDomainSetInterfaceParameters). Knowing what representation we are targetting impacts how this API will look. For comparison, look at the API for virDomainLookupByUUID (takes a raw uuid - fixed number of bytes, unsigned char* argument) vs. virDomainLookupByUUIDString (takes a stringized uuid, char* argument). If efficiency were a concern, then I'd propose that we have two API: virNetworkGetDHCPLeaseForMAC(virNetworkPtr network, unsigned char *macaddr, ...) virNetworkGetDHCPLeaseForMACString(virNetworkPtr network, char *macaddr, ...) But I don't think efficiency is a concern, and rather than add a new API that has to have dual forms, I'd rather stick with the shorter name but using the stringized form of MAC. -- Eric Blake eblake redhat com+1-919-301-3266 Libvirt virtualization library http://libvirt.org I would like to see the API as: /** * virNetworkGetDHCPLeases: * @network: pointer to network object * @macaddr: MAC Address of an interface * @leases: pointer to an array of structs which will hold the leases * @nleases: number of leases in output * @flags: extra flags, not used yet, so callers should always pass 0 * * The API returns the leases of all interfaces by default, and if * @macaddr is specified,.only the lease of the interface which * matches the @macaddr is returned. * * Returns number of leases on success, -1 otherwise */ int virNetworkGetDHCPLeases(virNetworkPtr network, const char *macaddr, virNetworkDHCPLeasesPtr *leases, int *nleases, unsigned int flags); Structs to be used: /*In include/libvirt/libvirt.h.in */ struct _virNetworkDHCPLeases { long long expirytime; char *macaddr; char *ipaddr; char *hostname; char *clientid; }; /*In src/remote/remote_protocol.x*/ struct remote_network_dhcp_leases { hyper expirytime; remote_nonnull_string macaddr; remote_nonnull_string ipaddr; remote_nonnull_string hostname; remote_nonnull_string clientid; }; struct remote_network_get_dhcp_leases_args { remote_nonnull_network net; remote_string macaddr; unsigned int flags; }; struct remote_network_get_dhcp_leases_ret { remote_network_dhcp_leases leases; }; The following two blocks are required more than one, so should we be introducing helper functions for them? if ((VIR_STRDUP((*leases)[0].macaddr, leaseparams[1]) 0) || (VIR_STRDUP((*leases)[0].ipaddr, leaseparams[2]) 0) || (VIR_STRDUP((*leases)[0].hostname, leaseparams[3]) 0) || (VIR_STRDUP((*leases)[0].clientid, leaseparams[4]) 0)) goto cleanup; for (i = 0; i nleases; i++) { VIR_FREE(leases[i].macaddr); VIR_FREE(leases[i].ipaddr); VIR_FREE(leases[i].hostname); VIR_FREE(leases[i].clientid); } -- Nehal J. Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv3 3/5] domifaddr: Implement the API for qemu
, /* 1.1.2 */ .nodeGetMemoryStats = qemuNodeGetMemoryStats, /* 0.9.3 */ .nodeGetCellsFreeMemory = qemuNodeGetCellsFreeMemory, /* 0.4.4 */ .nodeGetFreeMemory = qemuNodeGetFreeMemory, /* 0.4.4 */ diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 4e27981..6b6c47f 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -31,6 +31,8 @@ #define VIR_FROM_THIS VIR_FROM_NONE + + static int testQemuAgentFSFreeze(const void *data) { @@ -271,6 +273,7 @@ cleanup: } + static int testQemuAgentShutdown(const void *data) { @@ -496,7 +499,7 @@ testQemuAgentArbitraryCommand(const void *data) goto cleanup; if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test), - {\execute\:\ble\}, + {\execute\:\ble\}, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0) goto cleanup; @@ -576,6 +579,90 @@ cleanup: return ret; } +static const char testQemuAgentGetInterfacesResponse[] = +{\return\: +[ + {\name\:\lo\, +\ip-addresses\: + [ + {\ip-address-type\:\ipv4\, + \ip-address\:\127.0.0.1\, + \prefix\:8 + }, + {\ip-address-type\:\ipv6\, + \ip-address\:\::1\, + \prefix\:128 + } + ], +\hardware-address\:\00:00:00:00:00:00\ + }, + {\name\:\eth0\, +\ip-addresses\: + [ + {\ip-address-type\:\ipv4\, + \ip-address\:\192.168.102.142\, + \prefix\:24 + }, + {\ip-address-type\:\ipv6\, + \ip-address\:\fe80::5054:ff:fe89:ad35\, + \prefix\:64 + } + ], +\hardware-address\:\52:54:00:89:ad:35\ + }, + {\name\:\eth1\, +\ip-addresses\: + [ + {\ip-address-type\:\ipv4\, + \ip-address\:\192.168.103.83\, + \prefix\:24 + }, + {\ip-address-type\:\ipv6\, + \ip-address\:\fe80::5054:ff:fed3:39ee\, + \prefix\:64 + } + ], +\hardware-address\:\52:54:00:d3:39:ee\ + } +] +}; + +static int +testQemuAgentGetInterfaces(const void *data) +{ +virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; +qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt); +int ret = -1; +int ifaces_count = 0; +virDomainInterfacePtr *ifaces; + +if (!test) +return -1; + +if (qemuMonitorTestAddAgentSyncResponse(test) 0) +goto cleanup; + +if (qemuMonitorTestAddItem(test, guest-network-get-interfaces, + testQemuAgentGetInterfacesResponse) 0) +goto cleanup; + +if ((ifaces_count = qemuAgentGetInterfaces(qemuMonitorTestGetAgent(test), + ifaces)) 0) { +goto cleanup; +} + +if (ifaces_count != 3) { +virReportError(VIR_ERR_INTERNAL_ERROR, + expected 3 interfaces, got %d, ret); +goto cleanup; +} + +ret = 0; + +cleanup: +qemuMonitorTestFree(test); +return ret; +} static int mymain(void) @@ -605,6 +692,7 @@ mymain(void) DO_TEST(Shutdown); DO_TEST(CPU); DO_TEST(ArbitraryCommand); +DO_TEST(GetInterfaces); DO_TEST(Timeout); /* Timeout should always be called last */ -- 1.7.11.7 -- Nehal J. Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv3 4/5] domifaddr: Add virsh support
be driver dependent, it can be +the name within guest OS or the name you would see in domain XML. +Moreover, the whole command may require a guest agent to be configured +for the queried domain under some drivers, notably qemu. + =item Bdomifstat Idomain Iinterface-device Get network interface stats for a running domain. -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list -- Doug Goldstein The leases method will be applied to this API when virNetworkGetDHCPLeases() API is accepted, which is the next step after this. Refer: http://www.redhat.com/archives/libvir-list/2013-July/msg01603.html and its followups. The output from the virNetworkGetDHCPLeases will be something of this kind: virsh # net-dhcp-leases default Virtual Network Expiry Time MAC address IP address Hostname ClientId default 16-08-2013 03:53:11 52:54:00:89:4e:97 192.168.101.130 f18 * default 16-08-2013 03:45:20 52:54:00:fe:4c:4f 192.168.101.197 ** -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv3 4/5] domifaddr: Add virsh support
On Sat, Aug 24, 2013 at 6:46 AM, Doug Goldstein car...@gentoo.org wrote: On Fri, Aug 23, 2013 at 10:45 AM, Nehal J Wani nehaljw.k...@gmail.com wrote: On Fri, Aug 23, 2013 at 8:16 PM, Doug Goldstein car...@gentoo.org wrote: On Thu, Aug 22, 2013 at 5:18 PM, nehaljwani nehaljw.k...@gmail.com wrote: Use virDomainInterfacesAddresses in virsh tools/virsh-domain-monitor.c * Introduce new command : domifaddr virsh # domifaddr f18 Name MAC address IP address --- lo 00:00:00:00:00:00127.0.0.1/8 ::1/128 eth0 52:54:00:89:ad:35 192.168.102.142/24fe80::5054:ff:fe89:ad35/64 eth1 52:54:00:d3:39:ee 192.168.103.183/24fe80::5054:ff:fed3:39ee/64 eth2 52:54:00:fe:4c:4f 192.168.101.197/24fe80::5054:ff:fefe:4c4f/64 eth3 52:54:00:89:4e:97 192.168.101.130/24fe80::5054:ff:fe89:4e97/64 Not a review, but a question. How does this work with IP aliases? Will it show all the aliases 1 per line or just show the primary address? tools/virsh.pod * Document new command --- tools/virsh-domain-monitor.c | 99 tools/virsh.pod | 10 + 2 files changed, 109 insertions(+) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b29b82a..91efa71 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1871,6 +1871,99 @@ cleanup: } #undef FILTER +/* domifaddr command + */ +static const vshCmdInfo info_domifaddr[] = { +{help, N_(Get network interfaces' addresses for a running domain)}, +{desc, N_(Get network interfaces' addresses for a running domain)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_domifaddr[] = { +{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)}, +{interface, VSH_OT_DATA, VSH_OFLAG_NONE, N_(network interface name)}, +{NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) +{ +virDomainPtr dom = NULL; +const char *interface = NULL; +virDomainInterfacePtr *ifaces = NULL; +size_t i, j; +int ifaces_count = 0; +unsigned int flags = 0; +bool ret = false; + +if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) +return false; + +if (vshCommandOptString(cmd, interface, interface) 0) { +goto cleanup; +} + +if ((ifaces_count = virDomainInterfacesAddresses(dom, ifaces, flags)) 0) { +vshError(ctl, _(Failed to query for interfaces addresses)); +goto cleanup; +} + +vshPrintExtra(ctl, %-10s %-17s%s\n%s\n, + _(Name), _(MAC address), _(IP address), + ---); + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +virBuffer buf = VIR_BUFFER_INITIALIZER; +const char *hwaddr = ; +const char *ip_addr_str = NULL; + +if (interface STRNEQ(interface, iface-name)) { +virBufferFreeAndReset(buf); +continue; +} + +if (iface-hwaddr) +hwaddr = iface-hwaddr; + +for (j = 0; j iface-naddrs; j++) { +if (j) +virBufferAddChar(buf, ' '); +virBufferAsprintf(buf, %s/%d, + iface-addrs[j].addr, + iface-addrs[j].prefix); +} + +if (virBufferError(buf)) { +virBufferFreeAndReset(buf); +virReportOOMError(); +return ret; +} + +ip_addr_str = virBufferContentAndReset(buf); + +if (!ip_addr_str) +ip_addr_str = ; + +vshPrintExtra(ctl, %-10s %-17s%s\n, + iface-name, hwaddr, ip_addr_str); + +virBufferFreeAndReset(buf); +} + +ret = true; + +cleanup: +for (i = 0; i ifaces_count; i++) { +if (ifaces[i]) +virDomainInterfaceFree(ifaces[i]); +} +VIR_FREE(ifaces); + +virDomainFree(dom); +return ret; +} + const vshCmdDef domMonitoringCmds[] = { {.name = domblkerror, .handler = cmdDomBlkError, @@ -1944,5 +2037,11 @@ const vshCmdDef domMonitoringCmds[] = { .info = info_list, .flags = 0 }, +{.name = domifaddr, + .handler = cmdDomIfAddr, + .opts = opts_domifaddr, + .info = info_domifaddr, + .flags = 0 +}, {.name = NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 0ae5178..008ffea 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -636,6 +636,16 @@ BExplanation of fields (fields appear in the following order): flush_total_times - total
[libvirt] [PATCHv4 2/5] domifaddr: Implement the remote protocol
Implement RPC calls for virDomainInterfacesAddresses daemon/remote.c * Define remoteSerializeDomainInterfacePtr, remoteDispatchDomainInterfacesAddresses src/remote/remote_driver.c * Define remoteDomainInterfacesAddresses src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_DOMAIN_INTERFACES_ADDRESSES * Define structs remote_domain_ip_addr, remote_domain_interface, remote_domain_interfaces_addresses_args, remote_domain_interfaces_addresses_ret src/remote_protocol-structs * New structs added --- daemon/remote.c | 127 +++ src/remote/remote_driver.c | 85 + src/remote/remote_protocol.x | 41 +- src/remote_protocol-structs | 24 4 files changed, 276 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 03d5557..44d7ff2 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5025,7 +5025,134 @@ cleanup: return rv; } +static int +remoteSerializeDomainInterfacePtr(virDomainInterfacePtr *ifaces, + unsigned int ifaces_count, + remote_domain_interfaces_addresses_ret *ret) +{ +size_t i, j; + +if (ifaces_count REMOTE_DOMAIN_INTERFACE_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(Number of interfaces exceeds max limit!)); +return -1; +} + +if (VIR_ALLOC_N(ret-ifaces.ifaces_val, ifaces_count) 0) +return -1; + +ret-ifaces.ifaces_len = ifaces_count; + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); +if ((VIR_STRDUP(iface_ret-name, iface-name)) 0) +goto cleanup; + +if (iface-hwaddr) { +char **hwaddr_p = NULL; +if (VIR_ALLOC(hwaddr_p) 0) +goto cleanup; +if (VIR_STRDUP(*hwaddr_p, iface-hwaddr) 0) { +VIR_FREE(hwaddr_p); +goto cleanup; +} + +iface_ret-hwaddr = hwaddr_p; +} + +if (iface-naddrs REMOTE_DOMAIN_IP_ADDR_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(Number of IP addresses exceeds max limit!)); +goto cleanup; +} + +if (VIR_ALLOC_N(iface_ret-addrs.addrs_val, +iface-naddrs) 0) +goto cleanup; + +iface_ret-addrs.addrs_len = iface-naddrs; + +for (j = 0; j iface-naddrs; j++) { +virDomainIPAddressPtr ip_addr = (iface-addrs[j]); +remote_domain_ip_addr *ip_addr_ret = +(iface_ret-addrs.addrs_val[j]); + +if (VIR_STRDUP(ip_addr_ret-addr, ip_addr-addr) 0) +goto cleanup; + +ip_addr_ret-prefix = ip_addr-prefix; +ip_addr_ret-type = ip_addr-type; +} +} + +return 0; + +cleanup: +if (ret-ifaces.ifaces_val) { +for (i = 0; i ifaces_count; i++) { +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); +VIR_FREE(iface_ret-name); +VIR_FREE(iface_ret-hwaddr); +for (j = 0; j iface_ret-addrs.addrs_len; j++) { +remote_domain_ip_addr *ip_addr = +(iface_ret-addrs.addrs_val[j]); +VIR_FREE(ip_addr-addr); +} +VIR_FREE(iface_ret); +} +VIR_FREE(ret-ifaces.ifaces_val); +} + +return -1; +} + +static int +remoteDispatchDomainInterfacesAddresses( +virNetServerPtr server ATTRIBUTE_UNUSED, +virNetServerClientPtr client, +virNetMessagePtr msg ATTRIBUTE_UNUSED, +virNetMessageErrorPtr rerr, +remote_domain_interfaces_addresses_args *args, +remote_domain_interfaces_addresses_ret *ret) +{ +int rv = -1; +virDomainPtr dom = NULL; +virDomainInterfacePtr *ifaces = NULL; +int ifaces_count = 0; +struct daemonClientPrivate *priv = +virNetServerClientGetPrivateData(client); + +if (!priv-conn) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open)); +goto cleanup; +} + +if (!(dom = get_nonnull_domain(priv-conn, args-dom))) +goto cleanup; + +if ((ifaces_count = virDomainInterfacesAddresses(dom, ifaces, args-flags)) 0) +goto cleanup; + +if (remoteSerializeDomainInterfacePtr(ifaces, ifaces_count, ret) 0) +goto cleanup; + +rv = 0; + +cleanup: +if (rv 0) +virNetMessageSaveError(rerr); +if (dom) +virDomainFree(dom); +if (ifaces) { +size_t i; +for (i = 0; i ifaces_count; i++) +virDomainInterfaceFree(ifaces[i]); +VIR_FREE(ifaces); +} +return rv; +} /*- Helpers. -*/ diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 71d0034..94eb63d 100644 ---
[libvirt] [PATCHv4 0/5] Introduce API to query IP addresses for given domain
This feature has been requested for a very long time. Since qemu guest agent gives us reliable results, now the wait is over. The RFC was first proposed by Michal Privoznik: http://www.mail-archive.com/libvir-list@redhat.com/msg51857.html A patch was submitted, using structs: http://www.mail-archive.com/libvir-list@redhat.com/msg57141.html Another patch was submitted, using XML: http://www.mail-archive.com/libvir-list@redhat.com/msg57829.html Neither of the patches were accepted, probably due to lack of extensibility and usability. Hence, we thought of using virTypedParameters for reporting list of interfaces along with their MAC address and IP addresses. The RFC can be found here: http://www.mail-archive.com/libvir-list@redhat.com/msg79793.html The idea of extensibility was rejected and rendered out of scope of libvirt. Hence, we were back to structs. This API is called virDomainInterfacesAddresses which returns a dynamically allocated array of virDomainInterface struct. The great disadvantage is once this gets released, it's written in stone and we cannot change or add an item into it. The API supports two methods: * Return information (list of all associated interfaces with MAC address and IP addresses) of all of the domain interfaces by default (if no interface name is provided) * Return information for the specified interface (if an interface name is provided) Nehal J Wani (5): domifaddr: Implement the public API domifaddr: Implement the remote protocol domifaddr: Implement the API for qemu domifaddr: Add virsh support domifaddr: Expose python binding daemon/remote.c | 127 + examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 50 + include/libvirt/libvirt.h.in| 33 + python/generator.py | 3 + python/libvirt-override-api.xml | 8 ++- python/libvirt-override.c | 113 + src/driver.h| 6 ++ src/libvirt.c | 109 src/libvirt_public.syms | 6 ++ src/qemu/qemu_agent.c | 153 src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 +++ src/remote/remote_driver.c | 85 ++ src/remote/remote_protocol.x| 41 ++- src/remote_protocol-structs | 24 +++ tests/qemuagenttest.c | 113 + tools/virsh-domain-monitor.c| 101 ++ tools/virsh.pod | 10 +++ 20 files changed, 1040 insertions(+), 3 deletions(-) create mode 100755 examples/python/domipaddrs.py -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv4 5/5] domifaddr: Expose python binding
Expose virDomainInterfacesAddresses to python binding examples/python/Makefile.am: * Add new file domipaddrs.py examples/python/README: * Add documentation for the python example python/libvirt-override-api.xml: * Add new symbol for virDomainInterfacesAddresses python/libvirt-override.c: * Hand written python api Example: $ ./run ./examples/python/domipaddrs.py qemu:///system f18 Interface MAC address IPv4 AddressIPv6 Address eth3:1 52:54:00:fe:4c:4f192.168.101.198/24 eth2:1 52:54:00:d3:39:ee192.168.103.185/24 eth2:0 52:54:00:d3:39:ee192.168.103.184/24 eth1:2 52:54:00:89:ad:35192.168.102.143/24 lo 00:00:00:00:00:00127.0.0.1/8 ::1/128 eth0:2 52:54:00:89:4e:97192.168.101.132/24 eth0:1 52:54:00:89:4e:97192.168.101.133/24 eth3 52:54:00:fe:4c:4f192.168.101.197/24 fe80::5054:ff:fefe:4c4f/64 eth2 52:54:00:d3:39:ee192.168.103.183/24 fe80::5054:ff:fed3:39ee/64 eth1 52:54:00:89:ad:35192.168.102.142/24 fe80::5054:ff:fe89:ad35/64 eth0 52:54:00:89:4e:97192.168.101.130/24 fe80::5054:ff:fe89:4e97/64 --- examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 49 + python/libvirt-override-api.xml | 8 ++- python/libvirt-override.c | 113 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100755 examples/python/domipaddrs.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index 2cacfa1..d33ee17 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -17,4 +17,4 @@ EXTRA_DIST=\ README \ consolecallback.py \ - dominfo.py domrestore.py domsave.py domstart.py esxlist.py + dominfo.py domrestore.py domsave.py domstart.py esxlist.py domipaddrs.py diff --git a/examples/python/README b/examples/python/README index f4db76c..1285d52 100644 --- a/examples/python/README +++ b/examples/python/README @@ -10,6 +10,7 @@ domsave.py - save all running domU's into a directory domrestore.py - restore domU's from their saved files in a directory esxlist.py - list active domains of an VMware ESX host and print some info. also demonstrates how to use the libvirt.openAuth() method +domipaddrs.py - print domain interfaces along with their MAC and IP addresses The XML files in this directory are examples of the XML format that libvirt expects, and will have to be adapted for your setup. They are only needed diff --git a/examples/python/domipaddrs.py b/examples/python/domipaddrs.py new file mode 100755 index 000..e71e8f6 --- /dev/null +++ b/examples/python/domipaddrs.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# domipaddrds - print domain interfaces along with their MAC and IP addresses + +import libvirt +import sys + +def usage(): +print Usage: %s [URI] DOMAIN % sys.argv[0] +print Print domain interfaces along with their MAC and IP addresses + +uri = None +name = None +args = len(sys.argv) + +if args == 2: +name = sys.argv[1] +elif args == 3: +uri = sys.argv[1] +name = sys.argv[2] +else: +usage() +sys.exit(2) + +conn = libvirt.openReadOnly(uri) +if conn == None: +print Unable to open connection to libvirt +sys.exit(1) + +try: +dom = conn.lookupByName(name) +except libvirt.libvirtError: +print Domain %s not found % name +sys.exit(0) + +ifaces = dom.interfacesAddresses(0) +if (ifaces == None): +print Failed to get domain interfaces +sys.exit(0) + +print {0:10} {1:20} {2:15} {3}.format(Interface, MAC address, IPv4 Address, IPv6 Address) + +for (name, val) in ifaces.iteritems(): +print {0:10} {1:17}.format(name, val['hwaddr']), + +if (val['ip_addrs'] None): +print , +for addr in val['ip_addrs']: +print {0}/{1} .format(addr['addr'], addr['prefix']), +print diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 9a88215..f5c6e83 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -602,5 +602,11 @@ arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/ arg name='flags' type='int' info='unused, pass 0'/ /function - /symbols +function name='virDomainInterfacesAddresses' file='python' + inforeturns a dictionary of domain interfaces along with their MAC and IP addresses/info + arg name='dom' type='virDomainPtr' info='pointer to the domain'/ + arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/ + return type='virDomainInterfacePtr' info=dictionary of domain interfaces along with their MAC and IP addresses/ +/function +/symbols /api diff --git
[libvirt] [PATCHv4 1/5] domifaddr: Implement the public API
Define a new API virDomainInterfacesAddresses, which returns the address information of a running domain's interfaces(s). If no interface name is specified, it returns the information of all interfaces, otherwise it only returns the information of the specificed interface. The address information includes the MAC and IP addresses. The API is going to provide multiple methods by flags, e.g. * Query guest agent * Parse lease file of dnsmasq * DHCP snooping But at this stage, it will only work with guest agent, and flags won't be supported. include/libvirt/libvirt.h.in: * Define virDomainInterfacesAddresses, virDomainInterfaceFree * Define structs virDomainInterface, virDomainIPAddress python/generator.py: * Skip the auto-generation for virDomainInterfacesAddresses and virDomainInterfaceFree src/driver.h: * Define domainInterfacesAddresses src/libvirt.c: * Implement virDomainInterfacesAddresses * Implement virDomainInterfaceFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 33 + python/generator.py | 3 ++ src/driver.h | 6 +++ src/libvirt.c| 109 +++ src/libvirt_public.syms | 6 +++ 5 files changed, 157 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..deb1e1f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2044,6 +2044,39 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags); +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 _virDomainInterfaceIPAddress virDomainIPAddress; +typedef virDomainIPAddress *virDomainIPAddressPtr; +struct _virDomainInterfaceIPAddress { +int type; /* virIPAddrType */ +char *addr; /* IP address */ +int prefix; /* IP address prefix */ +}; + +typedef struct _virDomainInterface virDomainInterface; +typedef virDomainInterface *virDomainInterfacePtr; +struct _virDomainInterface { +char *name; /* interface name */ +char *hwaddr; /* hardware address */ +unsigned int naddrs;/* number of items in @addrs */ +virDomainIPAddressPtr addrs;/* array of IP addresses */ +}; + +int virDomainInterfacesAddresses (virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +void virDomainInterfaceFree (virDomainInterfacePtr iface); + /* Management of domain block devices */ int virDomainBlockPeek (virDomainPtr dom, diff --git a/python/generator.py b/python/generator.py index fb321c6..f24561e 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_impl = ( 'virNodeGetMemoryParameters', 'virNodeSetMemoryParameters', 'virNodeGetCPUMap', +'virDomainInterfacesAddresses', 'virDomainMigrate3', 'virDomainMigrateToURI3', ) @@ -560,6 +561,8 @@ skip_function = ( virTypedParamsGetString, virTypedParamsGetUInt, virTypedParamsGetULLong, + +virDomainInterfaceFree, # Only useful in C ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..8b6182e 100644 --- a/src/driver.h +++ b/src/driver.h @@ -518,6 +518,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainInterfacesAddresses)(virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +typedef int (*virDrvDomainMemoryStats)(virDomainPtr domain, struct _virDomainMemoryStat *stats, unsigned int nr_stats, @@ -1238,6 +1243,7 @@ struct _virDriver { virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; +virDrvDomainInterfacesAddressesdomainInterfacesAddresses; virDrvDomainMemoryStats domainMemoryStats; virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..05e3a03 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -8643,6 +8643,94 @@ error: return -1; } + /** + * virDomainInterfacesAddresses: + * @dom: domain object + * @ifaces: pointer to an array of pointers pointing interface objects + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Return a pointer to the allocated array of interfaces present in given + *
[libvirt] [PATCHv4 3/5] domifaddr: Implement the API for qemu
By querying the qemu guest agent with the QMP command guest-network-get-interfaces and converting the received JSON output to structured objects. src/qemu/qemu_agent.h: * Define qemuAgentGetInterfaces src/qemu/qemu_agent.c: * Implement qemuAgentGetInterface src/qemu/qemu_driver.c: * New function qemuDomainInterfacesAddresses src/remote_protocol-sructs: * Define new structs tests/qemuagenttest.c: * Add new test: testQemuAgentGetInterfaces --- src/qemu/qemu_agent.c | 153 + src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 ++ tests/qemuagenttest.c | 113 4 files changed, 324 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 2cd0ccc..11f5467 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1319,6 +1319,159 @@ cleanup: return ret; } + +int +qemuAgentGetInterfaces(qemuAgentPtr mon, + virDomainInterfacePtr **ifaces) +{ +int ret = -1; +size_t i, j; +int size = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +virJSONValuePtr ret_array = NULL; +int ifaces_count = 0; +virDomainInterfacePtr *ifaces_ret = NULL; + +if (!(cmd = qemuAgentMakeCommand(guest-network-get-interfaces, NULL))) + return -1; + +if (qemuAgentCommand(mon, cmd, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0 || +qemuAgentCheckError(cmd, reply) 0) { +goto cleanup; +} + +if (!(ret_array = virJSONValueObjectGet(reply, return))) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, +_(qemu agent didn't provide 'return' field)); +goto cleanup; +} + +if ((size = virJSONValueArraySize(ret_array)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, +_(qemu agent didn't return an array of interfaces)); +goto cleanup; +} + +ifaces_count = (unsigned int) size; + +if (VIR_ALLOC_N(ifaces_ret, size) 0) +goto cleanup; + +for (i = 0; i size; i++) { +virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); +virJSONValuePtr ip_addr_arr = NULL; +const char *name, *hwaddr; +int ip_addr_arr_size; + +if (VIR_ALLOC(ifaces_ret[i]) 0) +goto cleanup; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!tmp_iface) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, +_(something has went really wrong)); +goto error; +} + +/* interface name is required to be presented */ +name = virJSONValueObjectGetString(tmp_iface, name); +if (!name) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, +_(qemu agent didn't provide 'name' field)); +goto error; +} + +if (VIR_STRDUP(ifaces_ret[i]-name, name) 0) +goto error; + +/* hwaddr might be omitted */ +hwaddr = virJSONValueObjectGetString(tmp_iface, hardware-address); +if (hwaddr VIR_STRDUP(ifaces_ret[i]-hwaddr, hwaddr) 0) +goto error; + +/* as well as IP address which - moreover - + * can be presented multiple times */ +ip_addr_arr = virJSONValueObjectGet(tmp_iface, ip-addresses); +if (!ip_addr_arr) +continue; + +if ((ip_addr_arr_size = virJSONValueArraySize(ip_addr_arr)) 0) +/* Mmm, empty 'ip-address'? */ +continue; + +(*(ifaces_ret)[i]).naddrs = (unsigned int) ip_addr_arr_size; + +if (VIR_ALLOC_N((*(ifaces_ret)[i]).addrs, ip_addr_arr_size) 0) +goto error; + +for (j = 0; j ip_addr_arr_size; j++) { +virJSONValuePtr ip_addr_obj = virJSONValueArrayGet(ip_addr_arr, j); +virDomainIPAddressPtr ip_addr = ifaces_ret[i]-addrs[j]; +const char *type, *addr; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!ip_addr_obj) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, +_(something has went really wrong)); +goto error; +} + +type = virJSONValueObjectGetString(ip_addr_obj, ip-address-type); +if (!type) { +virReportError(VIR_ERR_INTERNAL_ERROR, +_(qemu agent didn't provide 'ip-address-type' + field for interface '%s'), name); +goto error; +} else if (STREQ(type, ipv4)) { +ip_addr-type = VIR_IP_ADDR_TYPE_IPV4; +} else if (STREQ(type, ipv6)) { +ip_addr-type = VIR_IP_ADDR_TYPE_IPV6; +} else { +virReportError(VIR_ERR_INTERNAL_ERROR, +_(unknown ip address type '%s'), +
[libvirt] [PATCHv4 4/5] domifaddr: Add virsh support
Use virDomainInterfacesAddresses in virsh tools/virsh-domain-monitor.c * Introduce new command : domifaddr virsh # domifaddr f18 Name MAC address IPv4 addressIPv6 address --- lo 00:00:00:00:00:00127.0.0.1/8 ::1/128 eth0 52:54:00:89:4e:97192.168.101.130/24 fe80::5054:ff:fe89:4e97/64 eth0:1 52:54:00:89:4e:97192.168.101.133/24 eth0:2 52:54:00:89:4e:97192.168.101.132/24 eth1 52:54:00:89:ad:35192.168.102.142/24 fe80::5054:ff:fe89:ad35/64 eth1:1 52:54:00:89:ad:35192.168.102.143/24 eth2 52:54:00:d3:39:ee192.168.103.183/24 fe80::5054:ff:fed3:39ee/64 eth2:0 52:54:00:d3:39:ee192.168.103.184/24 eth2:1 52:54:00:d3:39:ee192.168.103.185/24 eth3 52:54:00:fe:4c:4f192.168.101.197/24 fe80::5054:ff:fefe:4c4f/64 eth3:1 52:54:00:fe:4c:4f192.168.101.198/24 tools/virsh.pod * Document new command --- tools/virsh-domain-monitor.c | 101 +++ tools/virsh.pod | 10 + 2 files changed, 111 insertions(+) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b29b82a..040b0e4 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1871,6 +1871,101 @@ cleanup: } #undef FILTER +/* domifaddr command + */ +static const vshCmdInfo info_domifaddr[] = { +{help, N_(Get network interfaces' addresses for a running domain)}, +{desc, N_(Get network interfaces' addresses for a running domain)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_domifaddr[] = { +{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)}, +{interface, VSH_OT_DATA, VSH_OFLAG_NONE, N_(network interface name)}, +{NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) +{ +virDomainPtr dom = NULL; +const char *interface = NULL; +virDomainInterfacePtr *ifaces = NULL; +size_t i, j; +int ifaces_count = 0; +unsigned int flags = 0; +bool ret = false; + +if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) +return false; + +if (vshCommandOptString(cmd, interface, interface) 0) { +goto cleanup; +} + +if ((ifaces_count = virDomainInterfacesAddresses(dom, ifaces, flags)) 0) { +vshError(ctl, _(Failed to query for interfaces addresses)); +goto cleanup; +} + +vshPrintExtra(ctl, %-10s %-20s %-15s %s\n%s%s\n, _(Name), + _(MAC address), _(IPv4 address), _(IPv6 address), + _(-), + _(--)); + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +virBuffer buf = VIR_BUFFER_INITIALIZER; +const char *hwaddr = ; +const char *ip_addr_str = NULL; + +if (interface STRNEQ(interface, iface-name)) { +virBufferFreeAndReset(buf); +continue; +} + +if (iface-hwaddr) +hwaddr = iface-hwaddr; + +for (j = 0; j iface-naddrs; j++) { +if (j) +virBufferAsprintf(buf, %25s/%d, + iface-addrs[j].addr, + iface-addrs[j].prefix); +else +virBufferAsprintf(buf, %s/%d, + iface-addrs[j].addr, + iface-addrs[j].prefix); +} + +if (virBufferError(buf)) { +virBufferFreeAndReset(buf); +virReportOOMError(); +return ret; +} + +ip_addr_str = virBufferContentAndReset(buf); + +if (!ip_addr_str) +ip_addr_str = ; + +vshPrintExtra(ctl, %-10s %-17s%s\n, + iface-name, hwaddr, ip_addr_str); + +virBufferFreeAndReset(buf); +} + +ret = true; + +cleanup: +for (i = 0; i ifaces_count; i++) +virDomainInterfaceFree(ifaces[i]); +VIR_FREE(ifaces); + +virDomainFree(dom); +return ret; +} + const vshCmdDef domMonitoringCmds[] = { {.name = domblkerror, .handler = cmdDomBlkError, @@ -1944,5 +2039,11 @@ const vshCmdDef domMonitoringCmds[] = { .info = info_list, .flags = 0 }, +{.name = domifaddr, + .handler = cmdDomIfAddr, + .opts = opts_domifaddr, + .info = info_domifaddr, + .flags = 0 +}, {.name = NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 0ae5178..008ffea 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -636,6 +636,16 @@ BExplanation of fields (fields appear in the following order): flush_total_times - total time flush operations took (ns) -- other fields provided by hypervisor -- + +=item Bdomifaddr Idomain [Iinterface] +
Re: [libvirt] [PATCHv4 1/5] domifaddr: Implement the public API
On Tue, Aug 27, 2013 at 6:06 PM, Daniel P. Berrange berra...@redhat.com wrote: On Sun, Aug 25, 2013 at 04:45:41AM +0530, Nehal J Wani wrote: diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..deb1e1f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2044,6 +2044,39 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags); +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 _virDomainInterfaceIPAddress virDomainIPAddress; +typedef virDomainIPAddress *virDomainIPAddressPtr; +struct _virDomainInterfaceIPAddress { +int type; /* virIPAddrType */ +char *addr; /* IP address */ +int prefix; /* IP address prefix */ +}; s/int/unsigned int/ since there's no reason for prefix to ever be negative. + +typedef struct _virDomainInterface virDomainInterface; +typedef virDomainInterface *virDomainInterfacePtr; +struct _virDomainInterface { +char *name; /* interface name */ +char *hwaddr; /* hardware address */ +unsigned int naddrs;/* number of items in @addrs */ +virDomainIPAddressPtr addrs;/* array of IP addresses */ +}; + +int virDomainInterfacesAddresses (virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); Don't put a space between the function name opening bracket. The double pluralization reads oddly to me. I'd suggest we just name this 'virDomainInterfaceAddresses' ie remove the 's' from Interfaces here, and in all similarly named functions in this series. The double pluralization was chosen because there are multiple IP Addresses per interface and there are multiple interfaces. If we choose to use 'virDomainInterfaceAddresses', then it would look as if this function will report all the IP Addresses related to a single Interface only. + +void virDomainInterfaceFree (virDomainInterfacePtr iface); Likewise. diff --git a/src/driver.h b/src/driver.h index be64333..8b6182e 100644 --- a/src/driver.h +++ b/src/driver.h @@ -518,6 +518,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainInterfacesAddresses)(virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +typedef int (*virDrvDomainMemoryStats)(virDomainPtr domain, struct _virDomainMemoryStat *stats, unsigned int nr_stats, @@ -1238,6 +1243,7 @@ struct _virDriver { virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; +virDrvDomainInterfacesAddressesdomainInterfacesAddresses; virDrvDomainMemoryStats domainMemoryStats; virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..05e3a03 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -8643,6 +8643,94 @@ error: return -1; } + /** + * virDomainInterfacesAddresses: + * @dom: domain object + * @ifaces: pointer to an array of pointers pointing interface objects + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Return a pointer to the allocated array of interfaces present in given + * domain along with their IP and MAC addresses. Note that single interface + * can have multiple or even 0 IP address. + * + * This API dynamically allocates the virDomainInterfacePtr struct based + * on how many interfaces domain @dom has, usually there's 1:1 correlation. + * The count of the interfaces is returned as the return value. + * + * Note that for some hypervisors, a configured guest agent is needed + * for successful return from this API. Moreover, if guest agent is + * used then the interface name is the one seen by guest OS. To match + * such interface with the one from @dom XML use MAC address or IP range. + * + * @ifaces-name is never NULL, @ifaces-hwaddr might be NULL. + * + * The caller *must* free @ifaces when no longer needed. Usual use + * case looks like this: + * + * virDomainInterfacePtr *ifaces = NULL; + * int ifaces_count = 0; + * size_t i, j; + * virDomainPtr dom = ... obtain a domain here ...; + * + * if ((ifaces_count = virDomainInterfacesAddresses(dom, ifaces, 0)) 0) + * goto cleanup; + * + * ... do something with returned values
Re: [libvirt] [PATCHv4 4/5] domifaddr: Add virsh support
On Tue, Aug 27, 2013 at 6:20 PM, Daniel P. Berrange berra...@redhat.com wrote: On Sun, Aug 25, 2013 at 04:45:44AM +0530, Nehal J Wani wrote: Use virDomainInterfacesAddresses in virsh tools/virsh-domain-monitor.c * Introduce new command : domifaddr virsh # domifaddr f18 Name MAC address IPv4 addressIPv6 address --- lo 00:00:00:00:00:00127.0.0.1/8 ::1/128 eth0 52:54:00:89:4e:97192.168.101.130/24 fe80::5054:ff:fe89:4e97/64 eth0:1 52:54:00:89:4e:97192.168.101.133/24 eth0:2 52:54:00:89:4e:97192.168.101.132/24 eth1 52:54:00:89:ad:35192.168.102.142/24 fe80::5054:ff:fe89:ad35/64 eth1:1 52:54:00:89:ad:35192.168.102.143/24 eth2 52:54:00:d3:39:ee192.168.103.183/24 fe80::5054:ff:fed3:39ee/64 eth2:0 52:54:00:d3:39:ee192.168.103.184/24 eth2:1 52:54:00:d3:39:ee192.168.103.185/24 eth3 52:54:00:fe:4c:4f192.168.101.197/24 fe80::5054:ff:fefe:4c4f/64 eth3:1 52:54:00:fe:4c:4f192.168.101.198/24 This formatting of IP addrs is broken. We should not expose interface aliases 'eth0:1', 'eth0:2', etc. If QEMU agent is returning such names, either we should fix the agent, or strip the :1 suffixes in libvirt. The aliased names are an artifact of the legacy linux IP config tools. The new 'ip' command does not use these - it just shows 'eth0' with multiple IPv4 and multiple IPv6 addresses, which is also how libvirt/netcf report physical device names config. Our display format must allow for NICs having arbitrarily many addresses of either type, so displaying IPv4/IPv6 side by side will not work. I think we need a display format like: virsh domifaddr f18 Name MAC address Protocol Address --- lo 00:00:00:00:00:00ipv4 127.0.0.1/8 - -ipv6 ::1/128 eth0 52:54:00:89:4e:97ipv4 192.168.101.130/24 - -ipv4 192.168.101.133/24 - -ipv4 192.168.101.132/24 - -ipv6 fe80::5054:ff:fe89:4e97/64 eth1 52:54:00:89:ad:35ipv4 192.168.102.142/24 - -ipv4 192.168.102.143/24 - -ipv6 fe80::5054:ff:fe89:ad35/64 With option to fully display all fields to make life easier for scripts: virsh domifaddr --full f18 Name MAC address Protocol Address --- lo 00:00:00:00:00:00ipv4 127.0.0.1/8 lo 00:00:00:00:00:00ipv6 ::1/128 eth0 52:54:00:89:4e:97ipv4 192.168.101.130/24 eth0 52:54:00:89:4e:97ipv4 192.168.101.133/24 eth0 52:54:00:89:4e:97ipv4 192.168.101.132/24 eth0 52:54:00:89:4e:97ipv6 fe80::5054:ff:fe89:4e97/64 eth1 52:54:00:89:ad:35ipv4 192.168.102.142/24 eth1 52:54:00:89:ad:35ipv4 192.168.102.143/24 eth1 52:54:00:89:ad:35ipv6 fe80::5054:ff:fe89:ad35/64 + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +virBuffer buf = VIR_BUFFER_INITIALIZER; +const char *hwaddr = ; +const char *ip_addr_str = NULL; + +if (interface STRNEQ(interface, iface-name)) { +virBufferFreeAndReset(buf); +continue; +} + +if (iface-hwaddr) +hwaddr = iface-hwaddr; + +for (j = 0; j iface-naddrs; j++) { +if (j) +virBufferAsprintf(buf, %25s/%d, + iface-addrs[j].addr, + iface-addrs[j].prefix); +else +virBufferAsprintf(buf, %s/%d, + iface-addrs[j].addr, + iface-addrs[j].prefix); This logic is very broken not allowing for multiple addrs per device +} + +if (virBufferError(buf)) { +virBufferFreeAndReset(buf); +virReportOOMError(); +return ret; +} + +ip_addr_str = virBufferContentAndReset(buf); + +if (!ip_addr_str) +ip_addr_str = ; + +vshPrintExtra(ctl, %-10s %-17s%s\n, + iface-name, hwaddr, ip_addr_str); + +virBufferFreeAndReset(buf); +} + +ret = true; + +cleanup: +for (i = 0; i ifaces_count; i++) +virDomainInterfaceFree(ifaces[i]); +VIR_FREE(ifaces
Re: [libvirt] [PATCHv4 4/5] domifaddr: Add virsh support
So, qemu-ga doesn't understand that there can't be more than one device with same MAC addr. So, I think we are left with the following options: Actually that's wrong. You *can* have 2 completely different physical NICs with the same MAC address. (i) Modify qemu-guest-agent to return addresses belonging to same MAC address grouped under one interface only. You would not want to group based on MAC address - you explicitly just want to normalize by stripping the legacy aliases suffixes. Actually, the order in which the qemu-agent returns the value isn't always: ethX ethX:0 ethX:1 ethY ethY:0 ethY:2 It can be: ethX ethY:2 ethX:0 ethY:0 ethX:1 ethY which, after stripping, will just be left with: ethX ethY ethX ethY ethX ethY whereas, we would want: ethX ethX ethX ethY ethY ethY Hence, grouping either by the stripped down interface name or by the MAC address will be required. So that all IP addresses related to a single NIC are not distributed in the output. OR (ii) Let the reply be as it is now. Strip the :0, :1 from the response of guest agent (Is this really necessary?) . We'll have to parse the JSON multiple times and fill the virDomainInterface structs by grouping them according to the MAC addresses. I think we need to do (ii) regardless to cope with existing deployed QEMU agent versions. We should also recommend to QEMU developers to fix the agent to not expose these legacy device alias names. 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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 2/5] domifaddr: Implement the remote protocol
s/ip/IP/, + */ +const REMOTE_DOMAIN_IP_ADDR_MAX = 16; hm, are these 2 limits too small? I don't believe one host could only have up to 32 interfaces. Any evidence for you to descrease them in new series? Osier Since there is no theoretical limit on the number of interfaces that a physical or virtual machine can have, I would suggest making REMOTE_DOMAIN_INTERFACE_MAX = 2048 and REMOTE_DOMAIN_IP_ADDR_MAX = 2048 Earlier there used to be limitation defined in /usr/include/li nux/net_alias.h: #define NET_ALIAS_MAX_SLOT 256 but then the kernel developers thought that limits suck and removed them after kernel 2.0. I have tested creating multiple ipv4 aliases on the same interface and was able to achieve the count of 1010 without any warnings/errors. -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv5 1/5] domifaddr: Implement the public APIs
Define a new API virDomainInterfaceAddresses, which returns the address information of a running domain's interfaces(s). If no interface name is specified, it returns the information of all interfaces, otherwise it only returns the information of the specificed interface. The address information includes the MAC and IP addresses. Define helper function virDomainInterfaceFree, which allows the upper layer application to free the domain interface object conveniently. The API is going to provide multiple methods by flags, e.g. * Query guest agent * Parse lease file of dnsmasq * DHCP snooping But at this stage, it will only work with guest agent, and flags won't be supported. include/libvirt/libvirt.h.in: * Define virDomainInterfaceAddresses, virDomainInterfaceFree * Define structs virDomainInterface, virDomainIPAddress python/generator.py: * Skip the auto-generation for virDomainInterfaceAddresses and virDomainInterfaceFree src/driver.h: * Define domainInterfaceAddresses src/libvirt.c: * Implement virDomainInterfaceAddresses * Implement virDomainInterfaceFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 32 python/generator.py | 3 ++ src/driver.h | 6 +++ src/libvirt.c| 115 +++ src/libvirt_public.syms | 6 +++ 5 files changed, 162 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..1a34d02 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2044,6 +2044,38 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags); +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 _virDomainInterfaceIPAddress virDomainIPAddress; +typedef virDomainIPAddress *virDomainIPAddressPtr; +struct _virDomainInterfaceIPAddress { +int type;/* virIPAddrType */ +char *addr; /* IP address */ +unsigned int prefix; /* IP address prefix */ +}; + +typedef struct _virDomainInterface virDomainInterface; +typedef virDomainInterface *virDomainInterfacePtr; +struct _virDomainInterface { +char *name; /* interface name */ +char *hwaddr; /* hardware address */ +unsigned int naddrs;/* number of items in @addrs */ +virDomainIPAddressPtr addrs;/* array of IP addresses */ +}; + +int virDomainInterfaceAddresses(virDomainPtr dom, +virDomainInterfacePtr **ifaces, +unsigned int flags); + +void virDomainInterfaceFree(virDomainInterfacePtr iface); + /* Management of domain block devices */ int virDomainBlockPeek (virDomainPtr dom, diff --git a/python/generator.py b/python/generator.py index fb321c6..50f779b 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_impl = ( 'virNodeGetMemoryParameters', 'virNodeSetMemoryParameters', 'virNodeGetCPUMap', +'virDomainInterfaceAddresses', 'virDomainMigrate3', 'virDomainMigrateToURI3', ) @@ -560,6 +561,8 @@ skip_function = ( virTypedParamsGetString, virTypedParamsGetUInt, virTypedParamsGetULLong, + +virDomainInterfaceFree, # Only useful in C ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..eb4927b 100644 --- a/src/driver.h +++ b/src/driver.h @@ -518,6 +518,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainInterfaceAddresses)(virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +typedef int (*virDrvDomainMemoryStats)(virDomainPtr domain, struct _virDomainMemoryStat *stats, unsigned int nr_stats, @@ -1238,6 +1243,7 @@ struct _virDriver { virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; +virDrvDomainInterfaceAddressesdomainInterfaceAddresses; virDrvDomainMemoryStats domainMemoryStats; virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..82c117f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -8643,6 +8643,96 @@ error: return -1; } + /** + * virDomainInterfaceAddresses: + * @dom: domain object + * @ifaces: pointer to an array of pointers pointing to interface objects + * @flags:
[libvirt] [PATCHv5 0/5] Introduce API to query IP addresses for given domain
This feature has been requested for a very long time. Since qemu guest agent gives us reliable results, now the wait is over. The RFC was first proposed by Michal Privoznik: http://www.redhat.com/archives/libvir-list/2012-February/msg00437.html A patch was submitted, using structs: https://www.redhat.com/archives/libvir-list/2012-June/msg00220.html Another patch was submitted, using XML: https://www.redhat.com/archives/libvir-list/2012-June/msg00904.html Neither of the patches were accepted, probably due to lack of extensibility and usability. Hence, we thought of using virTypedParameters for reporting list of interfaces along with their MAC address and IP addresses. The RFC can be found here: https://www.redhat.com/archives/libvir-list/2013-July/msg00084.html The idea of extensibility was rejected and rendered out of scope of libvirt. Hence, we were back to structs. This API is called virDomainInterfaceAddresses which returns a dynamically allocated array of virDomainInterface struct. The great disadvantage is once this gets released, it's written in stone and we cannot change or add an item into it. The API supports two methods: * Return information (list of all associated interfaces with MAC address and IP addresses) of all of the domain interfaces by default (if no interface name is provided) * Return information for the specified interface (if an interface name is provided) v5: * s/virDomainInterfacesAddresses/virDomainInterfaceAddresses. * Case for IP aliasing handled using virHashTable. * New test cases added, involving multiple and 0 IP addresse(s) per interface. * IP prefix changed from int to unsigned int. * Changes to practice libvirt habits. v4: * Various style nits, indentation errors, memory leaks fixed. * https://www.redhat.com/archives/libvir-list/2013-August/msg01265.html v3: * Upper bounds to number of interfaces and addresses per interface introduced. * Change from array of structs to array of pointers * ifaces_count moved from function argument to return value * Changes in variable names * Test cases added for qemuAgentGetInterfaces. * https://www.redhat.com/archives/libvir-list/2013-August/msg01215.html v2: * Logical errors, memory leaks and few other errors fixed. * https://www.redhat.com/archives/libvir-list/2013-August/msg00631.html v1: * http://www.redhat.com/archives/libvir-list/2013-July/msg01553.html Nehal J Wani (5): domifaddr: Implement the public APIs domifaddr: Implement the remote protocol domifaddr: Implement the API for qemu domifaddr: Add virsh support domifaddr: Expose python binding daemon/remote.c | 131 +++ examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 50 +++ include/libvirt/libvirt.h.in| 32 +++ python/generator.py | 3 + python/libvirt-override-api.xml | 8 +- python/libvirt-override.c | 111 +++ src/driver.h| 6 ++ src/libvirt.c | 115 src/libvirt_public.syms | 6 ++ src/qemu/qemu_agent.c | 193 src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 src/remote/remote_driver.c | 99 + src/remote/remote_protocol.x| 40 - src/remote_protocol-structs | 24 + tests/qemuagenttest.c | 149 +++ tools/virsh-domain-monitor.c| 119 + tools/virsh.pod | 11 +++ 20 files changed, 1155 insertions(+), 3 deletions(-) create mode 100755 examples/python/domipaddrs.py -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv5 2/5] domifaddr: Implement the remote protocol
daemon/remote.c * Define remoteSerializeDomainInterface, remoteDispatchDomainInterfaceAddresses src/remote/remote_driver.c * Define remoteDomainInterfaceAddresses src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_DOMAIN_INTERFACE_ADDRESSES * Define structs remote_domain_ip_addr, remote_domain_interface, remote_domain_interfaces_addresse_args, remote_domain_interface_addresses_ret * Introduce upper bounds (to handle DDoS attacks): REMOTE_DOMAIN_INTERFACE_MAX = 2048 REMOTE_DOMAIN_IP_ADDR_MAX = 2048 Restrictions on the maximum number of aliases per interface were removed after kernel v2.0, and theoretically, at present, there are no upper limits on number of interfaces per virtual machine and on the number of IP addresses per interface. src/remote_protocol-structs * New structs added --- daemon/remote.c | 131 +++ src/remote/remote_driver.c | 99 src/remote/remote_protocol.x | 40 - src/remote_protocol-structs | 24 4 files changed, 293 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 6ace7af..7091cab 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5144,7 +5144,138 @@ cleanup: return rv; } +static int +remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces, + unsigned int ifaces_count, + remote_domain_interface_addresses_ret *ret) +{ +size_t i, j; + +if (ifaces_count REMOTE_DOMAIN_INTERFACE_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of interfaces, %d exceeds the max limit: %d), + ifaces_count, REMOTE_DOMAIN_INTERFACE_MAX); +return -1; +} + +if (VIR_ALLOC_N(ret-ifaces.ifaces_val, ifaces_count) 0) +return -1; + +ret-ifaces.ifaces_len = ifaces_count; + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); + +if ((VIR_STRDUP(iface_ret-name, iface-name)) 0) +goto cleanup; + +if (iface-hwaddr) { +char **hwaddr_p = NULL; +if (VIR_ALLOC(hwaddr_p) 0) +goto cleanup; +if (VIR_STRDUP(*hwaddr_p, iface-hwaddr) 0) { +VIR_FREE(hwaddr_p); +goto cleanup; +} + +iface_ret-hwaddr = hwaddr_p; +} + +if (iface-naddrs REMOTE_DOMAIN_IP_ADDR_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of interfaces, %d exceeds the max limit: %d), + iface-naddrs, REMOTE_DOMAIN_IP_ADDR_MAX); +goto cleanup; +} + +if (VIR_ALLOC_N(iface_ret-addrs.addrs_val, +iface-naddrs) 0) +goto cleanup; + +iface_ret-addrs.addrs_len = iface-naddrs; + +for (j = 0; j iface-naddrs; j++) { +virDomainIPAddressPtr ip_addr = (iface-addrs[j]); +remote_domain_ip_addr *ip_addr_ret = +(iface_ret-addrs.addrs_val[j]); + +if (VIR_STRDUP(ip_addr_ret-addr, ip_addr-addr) 0) +goto cleanup; + +ip_addr_ret-prefix = ip_addr-prefix; +ip_addr_ret-type = ip_addr-type; +} +} + +return 0; + +cleanup: +if (ret-ifaces.ifaces_val) { +for (i = 0; i ifaces_count; i++) { +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); +VIR_FREE(iface_ret-name); +VIR_FREE(iface_ret-hwaddr); +for (j = 0; j iface_ret-addrs.addrs_len; j++) { +remote_domain_ip_addr *ip_addr = +(iface_ret-addrs.addrs_val[j]); +VIR_FREE(ip_addr-addr); +} +VIR_FREE(iface_ret); +} +VIR_FREE(ret-ifaces.ifaces_val); +} +return -1; +} + +static int +remoteDispatchDomainInterfaceAddresses( +virNetServerPtr server ATTRIBUTE_UNUSED, +virNetServerClientPtr client, +virNetMessagePtr msg ATTRIBUTE_UNUSED, +virNetMessageErrorPtr rerr, +remote_domain_interface_addresses_args *args, +remote_domain_interface_addresses_ret *ret) +{ +size_t i; +int rv = -1; +virDomainPtr dom = NULL; +virDomainInterfacePtr *ifaces = NULL; +int ifaces_count = 0; +struct daemonClientPrivate *priv = +virNetServerClientGetPrivateData(client); + +if (!priv-conn) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open)); +goto cleanup; +} + +if (!(dom = get_nonnull_domain(priv-conn, args-dom))) +goto cleanup; + +if ((ifaces_count = virDomainInterfaceAddresses(dom, ifaces, args-flags)) 0) +goto cleanup; + +if (remoteSerializeDomainInterface(ifaces, ifaces_count,
[libvirt] [PATCHv5 4/5] domifaddr: Add virsh support
Use virDomainInterfaceAddresses in virsh tools/virsh-domain-monitor.c * Introduce new command : domifaddr Usage: domifaddr domain [interface] [full] Example output: virsh # domifaddr f18 Name MAC address Protocol IP Address --- lo 00:00:00:00:00:00ipv4 127.0.0.1/8 - -ipv6 ::1/128 eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 - -ipv6 2001:db8:0:f101::2/64 - -ipv6 fe80::5054:ff:fe2e:45ce/64 eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 - -ipv4 192.168.201.195/16 - -ipv6 fe80::5054:ff:feb1:7019/64 eth2 52:54:00:36:2a:e5 tools/virsh.pod * Document new command --- tools/virsh-domain-monitor.c | 119 +++ tools/virsh.pod | 11 2 files changed, 130 insertions(+) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b29b82a..cd1df7a 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1871,6 +1871,119 @@ cleanup: } #undef FILTER +/* domifaddr command + */ +static const vshCmdInfo info_domifaddr[] = { +{help, N_(Get network interfaces' addresses for a running domain)}, +{desc, N_(Get network interfaces' addresses for a running domain)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_domifaddr[] = { +{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)}, +{interface, VSH_OT_DATA, VSH_OFLAG_NONE, N_(network interface name)}, +{full, VSH_OT_BOOL, VSH_OFLAG_NONE, N_(display full fields)}, +{NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) +{ +virDomainPtr dom = NULL; +const char *interface = NULL; +virDomainInterfacePtr *ifaces = NULL; +size_t i, j; +int ifaces_count = 0; +unsigned int flags = 0; +bool ret = false; +bool optFull = vshCommandOptBool(cmd, full); + +if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) +return false; + +if (vshCommandOptString(cmd, interface, interface) 0) { +goto cleanup; +} + +if ((ifaces_count = virDomainInterfaceAddresses(dom, ifaces, flags)) 0) { +vshError(ctl, _(Failed to query for interfaces addresses)); +goto cleanup; +} + +vshPrintExtra(ctl, %-10s %-20s %-8s %s\n%s%s\n, _(Name), + _(MAC address), _(Protocol), _(Address), + _(-), + _(--)); + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +const char *hwaddr = ; +const char *ip_addr_str = NULL; +const char *type = NULL; + +if (interface STRNEQ(interface, iface-name)) +continue; + +if (iface-hwaddr) +hwaddr = iface-hwaddr; + +/* When the interface has no IP address */ +if (!iface-naddrs) { +vshPrintExtra(ctl, %-10s %-17s\n, + iface-name, hwaddr); +} + +for (j = 0; j iface-naddrs; j++) { +virBuffer buf = VIR_BUFFER_INITIALIZER; + +switch (iface-addrs[j].type) { +case VIR_IP_ADDR_TYPE_IPV4: +type = ipv4; +break; +case VIR_IP_ADDR_TYPE_IPV6: +type = ipv6; +break; +} + +virBufferAsprintf(buf, %-12s %s/%d, + type, iface-addrs[j].addr, + iface-addrs[j].prefix); + +if (virBufferError(buf)) { +virBufferFreeAndReset(buf); +virReportOOMError(); +return ret; +} + +ip_addr_str = virBufferContentAndReset(buf); + +if (!ip_addr_str) +ip_addr_str = ; + +/* Don't repeat interface name */ +if (optFull || !j) +vshPrintExtra(ctl, %-10s %-17s%s\n, + iface-name, hwaddr, ip_addr_str); +else +vshPrintExtra(ctl, %-10s %-17s%s\n, + -,-,ip_addr_str); + +virBufferFreeAndReset(buf); +} +} + +ret = true; + +cleanup: +if (ifaces) +for (i = 0; i ifaces_count; i++) +virDomainInterfaceFree(ifaces[i]); +VIR_FREE(ifaces); + +virDomainFree(dom); +return ret; +} + const vshCmdDef domMonitoringCmds[] = { {.name = domblkerror, .handler = cmdDomBlkError, @@ -1944,5 +2057,11 @@ const vshCmdDef domMonitoringCmds[] = { .info = info_list, .flags = 0 },
[libvirt] [PATCHv5 5/5] domifaddr: Expose python binding
Expose virDomainInterfaceAddresses to python binding examples/python/Makefile.am: * Add new file domipaddrs.py examples/python/README: * Add documentation for the python example python/libvirt-override-api.xml: * Add new symbol for virDomainInterfaceAddresses python/libvirt-override.c: * Hand written python api Example: $ ./run python ./examples/python/domipaddrs.py f18 Interface MAC address Protocol Address lo 00:00:00:00:00:00ipv4 127.0.0.1/8 lo 00:00:00:00:00:00ipv6 ::1/128 eth2 52:54:00:36:2a:e5 eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 eth1 52:54:00:b1:70:19ipv4 192.168.201.195/16 eth1 52:54:00:b1:70:19ipv6 fe80::5054:ff:feb1:7019/64 eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 eth0 52:54:00:2e:45:ceipv6 2001:db8:0:f101::2/64 eth0 52:54:00:2e:45:ceipv6 fe80::5054:ff:fe2e:45ce/64 --- examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 50 ++ python/libvirt-override-api.xml | 8 ++- python/libvirt-override.c | 111 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100755 examples/python/domipaddrs.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index 2cacfa1..d33ee17 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -17,4 +17,4 @@ EXTRA_DIST=\ README \ consolecallback.py \ - dominfo.py domrestore.py domsave.py domstart.py esxlist.py + dominfo.py domrestore.py domsave.py domstart.py esxlist.py domipaddrs.py diff --git a/examples/python/README b/examples/python/README index f4db76c..1285d52 100644 --- a/examples/python/README +++ b/examples/python/README @@ -10,6 +10,7 @@ domsave.py - save all running domU's into a directory domrestore.py - restore domU's from their saved files in a directory esxlist.py - list active domains of an VMware ESX host and print some info. also demonstrates how to use the libvirt.openAuth() method +domipaddrs.py - print domain interfaces along with their MAC and IP addresses The XML files in this directory are examples of the XML format that libvirt expects, and will have to be adapted for your setup. They are only needed diff --git a/examples/python/domipaddrs.py b/examples/python/domipaddrs.py new file mode 100755 index 000..679e0bf --- /dev/null +++ b/examples/python/domipaddrs.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# domipaddrds - print domain interfaces along with their MAC and IP addresses + +import libvirt +import sys + +def usage(): +print Usage: %s [URI] DOMAIN % sys.argv[0] +print Print domain interfaces along with their MAC and IP addresses + +uri = None +name = None +args = len(sys.argv) + +if args == 2: +name = sys.argv[1] +elif args == 3: +uri = sys.argv[1] +name = sys.argv[2] +else: +usage() +sys.exit(2) + +conn = libvirt.openReadOnly(uri) +if conn == None: +print Unable to open connection to libvirt +sys.exit(1) + +try: +dom = conn.lookupByName(name) +except libvirt.libvirtError: +print Domain %s not found % name +sys.exit(0) + +ifaces = dom.interfaceAddresses(0) +if (ifaces == None): +print Failed to get domain interfaces +sys.exit(0) + +print {0:10} {1:20} {2:12} {3}.format(Interface, MAC address, Protocol, Address) + +for (name, val) in ifaces.iteritems(): +if val['ip_addrs']: +for addr in val['ip_addrs']: + print {0:10} {1:19}.format(name, val['hwaddr']), + print {0:12} {1}/{2} .format(addr['type'], addr['addr'], addr['prefix']), + print +else: +print {0:10} {1:19}.format(name, val['hwaddr']), +print diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 9a88215..60491de 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -602,5 +602,11 @@ arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/ arg name='flags' type='int' info='unused, pass 0'/ /function - /symbols +function name='virDomainInterfaceAddresses' file='python' + inforeturns a dictionary of domain interfaces along with their MAC and IP addresses/info + arg name='dom' type='virDomainPtr' info='pointer to the domain'/ + arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/ + return type='virDomainInterfacePtr' info=dictionary of domain interfaces along with their MAC and IP addresses/ +/function +/symbols /api diff --git a/python/libvirt-override.c b/python/libvirt-override.c index d16b9a2..67e0cb8 100644
[libvirt] [PATCHv5 3/5] domifaddr: Implement the API for qemu
By querying the qemu guest agent with the QMP command guest-network-get-interfaces and converting the received JSON output to structured objects. Although ifconfig is deprecated, IP aliases created by ifconfig are supported by this API. The legacy syntax of an IP alias is: ifname:alias-name. Since we want all aliases to be clubbed under parent interface, simply stripping :alias-name suffices. Note that IP aliases formed by ip aren't visible to ifconfig, and aliases created by ip do not have any specific name. But we are lucky, as qemuga detects aliases created by both. src/qemu/qemu_agent.h: * Define qemuAgentGetInterfaces src/qemu/qemu_agent.c: * Implement qemuAgentGetInterface src/qemu/qemu_driver.c: * New function qemuDomainInterfaceAddresses src/remote_protocol-sructs: * Define new structs tests/qemuagenttest.c: * Add new test: testQemuAgentGetInterfaces Test cases for IP aliases, 0 or multiple ipv4/ipv6 address(es) --- src/qemu/qemu_agent.c | 193 + src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 ++ tests/qemuagenttest.c | 149 ++ 4 files changed, 400 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 2cd0ccc..009ed77 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1320,6 +1320,199 @@ cleanup: } /* + * qemuAgentGetInterfaces: + * @mon: Agent + * @ifaces: pointer to an array of pointers pointing to interface objects + * + * Issue guest-network-get-interfaces to guest agent, which returns the + * list of a interfaces of a running domain along with their IP and MAC + * addresses. + * + * Returns: number of interfaces on success, -1 on error. + */ +int +qemuAgentGetInterfaces(qemuAgentPtr mon, + virDomainInterfacePtr **ifaces) +{ +int ret = -1; +size_t i, j; +int size = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +virJSONValuePtr ret_array = NULL; +size_t ifaces_count = 0; +size_t addrs_count = 0; +virDomainInterfacePtr *ifaces_ret = NULL; +virHashTablePtr ifaces_store = NULL; + +/* Initially the bag of ifaces is empty */ +if (!(ifaces_store = virHashCreate(ifaces_count, NULL))) +return -1; + +if (!(cmd = qemuAgentMakeCommand(guest-network-get-interfaces, NULL))) + return -1; + +if (qemuAgentCommand(mon, cmd, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0 || +qemuAgentCheckError(cmd, reply) 0) { +goto cleanup; +} + +if (!(ret_array = virJSONValueObjectGet(reply, return))) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'return' field)); +goto cleanup; +} + +if ((size = virJSONValueArraySize(ret_array)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't return an array of interfaces)); +goto cleanup; +} + +for (i = 0; i size; i++) { +virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); +virJSONValuePtr ip_addr_arr = NULL; +const char *hwaddr, *ifname_s, *name = NULL; +char **ifname = NULL; +int ip_addr_arr_size; +virDomainInterfacePtr iface = NULL; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!tmp_iface) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(something has went really wrong)); +goto error; +} + +/* interface name is required to be presented */ +name = virJSONValueObjectGetString(tmp_iface, name); +if (!name) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'name' field)); +goto error; +} + +/* Handle aliases of type ifname:alias-name */ +ifname = virStringSplit(name, :, 2); +ifname_s = ifname[0]; + +iface = virHashLookup(ifaces_store, ifname_s); + +/* If the storage bag doesn't contain this iface, add it */ +if (!iface) { +if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) 0) +goto cleanup; + +if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) 0) +goto cleanup; + +if (virHashAddEntry(ifaces_store, ifname_s, +ifaces_ret[ifaces_count - 1]) 0) +goto cleanup; + +iface = ifaces_ret[ifaces_count - 1]; +iface-naddrs = 0; + +if (VIR_STRDUP(iface-name, ifname_s) 0) +goto error; + +/* hwaddr might be omitted */ +hwaddr = virJSONValueObjectGetString(tmp_iface, hardware-address); +if (hwaddr VIR_STRDUP(iface-hwaddr, hwaddr) 0) +goto error; +} + +/* Has to be freed for each interface. */ +
Re: [libvirt] [PATCHv5 1/5] domifaddr: Implement the public APIs
On Sun, Sep 1, 2013 at 7:13 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Define a new API virDomainInterfaceAddresses, which returns the address information of a running domain's interfaces(s). If no interface name is specified, it returns the information of all interfaces, otherwise it only returns the information of the specificed interface. The address information includes the MAC and IP addresses. Define helper function virDomainInterfaceFree, which allows the upper layer application to free the domain interface object conveniently. The API is going to provide multiple methods by flags, e.g. * Query guest agent * Parse lease file of dnsmasq * DHCP snooping But at this stage, it will only work with guest agent, and flags won't be supported. include/libvirt/libvirt.h.in: * Define virDomainInterfaceAddresses, virDomainInterfaceFree * Define structs virDomainInterface, virDomainIPAddress python/generator.py: * Skip the auto-generation for virDomainInterfaceAddresses and virDomainInterfaceFree src/driver.h: * Define domainInterfaceAddresses src/libvirt.c: * Implement virDomainInterfaceAddresses * Implement virDomainInterfaceFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 32 python/generator.py | 3 ++ src/driver.h | 6 +++ src/libvirt.c| 115 +++ src/libvirt_public.syms | 6 +++ 5 files changed, 162 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..1a34d02 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2044,6 +2044,38 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags); +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 _virDomainInterfaceIPAddress virDomainIPAddress; +typedef virDomainIPAddress *virDomainIPAddressPtr; +struct _virDomainInterfaceIPAddress { +int type;/* virIPAddrType */ +char *addr; /* IP address */ +unsigned int prefix; /* IP address prefix */ +}; + +typedef struct _virDomainInterface virDomainInterface; +typedef virDomainInterface *virDomainInterfacePtr; +struct _virDomainInterface { +char *name; /* interface name */ +char *hwaddr; /* hardware address */ +unsigned int naddrs;/* number of items in @addrs */ +virDomainIPAddressPtr addrs;/* array of IP addresses */ +}; + +int virDomainInterfaceAddresses(virDomainPtr dom, +virDomainInterfacePtr **ifaces, +unsigned int flags); + +void virDomainInterfaceFree(virDomainInterfacePtr iface); + /* Management of domain block devices */ int virDomainBlockPeek (virDomainPtr dom, diff --git a/python/generator.py b/python/generator.py index fb321c6..50f779b 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_impl = ( 'virNodeGetMemoryParameters', 'virNodeSetMemoryParameters', 'virNodeGetCPUMap', +'virDomainInterfaceAddresses', 'virDomainMigrate3', 'virDomainMigrateToURI3', ) @@ -560,6 +561,8 @@ skip_function = ( virTypedParamsGetString, virTypedParamsGetUInt, virTypedParamsGetULLong, + +virDomainInterfaceFree, # Only useful in C ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..eb4927b 100644 --- a/src/driver.h +++ b/src/driver.h @@ -518,6 +518,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainInterfaceAddresses)(virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +typedef int (*virDrvDomainMemoryStats)(virDomainPtr domain, struct _virDomainMemoryStat *stats, unsigned int nr_stats, @@ -1238,6 +1243,7 @@ struct _virDriver { virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; +virDrvDomainInterfaceAddressesdomainInterfaceAddresses; virDrvDomainMemoryStats domainMemoryStats; virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..82c117f 100644 --- a/src/libvirt.c +++ b/src/libvirt.c
Re: [libvirt] [PATCHv5 5/5] domifaddr: Expose python binding
On Sun, Sep 1, 2013 at 7:13 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Expose virDomainInterfaceAddresses to python binding examples/python/Makefile.am: * Add new file domipaddrs.py examples/python/README: * Add documentation for the python example python/libvirt-override-api.xml: * Add new symbol for virDomainInterfaceAddresses python/libvirt-override.c: * Hand written python api Example: $ ./run python ./examples/python/domipaddrs.py f18 Interface MAC address Protocol Address lo 00:00:00:00:00:00ipv4 127.0.0.1/8 lo 00:00:00:00:00:00ipv6 ::1/128 eth2 52:54:00:36:2a:e5 eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 eth1 52:54:00:b1:70:19ipv4 192.168.201.195/16 eth1 52:54:00:b1:70:19ipv6 fe80::5054:ff:feb1:7019/64 eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 eth0 52:54:00:2e:45:ceipv6 2001:db8:0:f101::2/64 eth0 52:54:00:2e:45:ceipv6 fe80::5054:ff:fe2e:45ce/64 --- examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 50 ++ python/libvirt-override-api.xml | 8 ++- python/libvirt-override.c | 111 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100755 examples/python/domipaddrs.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index 2cacfa1..d33ee17 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -17,4 +17,4 @@ EXTRA_DIST=\ README \ consolecallback.py \ - dominfo.py domrestore.py domsave.py domstart.py esxlist.py + dominfo.py domrestore.py domsave.py domstart.py esxlist.py domipaddrs.py diff --git a/examples/python/README b/examples/python/README index f4db76c..1285d52 100644 --- a/examples/python/README +++ b/examples/python/README @@ -10,6 +10,7 @@ domsave.py - save all running domU's into a directory domrestore.py - restore domU's from their saved files in a directory esxlist.py - list active domains of an VMware ESX host and print some info. also demonstrates how to use the libvirt.openAuth() method +domipaddrs.py - print domain interfaces along with their MAC and IP addresses The XML files in this directory are examples of the XML format that libvirt expects, and will have to be adapted for your setup. They are only needed diff --git a/examples/python/domipaddrs.py b/examples/python/domipaddrs.py new file mode 100755 index 000..679e0bf --- /dev/null +++ b/examples/python/domipaddrs.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# domipaddrds - print domain interfaces along with their MAC and IP addresses + +import libvirt +import sys + +def usage(): +print Usage: %s [URI] DOMAIN % sys.argv[0] +print Print domain interfaces along with their MAC and IP addresses + +uri = None +name = None +args = len(sys.argv) + +if args == 2: +name = sys.argv[1] +elif args == 3: +uri = sys.argv[1] +name = sys.argv[2] +else: +usage() +sys.exit(2) + +conn = libvirt.openReadOnly(uri) +if conn == None: +print Unable to open connection to libvirt +sys.exit(1) + +try: +dom = conn.lookupByName(name) +except libvirt.libvirtError: +print Domain %s not found % name +sys.exit(0) + +ifaces = dom.interfaceAddresses(0) +if (ifaces == None): +print Failed to get domain interfaces +sys.exit(0) + +print {0:10} {1:20} {2:12} {3}.format(Interface, MAC address, Protocol, Address) + +for (name, val) in ifaces.iteritems(): +if val['ip_addrs']: +for addr in val['ip_addrs']: + print {0:10} {1:19}.format(name, val['hwaddr']), + print {0:12} {1}/{2} .format(addr['type'], addr['addr'], addr['prefix']), + print +else: +print {0:10} {1:19}.format(name, val['hwaddr']), +print diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 9a88215..60491de 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -602,5 +602,11 @@ arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/ arg name='flags' type='int' info='unused, pass 0'/ /function - /symbols +function name='virDomainInterfaceAddresses' file='python' + inforeturns a dictionary of domain interfaces along with their MAC and IP addresses/info + arg name='dom' type='virDomainPtr' info='pointer to the domain'/ + arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/ + return type='virDomainInterfacePtr
Re: [libvirt] [PATCHv5 2/5] domifaddr: Implement the remote protocol
On Mon, Sep 2, 2013 at 5:11 PM, Daniel P. Berrange berra...@redhat.com wrote: On Sun, Sep 01, 2013 at 07:13:32PM +0530, Nehal J Wani wrote: daemon/remote.c * Define remoteSerializeDomainInterface, remoteDispatchDomainInterfaceAddresses src/remote/remote_driver.c * Define remoteDomainInterfaceAddresses src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_DOMAIN_INTERFACE_ADDRESSES * Define structs remote_domain_ip_addr, remote_domain_interface, remote_domain_interfaces_addresse_args, remote_domain_interface_addresses_ret * Introduce upper bounds (to handle DDoS attacks): REMOTE_DOMAIN_INTERFACE_MAX = 2048 REMOTE_DOMAIN_IP_ADDR_MAX = 2048 Restrictions on the maximum number of aliases per interface were removed after kernel v2.0, and theoretically, at present, there are no upper limits on number of interfaces per virtual machine and on the number of IP addresses per interface. src/remote_protocol-structs * New structs added --- daemon/remote.c | 131 +++ src/remote/remote_driver.c | 99 src/remote/remote_protocol.x | 40 - src/remote_protocol-structs | 24 4 files changed, 293 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 6ace7af..7091cab 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5144,7 +5144,138 @@ cleanup: + +static int +remoteDispatchDomainInterfaceAddresses( +virNetServerPtr server ATTRIBUTE_UNUSED, +virNetServerClientPtr client, +virNetMessagePtr msg ATTRIBUTE_UNUSED, +virNetMessageErrorPtr rerr, +remote_domain_interface_addresses_args *args, +remote_domain_interface_addresses_ret *ret) Normal practice for this file is to layout args thus: static int remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, remote_domain_interface_addresses_args *args, remote_domain_interface_addresses_ret *ret) ACK if the style issue is fixed Style issue fix (File attached): diff --git a/daemon/remote.c b/daemon/remote.c index 7091cab..d46e3ea 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5230,13 +5230,12 @@ cleanup: } static int -remoteDispatchDomainInterfaceAddresses( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client, -virNetMessagePtr msg ATTRIBUTE_UNUSED, -virNetMessageErrorPtr rerr, -remote_domain_interface_addresses_args *args, -remote_domain_interface_addresses_ret *ret) +remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_interface_addresses_args *args, + remote_domain_interface_addresses_ret *ret) { size_t i; int rv = -1; PS: IMO, other functions like remoteDispatchDomainCreateWithFiles, remoteDispatchDomainCreateXMLWithFiles, remoteDispatchDomainMigrateFinish3Params, etc also need same style change 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 2.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv5 3/5] domifaddr: Implement the API for qemu
\, -\hardware-address\:\52:54:00:36:2a:e5\ +\hardware-address\:\00:00:00:00:00:00\ } ] }; @@ -679,36 +679,75 @@ testQemuAgentGetInterfaces(const void *data) goto cleanup; } -if (ifaces[0]-naddrs != 2 || +if (STRNEQ(ifaces[0]-name, eth2) || +STRNEQ(ifaces[1]-name, eth1) || +STRNEQ(ifaces[2]-name, eth0) || +STRNEQ(ifaces[3]-name, lo)) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + unexpected return values for interface names); +goto cleanup; +} + +if (STRNEQ(ifaces[0]-hwaddr, 52:54:00:36:2a:e5) || +STRNEQ(ifaces[1]-hwaddr, 52:54:00:d3:39:ee) || +STRNEQ(ifaces[2]-hwaddr, 52:54:00:89:ad:35) || +STRNEQ(ifaces[3]-hwaddr, 00:00:00:00:00:00)) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + unexpected return values for MAC addresses); +goto cleanup; +} + +if (ifaces[0]-naddrs != 0 || ifaces[1]-naddrs != 4 || ifaces[2]-naddrs != 4 || -ifaces[3]-naddrs != 0) { +ifaces[3]-naddrs != 2) { virReportError(VIR_ERR_INTERNAL_ERROR, %s, - unexpected return value for number of IP addresses); + unexpected return values for number of IP addresses); goto cleanup; } -if (STRNEQ(ifaces[0]-name, lo) || -STRNEQ(ifaces[0]-addrs[0].addr, 127.0.0.1) || -ifaces[0]-addrs[1].prefix != 128) { +if (ifaces[1]-addrs[0].type != VIR_IP_ADDR_TYPE_IPV4 || +ifaces[1]-addrs[1].type != VIR_IP_ADDR_TYPE_IPV6 || +ifaces[1]-addrs[2].type != VIR_IP_ADDR_TYPE_IPV4 || +ifaces[1]-addrs[3].type != VIR_IP_ADDR_TYPE_IPV6 || +ifaces[2]-addrs[0].type != VIR_IP_ADDR_TYPE_IPV6 || +ifaces[2]-addrs[1].type != VIR_IP_ADDR_TYPE_IPV4 || +ifaces[2]-addrs[2].type != VIR_IP_ADDR_TYPE_IPV4 || +ifaces[2]-addrs[3].type != VIR_IP_ADDR_TYPE_IPV6 || +ifaces[3]-addrs[0].type != VIR_IP_ADDR_TYPE_IPV4 || +ifaces[3]-addrs[1].type != VIR_IP_ADDR_TYPE_IPV6) { virReportError(VIR_ERR_INTERNAL_ERROR, %s, - unexpected return values for interface: lo); + unexpected return values for IP address types); goto cleanup; } -if (STRNEQ(ifaces[1]-hwaddr, 52:54:00:89:ad:35) || -ifaces[1]-addrs[0].prefix != 24 || -ifaces[1]-addrs[1].type != VIR_IP_ADDR_TYPE_IPV6) { +if (ifaces[1]-addrs[0].prefix != 24 || +ifaces[1]-addrs[1].prefix != 64 || +ifaces[1]-addrs[2].prefix != 32 || +ifaces[1]-addrs[3].prefix != 64 || +ifaces[2]-addrs[0].prefix != 64 || +ifaces[2]-addrs[1].prefix != 24 || +ifaces[2]-addrs[2].prefix != 16 || +ifaces[2]-addrs[3].prefix != 64 || +ifaces[3]-addrs[0].prefix != 8 || +ifaces[3]-addrs[1].prefix != 128) { virReportError(VIR_ERR_INTERNAL_ERROR, %s, - unexpected return values for interface: eth0); + unexpected return values for IP address prefix); goto cleanup; } -if (STRNEQ(ifaces[2]-name, eth1) || -ifaces[2]-addrs[0].type != VIR_IP_ADDR_TYPE_IPV4 || -STRNEQ(ifaces[2]-addrs[1].addr, fe80::5054:ff:fed3:39ee)) { +if (STRNEQ(ifaces[1]-addrs[0].addr, 192.168.10.91) || +STRNEQ(ifaces[1]-addrs[1].addr, fe80::fc54:ff:fefe:4c4f) || +STRNEQ(ifaces[1]-addrs[2].addr, 192.168.103.83) || +STRNEQ(ifaces[1]-addrs[3].addr, fe80::5054:ff:fed3:39ee) || +STRNEQ(ifaces[2]-addrs[0].addr, fe80::5054:ff:fe89:ad35) || +STRNEQ(ifaces[2]-addrs[1].addr, 192.168.102.142) || +STRNEQ(ifaces[2]-addrs[2].addr, 192.168.234.152) || +STRNEQ(ifaces[2]-addrs[3].addr, fe80::5054:ff:fec3:68bb) || +STRNEQ(ifaces[3]-addrs[0].addr, 127.0.0.1) || +STRNEQ(ifaces[3]-addrs[1].addr, ::1)) { virReportError(VIR_ERR_INTERNAL_ERROR, %s, - unexpected return values for interface: eth1); + unexpected return values for IP address values); goto cleanup; } -- Nehal J Wani 3.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv5 3/5] domifaddr: Implement the API for qemu
On Tue, Sep 3, 2013 at 7:46 PM, Osier Yang jy...@redhat.com wrote: Except what Daniel pointed out: On 01/09/13 21:43, Nehal J Wani wrote: By querying the qemu guest agent with the QMP command guest-network-get-interfaces and converting the received JSON output to structured objects. Although ifconfig is deprecated, IP aliases created by ifconfig are supported by this API. The legacy syntax of an IP alias is: ifname:alias-name. Since we want all aliases to be clubbed under parent interface, simply stripping :alias-name suffices. s/suffices/suffixes/, Here, I by suffices, I meant: Be enough or adequate. Note that IP aliases formed by ip aren't visible to ifconfig, and aliases created by ip do not have any specific name. But we are lucky, as qemuga detects aliases created by both. s/qemuga/qemu guest agent/, or s/qemuga/qemu-ga/, src/qemu/qemu_agent.h: * Define qemuAgentGetInterfaces src/qemu/qemu_agent.c: * Implement qemuAgentGetInterface src/qemu/qemu_driver.c: * New function qemuDomainInterfaceAddresses src/remote_protocol-sructs: * Define new structs tests/qemuagenttest.c: * Add new test: testQemuAgentGetInterfaces Test cases for IP aliases, 0 or multiple ipv4/ipv6 address(es) --- src/qemu/qemu_agent.c | 193 + src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 ++ tests/qemuagenttest.c | 149 ++ 4 files changed, 400 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 2cd0ccc..009ed77 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1320,6 +1320,199 @@ cleanup: } /* + * qemuAgentGetInterfaces: + * @mon: Agent s/Agent/Agent monitor/, + * @ifaces: pointer to an array of pointers pointing to interface objects + * + * Issue guest-network-get-interfaces to guest agent, which returns the s/the/a/, + * list of a interfaces of a running domain along with their IP and MAC s/of a/of/, + * addresses. + * + * Returns: number of interfaces on success, -1 on error. + */ +int +qemuAgentGetInterfaces(qemuAgentPtr mon, + virDomainInterfacePtr **ifaces) +{ +int ret = -1; +size_t i, j; +int size = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +virJSONValuePtr ret_array = NULL; +size_t ifaces_count = 0; +size_t addrs_count = 0; +virDomainInterfacePtr *ifaces_ret = NULL; +virHashTablePtr ifaces_store = NULL; + +/* Initially the bag of ifaces is empty */ bag is magic here, how about: /* Hash table to handle the interface alias */ +if (!(ifaces_store = virHashCreate(ifaces_count, NULL))) +return -1; + +if (!(cmd = qemuAgentMakeCommand(guest-network-get-interfaces, NULL))) + return -1; You should free the created hash table. In the label cleanup, I have freed the has table. + +if (qemuAgentCommand(mon, cmd, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0 || +qemuAgentCheckError(cmd, reply) 0) { +goto cleanup; +} + +if (!(ret_array = virJSONValueObjectGet(reply, return))) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'return' field)); +goto cleanup; +} + +if ((size = virJSONValueArraySize(ret_array)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't return an array of interfaces)); +goto cleanup; +} + +for (i = 0; i size; i++) { +virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); +virJSONValuePtr ip_addr_arr = NULL; +const char *hwaddr, *ifname_s, *name = NULL; +char **ifname = NULL; +int ip_addr_arr_size; +virDomainInterfacePtr iface = NULL; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!tmp_iface) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(something has went really wrong)); +goto error; +} + +/* interface name is required to be presented */ +name = virJSONValueObjectGetString(tmp_iface, name); +if (!name) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'name' field)); +goto error; +} + +/* Handle aliases of type ifname:alias-name */ I think no need to mention the type here, since it only can be ifname:alias. So how about: /* Handle interface alias (ifname:alias +ifname = virStringSplit(name, :, 2); +ifname_s = ifname[0]; + +iface = virHashLookup(ifaces_store, ifname_s); + +/* If the storage bag doesn't contain this iface, add it */ s/storage bag/hash table/, +if (!iface
Re: [libvirt] [PATCHv5 3/5] domifaddr: Implement the API for qemu
On Tue, Sep 3, 2013 at 8:21 PM, Osier Yang jy...@redhat.com wrote: On 03/09/13 22:37, Nehal J Wani wrote: On Tue, Sep 3, 2013 at 7:46 PM, Osier Yang jy...@redhat.com wrote: Except what Daniel pointed out: On 01/09/13 21:43, Nehal J Wani wrote: By querying the qemu guest agent with the QMP command guest-network-get-interfaces and converting the received JSON output to structured objects. Although ifconfig is deprecated, IP aliases created by ifconfig are supported by this API. The legacy syntax of an IP alias is: ifname:alias-name. Since we want all aliases to be clubbed under parent interface, simply stripping :alias-name suffices. s/suffices/suffixes/, Here, I by suffices, I meant: Be enough or adequate. Note that IP aliases formed by ip aren't visible to ifconfig, and aliases created by ip do not have any specific name. But we are lucky, as qemuga detects aliases created by both. s/qemuga/qemu guest agent/, or s/qemuga/qemu-ga/, src/qemu/qemu_agent.h: * Define qemuAgentGetInterfaces src/qemu/qemu_agent.c: * Implement qemuAgentGetInterface src/qemu/qemu_driver.c: * New function qemuDomainInterfaceAddresses src/remote_protocol-sructs: * Define new structs tests/qemuagenttest.c: * Add new test: testQemuAgentGetInterfaces Test cases for IP aliases, 0 or multiple ipv4/ipv6 address(es) --- src/qemu/qemu_agent.c | 193 + src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 55 ++ tests/qemuagenttest.c | 149 ++ 4 files changed, 400 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 2cd0ccc..009ed77 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1320,6 +1320,199 @@ cleanup: } /* + * qemuAgentGetInterfaces: + * @mon: Agent s/Agent/Agent monitor/, + * @ifaces: pointer to an array of pointers pointing to interface objects + * + * Issue guest-network-get-interfaces to guest agent, which returns the s/the/a/, + * list of a interfaces of a running domain along with their IP and MAC s/of a/of/, + * addresses. + * + * Returns: number of interfaces on success, -1 on error. + */ +int +qemuAgentGetInterfaces(qemuAgentPtr mon, + virDomainInterfacePtr **ifaces) +{ +int ret = -1; +size_t i, j; +int size = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +virJSONValuePtr ret_array = NULL; +size_t ifaces_count = 0; +size_t addrs_count = 0; +virDomainInterfacePtr *ifaces_ret = NULL; +virHashTablePtr ifaces_store = NULL; + +/* Initially the bag of ifaces is empty */ bag is magic here, how about: /* Hash table to handle the interface alias */ +if (!(ifaces_store = virHashCreate(ifaces_count, NULL))) +return -1; + +if (!(cmd = qemuAgentMakeCommand(guest-network-get-interfaces, NULL))) + return -1; You should free the created hash table. In the label cleanup, I have freed the has table. But you returns -1 here. + +if (qemuAgentCommand(mon, cmd, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0 || +qemuAgentCheckError(cmd, reply) 0) { +goto cleanup; +} + +if (!(ret_array = virJSONValueObjectGet(reply, return))) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'return' field)); +goto cleanup; +} + +if ((size = virJSONValueArraySize(ret_array)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't return an array of interfaces)); +goto cleanup; +} + +for (i = 0; i size; i++) { +virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); +virJSONValuePtr ip_addr_arr = NULL; +const char *hwaddr, *ifname_s, *name = NULL; +char **ifname = NULL; +int ip_addr_arr_size; +virDomainInterfacePtr iface = NULL; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!tmp_iface) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(something has went really wrong)); +goto error; +} + +/* interface name is required to be presented */ +name = virJSONValueObjectGetString(tmp_iface, name); +if (!name) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'name' field)); +goto error; +} + +/* Handle aliases of type ifname:alias-name */ I think no need to mention the type here, since it only can be ifname:alias. So how about: /* Handle interface alias (ifname:alias +ifname = virStringSplit(name, :, 2); +ifname_s = ifname[0]; + +iface = virHashLookup(ifaces_store
[libvirt] [PATCH] Fix: Syle issues (daemon/remote.c)
Fix for argument layouts of various functions in daemon/remote.c. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00057.html --- daemon/remote.c | 117 ++-- 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 6ace7af..2aff7c1 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3852,13 +3852,13 @@ cleanup: return rv; } -static int remoteDispatchDomainGetDiskErrors( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client, -virNetMessagePtr msg ATTRIBUTE_UNUSED, -virNetMessageErrorPtr rerr, -remote_domain_get_disk_errors_args *args, -remote_domain_get_disk_errors_ret *ret) +static int +remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_get_disk_errors_args *args, + remote_domain_get_disk_errors_ret *ret) { int rv = -1; virDomainPtr dom = NULL; @@ -4674,13 +4674,12 @@ cleanup: } static int -remoteDispatchDomainMigrateBegin3Params( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client ATTRIBUTE_UNUSED, -virNetMessagePtr msg ATTRIBUTE_UNUSED, -virNetMessageErrorPtr rerr, -remote_domain_migrate_begin3_params_args *args, -remote_domain_migrate_begin3_params_ret *ret) +remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +virNetServerClientPtr client ATTRIBUTE_UNUSED, +virNetMessagePtr msg ATTRIBUTE_UNUSED, +virNetMessageErrorPtr rerr, + remote_domain_migrate_begin3_params_args *args, + remote_domain_migrate_begin3_params_ret *ret) { char *xml = NULL; virDomainPtr dom = NULL; @@ -4733,13 +4732,12 @@ cleanup: } static int -remoteDispatchDomainMigratePrepare3Params( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client ATTRIBUTE_UNUSED, -virNetMessagePtr msg ATTRIBUTE_UNUSED, -virNetMessageErrorPtr rerr, -remote_domain_migrate_prepare3_params_args *args, -remote_domain_migrate_prepare3_params_ret *ret) +remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_migrate_prepare3_params_args *args, + remote_domain_migrate_prepare3_params_ret *ret) { virTypedParameterPtr params = NULL; int nparams = 0; @@ -4794,13 +4792,12 @@ cleanup: } static int -remoteDispatchDomainMigratePrepareTunnel3Params( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client, -virNetMessagePtr msg, -virNetMessageErrorPtr rerr, -remote_domain_migrate_prepare_tunnel3_params_args *args, -remote_domain_migrate_prepare_tunnel3_params_ret *ret) +remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +virNetServerClientPtr client, +virNetMessagePtr msg, +virNetMessageErrorPtr rerr, + remote_domain_migrate_prepare_tunnel3_params_args *args, + remote_domain_migrate_prepare_tunnel3_params_ret *ret) { virTypedParameterPtr params = NULL; int nparams = 0; @@ -4865,13 +4862,12 @@ cleanup: static int -remoteDispatchDomainMigratePerform3Params( -virNetServerPtr server ATTRIBUTE_UNUSED, -virNetServerClientPtr client ATTRIBUTE_UNUSED, -virNetMessagePtr msg ATTRIBUTE_UNUSED, -virNetMessageErrorPtr rerr, -remote_domain_migrate_perform3_params_args *args, -remote_domain_migrate_perform3_params_ret *ret) +remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_migrate_perform3_params_args *args, +
Re: [libvirt] [PATCHv5 1/5] domifaddr: Implement the public APIs
On Wed, Sep 4, 2013 at 8:05 PM, Osier Yang jy...@redhat.com wrote: On 04/09/13 03:13, Eric Blake wrote: On 09/03/2013 01:07 PM, Eric Blake wrote: On 09/01/2013 07:43 AM, Nehal J Wani wrote: Define a new API virDomainInterfaceAddresses, which returns the address information of a running domain's interfaces(s). If no interface name is specified, it returns the information of all interfaces, otherwise it only returns the information of the specificed interface. The address information includes the MAC and IP addresses. Define helper function virDomainInterfaceFree, which allows the upper layer application to free the domain interface object conveniently. The API is going to provide multiple methods by flags, e.g. * Query guest agent * Parse lease file of dnsmasq * DHCP snooping But at this stage, it will only work with guest agent, and flags won't be supported. That worries me a bit. Ultimately, we want our interfaces to behave as sane as possible when flags==0; rather than making the behavior be that 'flags==0' implies 'only guest agent probe', I'd rather introduce a flag right away up front that says 'include guest agent probe in the set of attempted methods', and then document that 'flags==0 is shorthand for letting the hypervisor choose the best method(s) out of supported possibilities)'. In other words, I want to make sure that this API will be similar to virDomainShutdownFlags, where a flags of 0 lets the hypervisor choose between methods, a single explicit flag forces the hypervisor to use that method alone, and more than one flag can be OR'd together to let the hypervisor choose among that subset of flags. Hmm. I'm replying to myself - is that a good sign? If the guest agent returns names that are provided by the guest, and don't necessarily correspond to the domain XML, then maybe it's best to NEVER return guest results by default, but to make the user always explicitly request agent interaction. Hm, yes, the MAC address returned by guest agent might not match what the domain config specifies. It reminds me something, both the leases file and snooping will returns the interface name like vnetN, which is different with what guest agent returns (like ethN or emN). And since the MAC address from guest agent might be different with what domain config specifies, we have no way to convert it into the names in domain config. That says we will have different name styles for guest agent and the other two methods, which will need quite documentations to explain. That is, even if 'flags==0' is used to select between parsing the lease file vs. DHCP snoop results (both of which tie perfectly to guest XML naming), the agent approach can seriously confuse users if they passed flags==0 and don't know if they are getting XML names or guest-provided names. Which argues that guest results should ALWAYS be an explicit non-zero flag, never an automatic action. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list Daniel, would like to throw some light on the discussion? -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv5 1/5] domifaddr: Implement the public APIs
On Tue, Sep 3, 2013 at 6:51 PM, Osier Yang jy...@redhat.com wrote: On 01/09/13 21:43, Nehal J Wani wrote: Define a new API virDomainInterfaceAddresses, which returns the address information of a running domain's interfaces(s). If no interface name is specified, it returns the information of all interfaces, otherwise it only returns the information of the specificed interface. The address information includes the MAC and IP addresses. This API only returns all of the interfaces' address info, it doesn't take an argument to specify an interface. My bad though, didn't find it out in previous reviewing. ACK with the commit log fixed. Osier The optional argument interface is supported. I had forgotten to add it in the example. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv6 3/5] domifaddr: Implement the API for qemu
By querying the qemu guest agent with the QMP command guest-network-get-interfaces and converting the received JSON output to structured objects. Although ifconfig is deprecated, IP aliases created by ifconfig are supported by this API. The legacy syntax of an IP alias is: ifname:alias-name. Since we want all aliases to be clubbed under parent interface, simply stripping :alias-name suffices. Note that IP aliases formed by ip aren't visible to ifconfig, and aliases created by ip do not have any specific name. But we are lucky, as qemu guest agent detects aliases created by both. src/qemu/qemu_agent.h: * Define qemuAgentGetInterfaces src/qemu/qemu_agent.c: * Implement qemuAgentGetInterface src/qemu/qemu_driver.c: * New function qemuDomainInterfaceAddresses src/remote_protocol-sructs: * Define new structs tests/qemuagenttest.c: * Add new test: testQemuAgentGetInterfaces Test cases for IP aliases, 0 or multiple ipv4/ipv6 address(es) --- src/qemu/qemu_agent.c | 202 + src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 74 ++ tests/qemuagenttest.c | 188 + 4 files changed, 467 insertions(+) diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 2cd0ccc..76f8e7c 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -1320,6 +1320,208 @@ cleanup: } /* + * qemuAgentGetInterfaces: + * @mon: Agent monitor + * @ifaces: pointer to an array of pointers pointing to interface objects + * + * Issue guest-network-get-interfaces to guest agent, which returns a + * list of interfaces of a running domain along with their IP and MAC + * addresses. + * + * Returns: number of interfaces on success, -1 on error. + */ +int +qemuAgentGetInterfaces(qemuAgentPtr mon, + virDomainInterfacePtr **ifaces) +{ +int ret = -1; +size_t i, j; +int size = -1; +virJSONValuePtr cmd = NULL; +virJSONValuePtr reply = NULL; +virJSONValuePtr ret_array = NULL; +size_t ifaces_count = 0; +size_t addrs_count = 0; +virDomainInterfacePtr *ifaces_ret = NULL; +virHashTablePtr ifaces_store = NULL; +char **ifname = NULL; + +/* Hash table to handle the interface alias */ +if (!(ifaces_store = virHashCreate(ifaces_count, NULL))) { +virHashFree(ifaces_store); +return -1; +} + +if (!(cmd = qemuAgentMakeCommand(guest-network-get-interfaces, NULL))) { +goto cleanup; +} + +if (qemuAgentCommand(mon, cmd, reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) 0 || +qemuAgentCheckError(cmd, reply) 0) { +goto cleanup; +} + +if (!(ret_array = virJSONValueObjectGet(reply, return))) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'return' field)); +goto cleanup; +} + +if ((size = virJSONValueArraySize(ret_array)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't return an array of interfaces)); +goto cleanup; +} + +for (i = 0; i size; i++) { +virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); +virJSONValuePtr ip_addr_arr = NULL; +const char *hwaddr, *ifname_s, *name = NULL; +int ip_addr_arr_size; +virDomainInterfacePtr iface = NULL; + +/* Shouldn't happen but doesn't hurt to check neither */ +if (!tmp_iface) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(something has went really wrong)); +goto error; +} + +/* interface name is required to be presented */ +name = virJSONValueObjectGetString(tmp_iface, name); +if (!name) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide 'name' field)); +goto error; +} + +/* Handle interface alias (ifname:alias) */ +ifname = virStringSplit(name, :, 2); +ifname_s = ifname[0]; + +iface = virHashLookup(ifaces_store, ifname_s); + +/* If the hash table doesn't contain this iface, add it */ +if (!iface) { +if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) 0) +goto error; + +if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) 0) +goto error; + +if (virHashAddEntry(ifaces_store, ifname_s, +ifaces_ret[ifaces_count - 1]) 0) +goto error; + +iface = ifaces_ret[ifaces_count - 1]; +iface-naddrs = 0; + +if (VIR_STRDUP(iface-name, ifname_s) 0) +goto error; + +hwaddr = virJSONValueObjectGetString(tmp_iface, hardware-address); +if (!hwaddr) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(qemu agent didn't provide +
[libvirt] [PATCHv6 2/5] domifaddr: Implement the remote protocol
daemon/remote.c * Define remoteSerializeDomainInterface, remoteDispatchDomainInterfaceAddresses src/remote/remote_driver.c * Define remoteDomainInterfaceAddresses src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_DOMAIN_INTERFACE_ADDRESSES * Define structs remote_domain_ip_addr, remote_domain_interface, remote_domain_interfaces_addresse_args, remote_domain_interface_addresses_ret * Introduce upper bounds (to handle DDoS attacks): REMOTE_DOMAIN_INTERFACE_MAX = 2048 REMOTE_DOMAIN_IP_ADDR_MAX = 2048 Restrictions on the maximum number of aliases per interface were removed after kernel v2.0, and theoretically, at present, there are no upper limits on number of interfaces per virtual machine and on the number of IP addresses per interface. src/remote_protocol-structs * New structs added --- daemon/remote.c | 130 +++ src/remote/remote_driver.c | 99 src/remote/remote_protocol.x | 40 - src/remote_protocol-structs | 24 4 files changed, 292 insertions(+), 1 deletion(-) diff --git a/daemon/remote.c b/daemon/remote.c index 2aff7c1..4dff602 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5137,7 +5137,137 @@ cleanup: return rv; } +static int +remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces, + unsigned int ifaces_count, + remote_domain_interface_addresses_ret *ret) +{ +size_t i, j; + +if (ifaces_count REMOTE_DOMAIN_INTERFACE_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of interfaces, %d exceeds the max limit: %d), + ifaces_count, REMOTE_DOMAIN_INTERFACE_MAX); +return -1; +} + +if (VIR_ALLOC_N(ret-ifaces.ifaces_val, ifaces_count) 0) +return -1; + +ret-ifaces.ifaces_len = ifaces_count; + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); + +if ((VIR_STRDUP(iface_ret-name, iface-name)) 0) +goto cleanup; + +if (iface-hwaddr) { +char **hwaddr_p = NULL; +if (VIR_ALLOC(hwaddr_p) 0) +goto cleanup; +if (VIR_STRDUP(*hwaddr_p, iface-hwaddr) 0) { +VIR_FREE(hwaddr_p); +goto cleanup; +} + +iface_ret-hwaddr = hwaddr_p; +} + +if (iface-naddrs REMOTE_DOMAIN_IP_ADDR_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of interfaces, %d exceeds the max limit: %d), + iface-naddrs, REMOTE_DOMAIN_IP_ADDR_MAX); +goto cleanup; +} + +if (VIR_ALLOC_N(iface_ret-addrs.addrs_val, +iface-naddrs) 0) +goto cleanup; + +iface_ret-addrs.addrs_len = iface-naddrs; + +for (j = 0; j iface-naddrs; j++) { +virDomainIPAddressPtr ip_addr = (iface-addrs[j]); +remote_domain_ip_addr *ip_addr_ret = +(iface_ret-addrs.addrs_val[j]); + +if (VIR_STRDUP(ip_addr_ret-addr, ip_addr-addr) 0) +goto cleanup; + +ip_addr_ret-prefix = ip_addr-prefix; +ip_addr_ret-type = ip_addr-type; +} +} + +return 0; + +cleanup: +if (ret-ifaces.ifaces_val) { +for (i = 0; i ifaces_count; i++) { +remote_domain_interface *iface_ret = (ret-ifaces.ifaces_val[i]); +VIR_FREE(iface_ret-name); +VIR_FREE(iface_ret-hwaddr); +for (j = 0; j iface_ret-addrs.addrs_len; j++) { +remote_domain_ip_addr *ip_addr = +(iface_ret-addrs.addrs_val[j]); +VIR_FREE(ip_addr-addr); +} +VIR_FREE(iface_ret); +} +VIR_FREE(ret-ifaces.ifaces_val); +} + +return -1; +} + +static int +remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_interface_addresses_args *args, + remote_domain_interface_addresses_ret *ret) +{ +size_t i; +int rv = -1; +virDomainPtr dom = NULL; +virDomainInterfacePtr *ifaces = NULL; +int ifaces_count = 0; +struct daemonClientPrivate *priv = +virNetServerClientGetPrivateData(client); + +if (!priv-conn) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, _(connection not open)); +goto cleanup; +} +if (!(dom = get_nonnull_domain(priv-conn, args-dom))) +goto cleanup; +
[libvirt] [PATCHv6 5/5] domifaddr: Expose python binding
Expose virDomainInterfacesAddresses to python binding examples/python/Makefile.am: * Add new file domipaddrs.py examples/python/README: * Add documentation for the python example python/libvirt-override-api.xml: * Add new symbol for virDomainInterfacesAddresses python/libvirt-override.c: * Hand written python api Example: $ ./run ./examples/python/domipaddrs.py qemu:///system f18 Interface MAC address Protocol Address lo 00:00:00:00:00:00ipv4 127.0.0.1/8 lo 00:00:00:00:00:00ipv6 ::1/128 eth3 52:54:00:20:70:3dipv4 192.168.105.240/16 eth3 52:54:00:20:70:3dipv6 fe80::5054:ff:fe20:703d/64 eth2 52:54:00:36:2a:e5N/A N/A eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 eth1 52:54:00:b1:70:19ipv4 192.168.201.195/16 eth1 52:54:00:b1:70:19ipv6 fe80::5054:ff:feb1:7019/64 eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 eth0 52:54:00:2e:45:ceipv6 2001:db8:0:f101::2/64 eth0 52:54:00:2e:45:ceipv6 fe80::5054:ff:fe2e:45ce/64 --- examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 57 ++ python/libvirt-override-api.xml | 8 +++- python/libvirt-override.c | 102 5 files changed, 168 insertions(+), 2 deletions(-) create mode 100755 examples/python/domipaddrs.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index 7823c20..b77154f 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -18,4 +18,4 @@ EXTRA_DIST= \ README \ consolecallback.py \ topology.py \ - dominfo.py domrestore.py domsave.py domstart.py esxlist.py + dominfo.py domrestore.py domsave.py domstart.py esxlist.py domipaddrs.py diff --git a/examples/python/README b/examples/python/README index f4db76c..1285d52 100644 --- a/examples/python/README +++ b/examples/python/README @@ -10,6 +10,7 @@ domsave.py - save all running domU's into a directory domrestore.py - restore domU's from their saved files in a directory esxlist.py - list active domains of an VMware ESX host and print some info. also demonstrates how to use the libvirt.openAuth() method +domipaddrs.py - print domain interfaces along with their MAC and IP addresses The XML files in this directory are examples of the XML format that libvirt expects, and will have to be adapted for your setup. They are only needed diff --git a/examples/python/domipaddrs.py b/examples/python/domipaddrs.py new file mode 100755 index 000..4430f59 --- /dev/null +++ b/examples/python/domipaddrs.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# domipaddrds - print domain interfaces along with their MAC and IP addresses + +import libvirt +import sys + +def usage(): +print Usage: %s [URI] DOMAIN % sys.argv[0] +print Print domain interfaces along with their MAC and IP addresses + +uri = None +name = None +args = len(sys.argv) + +if args == 2: +name = sys.argv[1] +elif args == 3: +uri = sys.argv[1] +name = sys.argv[2] +else: +usage() +sys.exit(2) + +conn = libvirt.open(uri) +if conn == None: +print Unable to open connection to libvirt +sys.exit(1) + +try: +dom = conn.lookupByName(name) +except libvirt.libvirtError: +print Domain %s not found % name +sys.exit(0) + +ifaces = dom.interfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT); +if (ifaces == None): +print Failed to get domain interfaces +sys.exit(0) + +print {0:10} {1:20} {2:12} {3}.format(Interface, MAC address, Protocol, Address) + +def toIPAddrType(addrType): +if addrType == libvirt.VIR_IP_ADDR_TYPE_IPV4: +return ipv4 +elif addrType == libvirt.VIR_IP_ADDR_TYPE_IPV6: +return ipv6 + +for (name, val) in ifaces.iteritems(): +if val['ip_addrs']: +for addr in val['ip_addrs']: + print {0:10} {1:19}.format(name, val['hwaddr']), + print {0:12} {1}/{2} .format(toIPAddrType(addr['type']), addr['addr'], addr['prefix']), + print +else: +print {0:10} {1:19}.format(name, val['hwaddr']), +print {0:12} {1}.format(N/A, N/A), +print diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 9a88215..60491de 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -602,5 +602,11 @@ arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/ arg name='flags' type='int' info='unused, pass 0'/ /function - /symbols +function name='virDomainInterfaceAddresses' file='python' + inforeturns a
[libvirt] [PATCHv6 0/5] Introduce API to query IP addresses for given domain
This feature has been requested for a very long time. Since qemu guest agent gives us reliable results, now the wait is over. The RFC was first proposed by Michal Privoznik: http://www.redhat.com/archives/libvir-list/2012-February/msg00437.html A patch was submitted, using structs: https://www.redhat.com/archives/libvir-list/2012-June/msg00220.html Another patch was submitted, using XML: https://www.redhat.com/archives/libvir-list/2012-June/msg00904.html Neither of the patches were accepted, probably due to lack of extensibility and usability. Hence, we thought of using virTypedParameters for reporting list of interfaces along with their MAC address and IP addresses. The RFC can be found here: https://www.redhat.com/archives/libvir-list/2013-July/msg00084.html The idea of extensibility was rejected and rendered out of scope of libvirt. Hence, we were back to structs. This API is called virDomainInterfaceAddresses which returns a dynamically allocated array of virDomainInterface struct. The great disadvantage is once this gets released, it's written in stone and we cannot change or add an item into it. The API supports two methods: * Return information (list of all associated interfaces with MAC address and IP addresses) of all of the domain interfaces by default (if no interface name is provided) * Return information for the specified interface (if an interface name is provided) v6: * Inclusion of flags, readonly check for guest agent connection * Correction of memory leaks, other small nits. v5: * s/virDomainInterfacesAddresses/virDomainInterfaceAddresses. * Case for IP aliasing handled using virHashTable. * New test cases added, involving multiple and 0 IP addresse(s) per interface. * IP prefix changed from int to unsigned int. * Changes to practice libvirt habits. * https://www.redhat.com/archives/libvir-list/2013-September/msg3.html v4: * Various style nits, indentation errors, memory leaks fixed. * https://www.redhat.com/archives/libvir-list/2013-August/msg01265.html v3: * Upper bounds to number of interfaces and addresses per interface introduced. * Change from array of structs to array of pointers * ifaces_count moved from function argument to return value * Changes in variable names * Test cases added for qemuAgentGetInterfaces. * https://www.redhat.com/archives/libvir-list/2013-August/msg01215.html v2: * Logical errors, memory leaks and few other errors fixed. * https://www.redhat.com/archives/libvir-list/2013-August/msg00631.html v1: * http://www.redhat.com/archives/libvir-list/2013-July/msg01553.html Nehal J Wani (5): domifaddr: Implement the public APIs domifaddr: Implement the remote protocol domifaddr: Implement the API for qemu domifaddr: Add virsh support domifaddr: Expose python binding daemon/remote.c | 130 ++ examples/python/Makefile.am | 2 +- examples/python/README | 1 + examples/python/domipaddrs.py | 56 +++ include/libvirt/libvirt.h.in| 38 python/generator.py | 3 + python/libvirt-override-api.xml | 8 +- python/libvirt-override.c | 102 src/driver.h| 6 ++ src/libvirt.c | 135 +++ src/libvirt_public.syms | 6 ++ src/qemu/qemu_agent.c | 201 src/qemu/qemu_agent.h | 3 + src/qemu/qemu_driver.c | 76 +++ src/remote/remote_driver.c | 99 src/remote/remote_protocol.x| 40 +++- src/remote_protocol-structs | 24 + tests/qemuagenttest.c | 188 + tools/virsh-domain-monitor.c| 131 ++ tools/virsh.pod | 18 20 files changed, 1264 insertions(+), 3 deletions(-) create mode 100755 examples/python/domipaddrs.py -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv6 4/5] domifaddr: Add virsh support
Use virDomainInterfaceAddresses in virsh tools/virsh-domain-monitor.c * Introduce new command : domifaddr Usage: domifaddr domain [interface] [--full] [--snoop] [--lease] [--agent] Example outputs: virsh # domifaddr f18 Name MAC address Protocol Address --- lo 00:00:00:00:00:00ipv4 127.0.0.1/8 - -ipv6 ::1/128 eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 - -ipv6 2001:db8:0:f101::2/64 - -ipv6 fe80::5054:ff:fe2e:45ce/64 eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 - -ipv4 192.168.201.195/16 - -ipv6 fe80::5054:ff:feb1:7019/64 eth2 52:54:00:36:2a:e5N/A N/A eth3 52:54:00:20:70:3dipv4 192.168.105.240/16 - -ipv6 fe80::5054:ff:fe20:703d/64 virsh # domifaddr f18 eth1 --agent Name MAC address Protocol Address --- eth1 52:54:00:b1:70:19ipv4 192.168.105.201/16 - -ipv4 192.168.201.195/16 - -ipv6 fe80::5054:ff:feb1:7019/64 virsh # domifaddr f18 eth0 --agent --full Name MAC address Protocol Address --- eth0 52:54:00:2e:45:ceipv4 10.1.33.188/24 eth0 52:54:00:2e:45:ceipv6 2001:db8:0:f101::2/64 eth0 52:54:00:2e:45:ceipv6 fe80::5054:ff:fe2e:45ce/64 tools/virsh.pod * Document new command --- tools/virsh-domain-monitor.c | 131 +++ tools/virsh.pod | 18 ++ 2 files changed, 149 insertions(+) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b29b82a..3690776 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1871,6 +1871,131 @@ cleanup: } #undef FILTER +/* domifaddr command + */ +static const vshCmdInfo info_domifaddr[] = { +{help, N_(Get network interfaces' addresses for a running domain)}, +{desc, N_(Get network interfaces' addresses for a running domain)}, +{NULL, NULL} +}; + +static const vshCmdOptDef opts_domifaddr[] = { +{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)}, +{interface, VSH_OT_DATA, VSH_OFLAG_NONE, N_(network interface name)}, +{full, VSH_OT_BOOL, VSH_OFLAG_NONE, N_(display full fields)}, +{snoop, VSH_OT_BOOL, VSH_OFLAG_NONE, N_(snoop network traffic)}, +{lease, VSH_OT_BOOL, VSH_OFLAG_NONE, N_(parse dhcp lease file)}, +{agent, VSH_OT_BOOL, VSH_OFLAG_NONE, N_(query qemu guest agent)}, +{NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) +{ +virDomainPtr dom = NULL; +const char *interface = NULL; +virDomainInterfacePtr *ifaces = NULL; +size_t i, j; +int ifaces_count = 0; +unsigned int flags = 0; +bool ret = false; +bool full = vshCommandOptBool(cmd, full); + +if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) +return false; + +if (vshCommandOptString(cmd, interface, interface) 0) { +goto cleanup; +} + +if (vshCommandOptBool(cmd, snoop)) +flags |= VIR_DOMAIN_INTERFACE_ADDRESSES_SNOOP; + +if (vshCommandOptBool(cmd, lease)) +flags |= VIR_DOMAIN_INTERFACE_ADDRESSES_LEASE; + +if (vshCommandOptBool(cmd, agent)) +flags |= VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT; + +if ((ifaces_count = virDomainInterfaceAddresses(dom, ifaces, flags)) 0) { +vshError(ctl, _(Failed to query for interfaces addresses)); +goto cleanup; +} + +vshPrintExtra(ctl, %-10s %-20s %-8s %s\n%s%s\n, _(Name), + _(MAC address), _(Protocol), _(Address), + _(-), + _(--)); + +for (i = 0; i ifaces_count; i++) { +virDomainInterfacePtr iface = ifaces[i]; +const char *hwaddr = ; +const char *ip_addr_str = NULL; +const char *type = NULL; + +if (interface STRNEQ(interface, iface-name)) +continue; + +hwaddr = iface-hwaddr; + +/* When the interface has no IP address */ +if (!iface-naddrs) { +vshPrintExtra(ctl, %-10s %-17s%-12s %s\n, + iface-name, hwaddr, N/A, N/A); +continue; +} + +for (j = 0; j iface-naddrs; j++) { +virBuffer buf = VIR_BUFFER_INITIALIZER; + +
[libvirt] [PATCHv6 1/5] domifaddr: Implement the public APIs
Define helper function virDomainInterfaceFree, which allows the upper layer application to free the domain interface object conveniently. The API is going to provide multiple methods by flags, e.g. * Query guest agent * Parse lease file of dnsmasq * DHCP snooping At this stage, it will only work with guest agent. Passing other flags will result in error: Method hasn't been implemented yet include/libvirt/libvirt.h.in: * Define virDomainInterfaceAddresses, virDomainInterfaceFree * Define structs virDomainInterface, virDomainIPAddress python/generator.py: * Skip the auto-generation for virDomainInterfaceAddresses and virDomainInterfaceFree src/driver.h: * Define domainInterfaceAddresses src/libvirt.c: * Implement virDomainInterfaceAddresses * Implement virDomainInterfaceFree src/libvirt_public.syms: * Export the new symbols --- include/libvirt/libvirt.h.in | 38 python/generator.py | 3 + src/driver.h | 6 ++ src/libvirt.c| 135 +++ src/libvirt_public.syms | 6 ++ 5 files changed, 188 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a47e33c..0995080 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2044,6 +2044,44 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, virTypedParameterPtr params, int *nparams, unsigned int flags); +typedef enum { +VIR_DOMAIN_INTERFACE_ADDRESSES_SNOOP = (1 0), /* Snoop traffic */ +VIR_DOMAIN_INTERFACE_ADDRESSES_LEASE = (1 1), /* Parse DHCP lease file */ +VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT = (1 2), /* Query qemu guest agent */ +} virDomainInterfaceAddressesFlags; + +typedef enum { +VIR_IP_ADDR_TYPE_IPV4 = 0, +VIR_IP_ADDR_TYPE_IPV6 = 1, + +#ifdef VIR_ENUM_SENTINELS +VIR_IP_ADDR_TYPE_LAST, +#endif +} virIPAddrType; + +typedef struct _virDomainInterfaceIPAddress virDomainIPAddress; +typedef virDomainIPAddress *virDomainIPAddressPtr; +struct _virDomainInterfaceIPAddress { +int type;/* virIPAddrType */ +char *addr; /* IP address */ +unsigned int prefix; /* IP address prefix */ +}; + +typedef struct _virDomainInterface virDomainInterface; +typedef virDomainInterface *virDomainInterfacePtr; +struct _virDomainInterface { +char *name; /* interface name */ +char *hwaddr; /* hardware address */ +unsigned int naddrs;/* number of items in @addrs */ +virDomainIPAddressPtr addrs;/* array of IP addresses */ +}; + +int virDomainInterfaceAddresses(virDomainPtr dom, +virDomainInterfacePtr **ifaces, +unsigned int flags); + +void virDomainInterfaceFree(virDomainInterfacePtr iface); + /* Management of domain block devices */ int virDomainBlockPeek (virDomainPtr dom, diff --git a/python/generator.py b/python/generator.py index fb321c6..50f779b 100755 --- a/python/generator.py +++ b/python/generator.py @@ -458,6 +458,7 @@ skip_impl = ( 'virNodeGetMemoryParameters', 'virNodeSetMemoryParameters', 'virNodeGetCPUMap', +'virDomainInterfaceAddresses', 'virDomainMigrate3', 'virDomainMigrateToURI3', ) @@ -560,6 +561,8 @@ skip_function = ( virTypedParamsGetString, virTypedParamsGetUInt, virTypedParamsGetULLong, + +virDomainInterfaceFree, # Only useful in C ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index be64333..210a910 100644 --- a/src/driver.h +++ b/src/driver.h @@ -518,6 +518,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainInterfaceAddresses)(virDomainPtr dom, + virDomainInterfacePtr **ifaces, + unsigned int flags); + +typedef int (*virDrvDomainMemoryStats)(virDomainPtr domain, struct _virDomainMemoryStat *stats, unsigned int nr_stats, @@ -1238,6 +1243,7 @@ struct _virDriver { virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; +virDrvDomainInterfaceAddresses domainInterfaceAddresses; virDrvDomainMemoryStats domainMemoryStats; virDrvDomainBlockPeek domainBlockPeek; virDrvDomainMemoryPeek domainMemoryPeek; diff --git a/src/libvirt.c b/src/libvirt.c index 07a3fd5..7a5759b 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -8643,6 +8643,116 @@ error: return -1; } + /** + * virDomainInterfaceAddresses: + * @dom: domain object + * @ifaces: pointer to an array of pointers pointing to interface objects + *
Re: [libvirt] [PATCHv6 1/5] domifaddr: Implement the public APIs
ping On Sun, Sep 8, 2013 at 2:42 PM, Osier Yang jy...@redhat.com wrote: [..] + * + * If 0 is passed as @flags, libvirt will choose the best way, and won't + * include agent in it. I'm thinking if we don't need to be so complicated, by defaulting to one of _LEASE or _SNOOP explicitly. That says (conclusion of all of above), I'm wondering if define the enum like blow is better. typedef enum { VIR_DOMAIN_INTERFACE_**ADDRESSES_AGENT = (1 1), /* Query qemu guest agent */ And s/AGENT/GUEST_AGENT/, since AGENT could mean too much than guest agent -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 4/4] net-dhcp-leases: Add virsh support
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 addressHostname ClientId -- 11-09-2013 03:53:11 52:54:00:89:4e:97192.168.101.130 f18 * 11-09-2013 03:45:20 52:54:00:fe:4c:4f192.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 Bnet-dhcp-leases Inetwork Imac + +Get a list of dhcp leases for all network interfaces connected to the given +virtual Inetwork or limited output just for one interface if Imac is +specified. + =back =head1 INTERFACE COMMANDS -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH 2/4] net-dhcp-leases: Implement the remote protocol
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; +
[libvirt] [PATCH 1/4] net-dhcp-leases: Implement the public APIs
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
[libvirt] [PATCH 3/4] net-dhcp-leases: Private implementation inside network driver
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
[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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] rpmbuild libvirt 1.1.2 problem
On Wed, Sep 11, 2013 at 10:17 AM, jsjshaowen...@21cn.com wrote: hi: i build rpm in centos 6.2, libvirt version 1.1.2,i found an error FAIL: virsh-uriprecedence Details in the attachment,thanks !Wait for a response --- 21CN手机邮Android客户端,邮件随身享! -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list Reproducible on Cent OS 6.4 x86_64 See attached log for details. -- Nehal J Wani PASS: virshtest PASS: sockettest PASS: nodeinfotest PASS: virbuftest PASS: commandtest PASS: seclabeltest PASS: virhashtest PASS: virnetmessagetest PASS: virnetsockettest PASS: viratomictest PASS: utiltest PASS: shunloadtest PASS: virtimetest PASS: viruritest PASS: virkeyfiletest PASS: virauthconfigtest PASS: virbitmaptest PASS: vircgrouptest PASS: virendiantest PASS: viridentitytest PASS: virkeycodetest PASS: virlockspacetest PASS: virstringtest PASS: virportallocatortest PASS: sysinfotest PASS: virstoragetest PASS: fdstreamtest PASS: fchosttest PASS: virnettlscontexttest PASS: virnettlssessiontest SKIP: securityselinuxtest SKIP: securityselinuxlabeltest PASS: virdrivermoduletest PASS: qemuxml2argvtest PASS: qemuxml2xmltest PASS: qemuxmlnstest PASS: qemuargv2xmltest PASS: qemuhelptest PASS: domainsnapshotxml2xmltest PASS: qemumonitortest PASS: qemumonitorjsontest PASS: qemuhotplugtest PASS: qemuagenttest PASS: lxcxml2xmltest PASS: esxutilstest PASS: vmx2xmltest PASS: xml2vmxtest PASS: jsontest PASS: networkxml2xmltest PASS: networkxml2xmlupdatetest PASS: networkxml2conftest PASS: nwfilterxml2xmltest PASS: storagevolxml2argvtest PASS: storagevolxml2xmltest PASS: storagepoolxml2xmltest PASS: nodedevxml2xmltest PASS: interfacexml2xmltest PASS: cputest PASS: eventtest PASS: libvirtdconftest PASS: capabilityschematest PASS: interfaceschematest PASS: networkschematest PASS: storagepoolschematest PASS: storagevolschematest PASS: domainschematest PASS: nodedevschematest PASS: nwfilterschematest PASS: domainsnapshotschematest #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h #include stdlib.h PASS: test_conf.sh PASS: cpuset PASS: define-dev-segfault PASS: int-overflow PASS: libvirtd-fail PASS: libvirtd-pool PASS: read-bufsiz PASS: read-non-seekable PASS: start FAIL: virsh-uriprecedence PASS: vcpupin PASS: virsh-all PASS: virsh-optparse PASS: virsh-schedinfo PASS: virsh-synopsis PASS: virsh-undefine make[4]: Entering directory `/root/rpmbuild/BUILD/libvirt-1.1.2/tests' make[4]: Nothing to be done for `all'. make[4]: Leaving directory `/root/rpmbuild/BUILD/libvirt-1.1.2/tests' Testsuite summary for libvirt 1.1.2 # TOTAL: 85 # PASS: 82 # SKIP: 2 # XFAIL: 0 # FAIL: 1 # XPASS: 0 # ERROR: 0 See tests/test-suite.log Please report to libvir-list@redhat.com make[3]: *** [test-suite.log] Error 1 make[3]: Leaving directory `/root/rpmbuild/BUILD/libvirt-1.1.2/tests' make[2]: *** [check-TESTS] Error 2 make[2]: Leaving directory `/root/rpmbuild/BUILD/libvirt-1.1.2/tests' make[1]: *** [check-am] Error 2 make[1]: Leaving directory `/root/rpmbuild/BUILD/libvirt-1.1.2/tests' + cat test-suite.log = libvirt 1.1.2: tests/test-suite.log = # TOTAL: 85 # PASS: 82 # SKIP: 2 # XFAIL: 0 # FAIL: 1 # XPASS: 0 # ERROR: 0 .. contents:: :depth: 2 SKIP: securityselinuxtest = TEST: securityselinuxtest SKIP: securityselinuxlabeltest == TEST: securityselinuxlabeltest FAIL: virsh-uriprecedence = error: failed to connect to the hypervisor error: no valid connection error: internal error: Unable to locate libvirtd daemon in /usr/sbin (to override, set $LIBVIRTD_PATH to the name of the libvirtd binary) 1) User config file ... FAILED 2) LIBVIRT_DEFAULT_URI ... OK 3) VIRSH_DEFAULT_CONNECT_URI... OK 4) Parameter... OK + exit 1 error: Bad exit status from /var/tmp/rpm-tmp.oRWBuD (%check) RPM build errors: Bad exit status from /var/tmp/rpm-tmp.oRWBuD (%check) make: *** [rpm] Error 1 [root@ldap libvirt-1.1.2]# #include sys/types.h [root@ldap libvirt-1.1.2]# #include sys/stat.h [root@ldap libvirt-1.1.2]# #include fcntl.h [root@ldap libvirt-1.1.2]# #include unistd.h [root@ldap libvirt-1.1.2]# #include stdlib.h -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 1/4] net-dhcp-leases: Implement the public APIs
On Wed, Sep 11, 2013 at 9:25 PM, Daniel P. Berrange berra...@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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 2/4] net-dhcp-leases: Implement the remote protocol
+ +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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv6 1/5] domifaddr: Implement the public APIs
Eric, could you please share your views on the discussion? On Sun, Sep 8, 2013 at 2:42 PM, Osier Yang jy...@redhat.com wrote: [..] + * + * If 0 is passed as @flags, libvirt will choose the best way, and won't + * include agent in it. I'm thinking if we don't need to be so complicated, by defaulting to one of _LEASE or _SNOOP explicitly. That says (conclusion of all of above), I'm wondering if define the enum like blow is better. typedef enum { VIR_DOMAIN_INTERFACE_**ADDRESSES_AGENT = (1 1), /* Query qemu guest agent */ And s/AGENT/GUEST_AGENT/, since AGENT could mean too much than guest agent -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] rpmbuild libvirt 1.1.2 problem
The issue is being fixed by the patch: https://www.redhat.com/archives/libvir-list/2013-September/msg00703.html On Thu, Sep 12, 2013 at 8:35 PM, Alex Jia a...@redhat.com wrote: Hi Martin, BTW, I met the same question, and I ran 'make check' under root. -- Regards, Alex - Original Message - From: Martin Kletzander mklet...@redhat.com To: Nehal J Wani nehaljw.k...@gmail.com Cc: libvir-list libvir-list@redhat.com, jsjshaowen...@21cn.com Sent: Thursday, September 12, 2013 4:29:32 PM Subject: Re: [libvirt] rpmbuild libvirt 1.1.2 problem On 09/11/2013 07:18 PM, Nehal J Wani wrote: On Wed, Sep 11, 2013 at 10:17 AM, jsjshaowen...@21cn.com wrote: hi: i build rpm in centos 6.2, libvirt version 1.1.2,i found an error FAIL: virsh-uriprecedence Details in the attachment,thanks !Wait for a response Reproducible on Cent OS 6.4 x86_64 See attached log for details. I've identified the problem; we aren't correctly reading file paths when running as root. Are you running make check under root? Martin -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv2 2/4] net-dhcp-leases: Implement the remote protocol
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); +
[libvirt] [PATCHv2 1/4] net-dhcp-leases: Implement the public APIs
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; };
[libvirt] [PATCHv2 4/4] net-dhcp-leases: Add virsh support
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:3dipv4 192.168.105.240/24 f18 * 13-09-2013 03:32:31 52:54:00:b1:70:19ipv4 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 Bnet-dhcp-leases Inetwork Imac + +Get a list of dhcp leases for all network interfaces connected to the given +virtual Inetwork or limited output just for one interface if Imac is +specified. + =back =head1 INTERFACE COMMANDS -- 1.7.11.7 -- libvir-list mailing list
[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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv2 3/4] net-dhcp-leases: Private implementation inside network driver
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; 3.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv2 3/4] net-dhcp-leases: Private implementation inside network driver
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
[libvirt] [PATCHv3 0/4] Introduce APIs to extract DHCP leases info
This API returns the leases information stored in the DHCP leases file of dnsmasq for a given virtual network. It contacts the bridge network driver, which parses 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 v3 * Mostly small nits, change in MACRO names, use of virSocketAddrGetIpPrefix to retrieve IP prefix from @dom XML. v2 * Since DHCPv6 is supposed to be suported in future, virNetworkGetDHCPLeasesForMAC changed, prefix and virIPAddrType added in virNetworkDHCPLeases struct. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00732.html v1 * Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00620.html * The need for these APIs were result of a RFC was proposed on the list. Refer: http://www.redhat.com/archives/libvir-list/2013-July/msg01603.html Nehal J Wani (4): net-dhcp-leases: Implement the public APIs net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network 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_public.syms | 7 ++ src/network/bridge_driver.c | 177 +++ 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| 100 tools/virsh.pod | 6 ++ 13 files changed, 877 insertions(+), 1 deletion(-) -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv3 1/4] net-dhcp-leases: Implement the public APIs
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 (with type and prefix), 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 --- include/libvirt/libvirt.h.in | 33 + python/generator.py | 3 + src/driver.h | 13 src/libvirt.c| 173 +++ src/libvirt_public.syms | 7 ++ 5 files changed, 229 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 a6fcab0..05d20e9 100644 --- a/src/libvirt.c
[libvirt] [PATCHv3 3/4] net-dhcp-leases: Private implementation inside network driver
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 | 177 1 file changed, 177 insertions(+) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 3a8be90..f5adb97 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -109,6 +109,21 @@ static int networkPlugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); static int networkUnplugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); +/** + * VIR_NETWORK_DHCP_LEASE_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_DHCP_LEASE_LENGTH_MAX 2048 + +/** + * VIR_NETWORK_DHCPLEASE_PARAMS: + * + * Macro providing the maximum number of parameters in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FIELDS 5 static virNetworkDriverStatePtr driverState = NULL; @@ -2980,6 +2995,166 @@ cleanup: return ret; } +/* This function parese the leases file of dnsmasq. + * + * 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 * * + */ +static int +networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases) +{ +int rv = -1; +size_t i = 0; +size_t nleases = 0; +char *leasefile; +char **lease_fields; +char dhcpentry[VIR_NETWORK_DHCP_LEASE_LENGTH_MAX]; +virNetworkDHCPLeasesPtr *leases_ret = NULL; +FILE *fp = NULL; + +if (!network) { +virReportError(VIR_ERR_NO_NETWORK, %s, + _(no network with matching name)); +return -1; +} + +/* Retrieve 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 cleanup; +} + +while (fgets(dhcpentry, sizeof(dhcpentry), fp) != NULL) { +virNetworkDHCPLeasesPtr lease = NULL; + +/* Remove newline */ +dhcpentry[strlen(dhcpentry) - 1] = '\0'; + +/* Split the lease line */ +lease_fields = virStringSplit(dhcpentry, , VIR_NETWORK_DHCP_LEASE_FIELDS); + +if (virStringListLength(lease_fields) != VIR_NETWORK_DHCP_LEASE_FIELDS) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of lease params aren't equal to: %d), + VIR_NETWORK_DHCP_LEASE_FIELDS); +goto error; +} + +if (mac STRNEQ(mac, lease_fields[1])) +continue; + +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(lease_fields[0], NULL, 10, (lease-expirytime)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Unable to convert lease expiry time to integer: %s), + lease_fields[0]); +goto error; +} + +/* Hardcoded, as dnsmasq uses ipv4 */ +lease-type = VIR_IP_ADDR_TYPE_IPV4; +lease-prefix = virSocketAddrGetIpPrefix(obj-def-ips-address, + obj-def-ips-netmask, + obj-def-ips-prefix); + +if ((VIR_STRDUP(lease-mac, lease_fields[1]) 0) || +(VIR_STRDUP(lease-ipaddr, lease_fields[2]) 0) || +(VIR_STRDUP(lease-hostname, lease_fields[3]) 0) || +(VIR_STRDUP(lease-clientid, lease_fields[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) { +/* 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 int
[libvirt] [PATCHv3 2/4] net-dhcp-leases: Implement the remote protocol
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..5252893 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_DHCP_LEASES_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of leases is %d, which exceeds max limit: %d), + nleases, REMOTE_NETWORK_DHCP_LEASES_MAX); +return -1; +} + +if (VIR_ALLOC_N(ret-leases.leases_val, nleases) 0) +return -1; + +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: +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); +virNetworkFree(net); +return rv; +} + +static int +remoteDispatchNetworkGetDHCPLeasesForMAC(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_for_mac_args *args, + remote_network_get_dhcp_leases_for_mac_ret *ret) +{ +int rv = -1; +struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); +virNetworkDHCPLeasesPtr *leases = NULL; +
[libvirt] [PATCHv3 4/4] net-dhcp-leases: Add virsh support
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:3dipv4 192.168.105.240/24 f18 * 13-09-2013 03:32:31 52:54:00:b1:70:19ipv4 192.168.105.201/24 LDAP * tools/virsh.pod * Document new command --- tools/virsh-network.c | 100 ++ tools/virsh.pod | 6 +++ 2 files changed, 106 insertions(+) diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8ddd5ca..9543c64 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1129,6 +1129,100 @@ 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) +return false; + +if (!(network = vshCommandOptNetworkBy(ctl, cmd, name, + VSH_BYNAME | VSH_BYUUID))) +return false; + +nleases = mac ? virNetworkGetDHCPLeasesForMAC(network, mac, leases, flags) +: virNetworkGetDHCPLeases(network, leases, flags); + +if (nleases 0) { +vshError(ctl, _(Failed to get leases info for %s), name); +goto cleanup; +} + +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); +virNetworkFree(network); +return ret; +} const vshCmdDef networkCmds[] = { {.name = net-autostart, @@ -1209,5 +1303,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 Bnet-dhcp-leases Inetwork Imac + +Get a list of dhcp leases for all network interfaces connected to the given +virtual Inetwork or limited output just for one interface if Imac is +specified. + =back =head1 INTERFACE COMMANDS -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com
Re: [libvirt] [PATCHv3 1/4] net-dhcp-leases: Implement the public APIs
On Mon, Sep 16, 2013 at 3:22 PM, Daniel P. Berrange berra...@redhat.com wrote: On Mon, Sep 16, 2013 at 11:19:13AM +0530, Nehal J Wani wrote: +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__); Don't pass __FUNCTION__ in this error message - that is already done automatically +goto error; +} 'mac' should be a mandatory parameter here. Attached diff should fix it. But there are still calls to virReportInvalidArg() with __FUNCTION__ as one of its arguments in src/libvirt.c + +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; +} 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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv3 1/4] net-dhcp-leases: Implement the public APIs
PFA: Diff On Mon, Sep 16, 2013 at 8:44 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: On Mon, Sep 16, 2013 at 3:22 PM, Daniel P. Berrange berra...@redhat.com wrote: On Mon, Sep 16, 2013 at 11:19:13AM +0530, Nehal J Wani wrote: +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__); Don't pass __FUNCTION__ in this error message - that is already done automatically +goto error; +} 'mac' should be a mandatory parameter here. Attached diff should fix it. But there are still calls to virReportInvalidArg() with __FUNCTION__ as one of its arguments in src/libvirt.c + +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; +} 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 -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com 1.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] Add helper program to create custom leases
Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports dhcpv4 and dhcpv6. The file is saved as interface-name.status. The format of each lease is: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: 1385245780 52:54:00:2f:ba:76 * 192.168.150.153 * * 1385245781 52:54:00:2f:ba:76 3127926 2001:db8:ca2:2:1::6c * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 iiit-ad885e4aa1 01:52:54:00:44:7c:d7 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 * 01:52:54:00:44:7c:d7 1385246016 52:54:00:5d:99:92 * 192.168.150.212 iiit-ad885e4aa1 01:52:54:00:5d:99:92 1385246041 52:54:00:3b:16:e0 * 192.168.150.207 * * 1385246081 52:54:00:db:dd:98 * 192.168.150.234 * * 1385246088 52:54:00:db:dd:98 14409112 2001:db8:ca2:2:1::6d * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec --- src/util/leaseshelper.c | 232 1 file changed, 232 insertions(+) create mode 100644 src/util/leaseshelper.c diff --git a/src/util/leaseshelper.c b/src/util/leaseshelper.c new file mode 100644 index 000..9ed22a6 --- /dev/null +++ b/src/util/leaseshelper.c @@ -0,0 +1,232 @@ +/* + * leasehelper.c: Helper program to create custom leases file + * + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * http://www.gnu.org/licenses/. + * + * Author: Nehal J Wani nehaljw.k...@gmail.com + * + */ + +#include config.h + +#include stdio.h +#include stdlib.h + +#include virutil.h +#include virthread.h +#include virfile.h +#include virbuffer.h +#include virstring.h +#include virerror.h +#include viralloc.h +#include configmake.h + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FIELDS: + * + * Macro providing the maximum number of fields in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FIELDS 6 +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152 + +/* + * Use this when passing possibly-NULL strings to printf-a-likes. + */ +# define EMPTY_STR(s) ((s) ? (s) : *) + +int +main(int argc, char **argv) { + +FILE *g = fopen(/tmp/wtf, a); +int j; +for (j = 0; j argc; j++) +fprintf(g, called :: : %s, , argv[j]); +fprintf(g, \n); +fclose(g); + +/* Doesn't hurt to check */ +if (argc 4) { +/* Refer man page of dnsmasq --dhcp-script for more details */ +fprintf(stderr, Usage: $program $action ${mac|clientid} $ip\n); +return -1; +} + +const char *program_name = argv[0]; +const char *action = argv[1]; +const char *interface = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_INTERFACE)); +const char *expirytime = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_LEASE_EXPIRES)); +const char *mac = argv[2]; +const char *ip = argv[3]; +const char *iaid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_IAID)); +const char *hostname = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_SUPPLIED_HOSTNAME)); +const char *clientid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_CLIENT_ID)); +const char *leases_str = NULL; +char *lease_file = NULL; +char *lease_entries = NULL; +char *lease_entry = NULL; +char **lease_fields = NULL; +bool delete = false; +bool add = false; +int rv = -1; +int lease_file_len = 0; +FILE *fp = NULL; +long long expirytime_tmp = 0; +virBuffer buf_new_lease = VIR_BUFFER_INITIALIZER; +virBuffer buf_all_leases = VIR_BUFFER_INITIALIZER; + +if (setlocale(LC_ALL, ) == NULL || +bindtextdomain(PACKAGE, LOCALEDIR) == NULL || +textdomain(PACKAGE) == NULL) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virThreadInitialize() 0 || +virErrorInitialize() 0) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virAsprintf(lease_file, %s/%s.status, LOCALSTATEDIR +/lib/libvirt/dnsmasq/, interface) 0) +goto cleanup; + +if (virGetEnvAllowSUID(DNSMASQ_IAID)) { +mac = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_MAC)); +clientid = argv[2]; +} + +/* Make sure
[libvirt] [PATCH] Fix memory leak in testDomainCreateXMLMixed()
While running objecteventtest, it was found that valgrind pointed out the following memory leak: ==13025== 538 (56 direct, 482 indirect) bytes in 1 blocks are definitely lost in loss record 216 of 226 ==13025==at 0x4A06B6F: calloc (vg_replace_malloc.c:593) ==13025==by 0x4C65D8D: virAllocVar (viralloc.c:558) ==13025==by 0x4C9F055: virObjectNew (virobject.c:190) ==13025==by 0x4D2B2E8: virGetDomain (datatypes.c:220) ==13025==by 0x4D79180: testDomainDefineXML (test_driver.c:2962) ==13025==by 0x4D4977D: virDomainDefineXML (libvirt.c:8512) ==13025==by 0x4029C2: testDomainCreateXMLMixed (objecteventtest.c:226) ==13025==by 0x403A21: virtTestRun (testutils.c:138) ==13025==by 0x4021C2: mymain (objecteventtest.c:549) ==13025==by 0x4040C2: virtTestMain (testutils.c:593) ==13025==by 0x341F421A04: (below main) (libc-start.c:225) ==13025== --- tests/objecteventtest.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/tests/objecteventtest.c b/tests/objecteventtest.c index 65642a2..de57970 100644 --- a/tests/objecteventtest.c +++ b/tests/objecteventtest.c @@ -245,6 +245,12 @@ testDomainCreateXMLMixed(const void *data) if (id2 0) goto cleanup; +if (dom != NULL) { +virDomainUndefine(dom); +virDomainDestroy(dom); +virDomainFree(dom); +} + dom = virDomainCreateXML(test-conn, domainDef, 0); if (dom == NULL || virEventRunDefaultImpl() 0) goto cleanup; -- 1.8.1.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Add helper program to create custom leases
Ignore this. It has missing lines for compilation and addition in network driver. I am sending Patch v2. On Thu, Dec 19, 2013 at 1:09 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports dhcpv4 and dhcpv6. The file is saved as interface-name.status. The format of each lease is: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: 1385245780 52:54:00:2f:ba:76 * 192.168.150.153 * * 1385245781 52:54:00:2f:ba:76 3127926 2001:db8:ca2:2:1::6c * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 iiit-ad885e4aa1 01:52:54:00:44:7c:d7 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 * 01:52:54:00:44:7c:d7 1385246016 52:54:00:5d:99:92 * 192.168.150.212 iiit-ad885e4aa1 01:52:54:00:5d:99:92 1385246041 52:54:00:3b:16:e0 * 192.168.150.207 * * 1385246081 52:54:00:db:dd:98 * 192.168.150.234 * * 1385246088 52:54:00:db:dd:98 14409112 2001:db8:ca2:2:1::6d * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec --- src/util/leaseshelper.c | 232 1 file changed, 232 insertions(+) create mode 100644 src/util/leaseshelper.c diff --git a/src/util/leaseshelper.c b/src/util/leaseshelper.c new file mode 100644 index 000..9ed22a6 --- /dev/null +++ b/src/util/leaseshelper.c @@ -0,0 +1,232 @@ +/* + * leasehelper.c: Helper program to create custom leases file + * + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * http://www.gnu.org/licenses/. + * + * Author: Nehal J Wani nehaljw.k...@gmail.com + * + */ + +#include config.h + +#include stdio.h +#include stdlib.h + +#include virutil.h +#include virthread.h +#include virfile.h +#include virbuffer.h +#include virstring.h +#include virerror.h +#include viralloc.h +#include configmake.h + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FIELDS: + * + * Macro providing the maximum number of fields in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FIELDS 6 +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152 + +/* + * Use this when passing possibly-NULL strings to printf-a-likes. + */ +# define EMPTY_STR(s) ((s) ? (s) : *) + +int +main(int argc, char **argv) { + +FILE *g = fopen(/tmp/wtf, a); +int j; +for (j = 0; j argc; j++) +fprintf(g, called :: : %s, , argv[j]); +fprintf(g, \n); +fclose(g); + +/* Doesn't hurt to check */ +if (argc 4) { +/* Refer man page of dnsmasq --dhcp-script for more details */ +fprintf(stderr, Usage: $program $action ${mac|clientid} $ip\n); +return -1; +} + +const char *program_name = argv[0]; +const char *action = argv[1]; +const char *interface = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_INTERFACE)); +const char *expirytime = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_LEASE_EXPIRES)); +const char *mac = argv[2]; +const char *ip = argv[3]; +const char *iaid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_IAID)); +const char *hostname = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_SUPPLIED_HOSTNAME)); +const char *clientid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_CLIENT_ID)); +const char *leases_str = NULL; +char *lease_file = NULL; +char *lease_entries = NULL; +char *lease_entry = NULL; +char **lease_fields = NULL; +bool delete = false; +bool add = false; +int rv = -1; +int lease_file_len = 0; +FILE *fp = NULL; +long long expirytime_tmp = 0; +virBuffer buf_new_lease = VIR_BUFFER_INITIALIZER; +virBuffer buf_all_leases = VIR_BUFFER_INITIALIZER; + +if (setlocale(LC_ALL, ) == NULL || +bindtextdomain(PACKAGE, LOCALEDIR) == NULL || +textdomain(PACKAGE) == NULL) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virThreadInitialize() 0 || +virErrorInitialize() 0) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit
[libvirt] [PATCH v2] Add helper program to create custom leases
Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports DHCPv4 and DHCPv6. The file is saved as interface-name.status. The format of each lease is: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: 1385245780 52:54:00:2f:ba:76 * 192.168.150.153 * * 1385245781 52:54:00:2f:ba:76 3127926 2001:db8:ca2:2:1::6c * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 iiit-ad885e4aa1 01:52:54:00:44:7c:d7 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 * 01:52:54:00:44:7c:d7 1385246016 52:54:00:5d:99:92 * 192.168.150.212 iiit-ad885e4aa1 01:52:54:00:5d:99:92 1385246041 52:54:00:3b:16:e0 * 192.168.150.207 * * 1385246081 52:54:00:db:dd:98 * 192.168.150.234 * * 1385246088 52:54:00:db:dd:98 14409112 2001:db8:ca2:2:1::6d * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec --- As danpb suggested, I have split the previous patch into helper program API Refer: https://www.redhat.com/archives/libvir-list/2013-December/msg00694.html Once this get ACKed, I'll send in the patches for the Leases API v6 src/Makefile.am | 20 src/network/bridge_driver.c | 4 + src/util/leaseshelper.c | 225 3 files changed, 249 insertions(+) create mode 100644 src/util/leaseshelper.c diff --git a/src/Makefile.am b/src/Makefile.am index 57e163f..6e5b03c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -838,6 +838,9 @@ STORAGE_HELPER_DISK_SOURCES = \ UTIL_IO_HELPER_SOURCES = \ util/iohelper.c +UTIL_LEASES_HELPER_SOURCES = \ + util/leaseshelper.c + # Network filters NWFILTER_DRIVER_SOURCES = \ nwfilter/nwfilter_driver.h nwfilter/nwfilter_driver.c \ @@ -2408,6 +2411,23 @@ libvirt_iohelper_CFLAGS = \ $(NULL) endif WITH_LIBVIRTD +if WITH_LIBVIRTD +libexec_PROGRAMS += libvirt_leaseshelper +libvirt_leaseshelper_SOURCES = $(UTIL_LEASES_HELPER_SOURCES) +libvirt_leaseshelper_LDFLAGS = \ + $(NULL) +libvirt_leaseshelper_LDADD = \ + libvirt_util.la \ + ../gnulib/lib/libgnu.la +if WITH_DTRACE_PROBES +libvirt_leaseshelper_LDADD += libvirt_probes.lo +endif WITH_DTRACE_PROBES + +libvirt_leaseshelper_CFLAGS = \ + $(PIE_CFLAGS) \ + $(NULL) +endif WITH_LIBVIRTD + if WITH_STORAGE_DISK if WITH_LIBVIRTD libexec_PROGRAMS += libvirt_parthelper diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 95e4b65..2278dba 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1063,6 +1063,10 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps)); virCommandAddArgFormat(cmd, --conf-file=%s, configfile); + +/* This helper is used to create cutom leases file for libvirt */ +virCommandAddArgFormat(cmd, --dhcp-script=%s, LIBEXECDIR /libvirt_leaseshelper); + *cmdout = cmd; ret = 0; cleanup: diff --git a/src/util/leaseshelper.c b/src/util/leaseshelper.c new file mode 100644 index 000..486ebe3 --- /dev/null +++ b/src/util/leaseshelper.c @@ -0,0 +1,225 @@ +/* + * leasehelper.c: Helper program to create custom leases file + * + * Copyright (C) 2013 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * http://www.gnu.org/licenses/. + * + * Author: Nehal J Wani nehaljw.k...@gmail.com + * + */ + +#include config.h + +#include stdio.h +#include stdlib.h + +#include virutil.h +#include virthread.h +#include virfile.h +#include virbuffer.h +#include virstring.h +#include virerror.h +#include viralloc.h +#include configmake.h + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FIELDS: + * + * Macro providing the maximum number of fields in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FIELDS 6 +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152 + +/* + * Use this when passing possibly-NULL strings to printf-a-likes. + */ +# define
Re: [libvirt] [PATCH v2] Add helper program to create custom leases
On Thu, Jan 16, 2014 at 9:07 AM, Doug Goldstein car...@cardoe.com wrote: On Jan 14, 2014, at 2:09 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports DHCPv4 and DHCPv6. The file is saved as interface-name.status. The format of each lease is: expiry-time (epoch time) mac iaid ip-address hostname clientid I feel like I'm bikesheding but is it the best idea to have a custom file format? I know our string handling code makes this really easy to do but it just has a slight code smell to make our own format. We link to stuff like yajl and libxml for JSON/XML support and its really simple to do so we could easily write out a JSON/XML file and read it in. Definitely don't rework the patch based on my comments because we'll 99.9% go with this way, I'm just asking a question I felt should be asked. I understand the point you are trying to raise here. A similar discussion had taken place when I had posted the RFC: http://www.redhat.com/archives/libvir-list/2013-October/msg01024.html . If y'all still think that we should be using a format we already have a parser for, I'll be happy to rewrite the patch :-) -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v2] Add helper program to create custom leases
I feel like I'm bikesheding but is it the best idea to have a custom file format? I know our string handling code makes this really easy to do but it just has a slight code smell to make our own format. We link to stuff like yajl and libxml for JSON/XML support and its really simple to do so we could easily write out a JSON/XML file and read it in. Definitely don't rework the patch based on my comments because we'll 99.9% go with this way, I'm just asking a question I felt should be asked. Seems like nobody liked this format. I am sending the updated patch which uses JSON as the format for storing leases. -- Nehal J Wani -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v2] Add helper program to create custom leases
redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * http://www.gnu.org/licenses/. + * + * Author: Nehal J Wani nehaljw.k...@gmail.com + * + */ + +#include config.h + +#include stdio.h +#include stdlib.h + +#include virutil.h +#include virthread.h +#include virfile.h +#include virbuffer.h +#include virstring.h +#include virerror.h +#include viralloc.h +#include virjson.h +#include configmake.h + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152 + +/* + * Use this when passing possibly-NULL strings to printf-a-likes. + */ +# define EMPTY_STR(s) ((s) ? (s) : *) + +int +main(int argc, char **argv) { + +/* Doesn't hurt to check */ +if (argc 4) { +/* Refer man page of dnsmasq --dhcp-script for more details */ +fprintf(stderr, Usage: $program $action ${mac|clientid} $ip\n); +return -1; +} + +char *lease_file = NULL; +char *lease_entries = NULL; +const char *ip = argv[3]; +const char *mac = argv[2]; +const char *action = argv[1]; +const char *program_name = argv[0]; +const char *iaid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_IAID)); +const char *clientid = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_CLIENT_ID)); +const char *interface = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_INTERFACE)); +const char *exptime = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_LEASE_EXPIRES)); +const char *hostname = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_SUPPLIED_HOSTNAME)); +const char *leases_str = NULL; +size_t i = 0; +int rv = -1; +int size = 0; +int lease_file_len = 0; +FILE *fp = NULL; +bool add = false; +bool delete = false; +virJSONValuePtr lease_new; +virJSONValuePtr lease_tmp; +virJSONValuePtr leases_array; +virJSONValuePtr lease_new_tmp; +virJSONValuePtr leases_array_new; + +if (setlocale(LC_ALL, ) == NULL || +bindtextdomain(PACKAGE, LOCALEDIR) == NULL || +textdomain(PACKAGE) == NULL) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virThreadInitialize() 0 || +virErrorInitialize() 0) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virAsprintf(lease_file, %s/%s.status, LOCALSTATEDIR +/lib/libvirt/dnsmasq/, interface) 0) +goto cleanup; + +if (virGetEnvAllowSUID(DNSMASQ_IAID)) { +mac = EMPTY_STR(virGetEnvAllowSUID(DNSMASQ_MAC)); +clientid = argv[2]; +} + +/* Make sure dnsmasq knows the interface, otherwise something is wrong */ +if (STREQ(interface, *)) +goto cleanup; + +/* Make sure the file exists. If not, 'touch' it */ +if (virFileTouch(lease_file, 0644) 0) +goto cleanup; + +/* Read entire contents */ +if ((lease_file_len = virFileReadAll(lease_file, + VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX, + lease_entries)) 0) { +goto cleanup; +} + +if (STREQ(action, add) || STREQ(action, old) || STREQ(action, del)) { +if (mac || STREQ(action, del)) { +/* Delete the corresponding lease */ +delete = true; +if (STREQ(action, add) || STREQ(action, old)) { +add = true; +/* Enter new lease */ +if (!(lease_new = virJSONValueNewObject())) { +virReportError(VIR_ERR_INTERNAL_ERROR, %s, + _(failed to create json)); +goto cleanup; +} +if (virJSONValueObjectAppendString(lease_new, expiry-time, + exptime) 0 || +virJSONValueObjectAppendString(lease_new, mac-address, + mac) 0 || +virJSONValueObjectAppendString(lease_new, iaid, + iaid) 0 || +virJSONValueObjectAppendString(lease_new, ip-address, + ip) 0 || +virJSONValueObjectAppendString(lease_new, hostname
Re: [libvirt] [PATCH v2] Add helper program to create custom leases
On Mon, Jan 27, 2014 at 2:17 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports dhcpv4 and dhcpv6. The file is saved as interface-name.status. Each lease contains the following info: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: [ { expiry-time: 1390775837, mac-address: 52:54:00:93:8c:63, iaid: *, ip-address: 192.168.150.209, hostname: iit-ad885e4aa1, client-id: 01:52:54:00:44:7c:d7 }, { expiry-time: 1390775950, mac-address: 52:54:00:7b:6f:ba, iaid: 8089530, ip-address: 2001:db8:ca2:2:1::6d, hostname: *, client-id: 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec } ] src/Makefile.am: * Add options to compile the helper program src/network/bridge_driver.c: * Introduce networkDnsmasqLeaseFileNameCustom() * Invoke helper program along with dnsmasq * Delete the .status file when corresponding n/w is destroyed. src/util/leaseshelper.c * Helper program to create the custom lease file --- v2: * Changed format to JSON v1: * Refer: https://www.redhat.com/archives/libvir-list/2014-January/msg00626.html src/Makefile.am | 20 src/network/bridge_driver.c | 19 src/util/leaseshelper.c | 271 3 files changed, 310 insertions(+) create mode 100644 src/util/leaseshelper.c Ping! -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] Fix memory leak in virDomainSnapshotDiskDefClear()
While running domainsnapshotxml2xmltest, it was found that valgrind pointed out the following memory leaks: ==32176== 42 (32 direct, 10 indirect) bytes in 1 blocks are definitely lost in loss record 42 of 66 ==32176==at 0x4A069EE: malloc (vg_replace_malloc.c:270) ==32176==by 0x4A06B62: realloc (vg_replace_malloc.c:662) ==32176==by 0x4C65A07: virReallocN (viralloc.c:243) ==32176==by 0x4C65B2E: virExpandN (viralloc.c:292) ==32176==by 0x4C65E30: virInsertElementsN (viralloc.c:434) ==32176==by 0x4CD71F3: virDomainDiskSourceDefParse (domain_conf.c:5078) ==32176==by 0x4CF6EF4: virDomainSnapshotDefParseNode (snapshot_conf.c:151) ==32176==by 0x4CF7314: virDomainSnapshotDefParseString (snapshot_conf.c:410) ==32176==by 0x41FB8D: testCompareXMLToXMLHelper (domainsnapshotxml2xmltest.c:100) ==32176==by 0x420FD1: virtTestRun (testutils.c:199) ==32176==by 0x41F859: mymain (domainsnapshotxml2xmltest.c:222) ==32176==by 0x42174D: virtTestMain (testutils.c:782) ==32176== ==32176== 128 (96 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 51 of 66 ==32176==at 0x4A06BE0: realloc (vg_replace_malloc.c:662) ==32176==by 0x4C65A07: virReallocN (viralloc.c:243) ==32176==by 0x4C65B2E: virExpandN (viralloc.c:292) ==32176==by 0x4C65E30: virInsertElementsN (viralloc.c:434) ==32176==by 0x4CD71F3: virDomainDiskSourceDefParse (domain_conf.c:5078) ==32176==by 0x4CF6EF4: virDomainSnapshotDefParseNode (snapshot_conf.c:151) ==32176==by 0x4CF7314: virDomainSnapshotDefParseString (snapshot_conf.c:410) ==32176==by 0x41FB8D: testCompareXMLToXMLHelper (domainsnapshotxml2xmltest.c:100) ==32176==by 0x420FD1: virtTestRun (testutils.c:199) ==32176==by 0x41F859: mymain (domainsnapshotxml2xmltest.c:222) ==32176==by 0x42174D: virtTestMain (testutils.c:782) ==32176==by 0x3E6CE1ED1C: (below main) (libc-start.c:226) ==32176== --- src/conf/snapshot_conf.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 12b0930..475525f 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -82,6 +82,7 @@ virDomainSnapshotDiskDefClear(virDomainSnapshotDiskDefPtr disk) { VIR_FREE(disk-name); VIR_FREE(disk-file); +virDomainDiskHostDefFree(disk-nhosts, disk-hosts); } void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def) -- 1.7.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH] Fix memory leak in virSCSIDeviceListDel()
While running virscsitest, it was found that valgrind pointed out the following memory leak: ==320== 5 bytes in 1 blocks are definitely lost in loss record 4 of 37 ==320==at 0x4A069EE: malloc (vg_replace_malloc.c:270) ==320==by 0x3E6CE81171: strdup (strdup.c:43) ==320==by 0x4CB28DF: virStrdup (virstring.c:554) ==320==by 0x4CAC987: virSCSIDeviceSetUsedBy (virscsi.c:289) ==320==by 0x402321: test2 (virscsitest.c:100) ==320==by 0x403231: virtTestRun (testutils.c:199) ==320==by 0x402121: mymain (virscsitest.c:180) ==320==by 0x4039AD: virtTestMain (testutils.c:782) ==320==by 0x3E6CE1ED1C: (below main) (libc-start.c:226) ==320== --- src/util/virscsi.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/util/virscsi.c b/src/util/virscsi.c index acc3815..2f469f2 100644 --- a/src/util/virscsi.c +++ b/src/util/virscsi.c @@ -435,6 +435,7 @@ virSCSIDeviceListDel(virSCSIDeviceListPtr list, for (i = 0; i dev-n_used_by; i++) { if (STREQ_NULLABLE(dev-used_by[i], name)) { if (dev-n_used_by 1) { +VIR_FREE(dev-used_by[i]); VIR_DELETE_ELEMENT(dev-used_by, i, dev-n_used_by); } else { tmp = virSCSIDeviceListSteal(list, dev); -- 1.7.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCH v3] Add helper program to create custom leases
+ * + * Copyright (C) 2014 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * http://www.gnu.org/licenses/. + * + * Author: Nehal J Wani nehaljw.k...@gmail.com + */ + +#include config.h + +#include stdio.h +#include stdlib.h +#include sys/stat.h + +#include virutil.h +#include virthread.h +#include virfile.h +#include virbuffer.h +#include virstring.h +#include virerror.h +#include viralloc.h +#include virjson.h +#include configmake.h + +#define VIR_FROM_THIS VIR_FROM_NETWORK + +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (2 * 1024 * 1024) + +static const char *program_name; + +/* Display version information. */ +static void +helperVersion(const char *argv0) +{ +printf(%s (%s) %s\n, argv0, PACKAGE_NAME, PACKAGE_VERSION); +} + +ATTRIBUTE_NORETURN static void +usage(int status) +{ +if (status) { +fprintf(stderr, _(%s: try --help for more details\n), program_name); +} else { +printf(_(Usage: %s ACTION MAC|CLIENTID IP HOSTNAME\n +or: %s ACTION MAC|CLIENTID IP\n), + program_name, program_name); +} +exit(status); +} + +static int +customLeaseRewriteFile(int fd, void *opaque) +{ +char **data = opaque; + +if (safewrite(fd, *data, strlen(*data)) 0) +return -1; + +return 0; +} + +int +main(int argc, char **argv) +{ +char *lease_entries = NULL; +char *custom_lease_file = NULL; +const char *ip = NULL; +const char *mac = NULL; +const char *action = NULL; +const char *iaid = virGetEnvAllowSUID(DNSMASQ_IAID); +const char *clientid = virGetEnvAllowSUID(DNSMASQ_CLIENT_ID); +const char *interface = virGetEnvAllowSUID(DNSMASQ_INTERFACE); +const char *exptime = virGetEnvAllowSUID(DNSMASQ_LEASE_EXPIRES); +const char *hostname = virGetEnvAllowSUID(DNSMASQ_SUPPLIED_HOSTNAME); +const char *leases_str = NULL; +long long expirytime = 0; +size_t i = 0; +int rv = EXIT_FAILURE; +int size = 0; +int custom_lease_file_len = 0; +bool add = false; +bool delete = false; +virJSONValuePtr lease_new = NULL; +virJSONValuePtr lease_tmp = NULL; +virJSONValuePtr leases_array = NULL; +virJSONValuePtr leases_array_new = NULL; + +virSetErrorFunc(NULL, NULL); +virSetErrorLogPriorityFunc(NULL); + +program_name = argv[0]; + +if (setlocale(LC_ALL, ) == NULL || +bindtextdomain(PACKAGE, LOCALEDIR) == NULL || +textdomain(PACKAGE) == NULL) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +if (virThreadInitialize() 0 || +virErrorInitialize() 0) { +fprintf(stderr, _(%s: initialization failed\n), program_name); +exit(EXIT_FAILURE); +} + +/* Doesn't hurt to check */ +if (argc 1) { +if(STREQ(argv[1], --help)) +usage(EXIT_SUCCESS); + +if (STREQ(argv[1], --version)) { +helperVersion(argv[0]); +exit(EXIT_SUCCESS); +} +} + +if (argc != 4 argc != 5) { +/* Refer man page of dnsmasq --dhcp-script for more details */ +usage(EXIT_FAILURE); +} + +/* Make sure dnsmasq knows the interface. The interface name is not known + * when dnsmasq (re)starts and throws 'del' events for expired leases. + * So, if any old lease has expired, it will be automatically removed the + * next time this program is invoked */ +if (!interface) +goto cleanup; + +ip = argv[3]; +mac = argv[2]; +action = argv[1]; + +/* In case hostname is known, it is the 5th argument */ +if (argc == 5) + hostname = argv[4]; + +if (virAsprintf(custom_lease_file, %s/%s.status, LOCALSTATEDIR +/lib/libvirt/dnsmasq/, interface) 0) +goto cleanup; + +/* Check if it is an IPv6 lease */ +if (virGetEnvAllowSUID(DNSMASQ_IAID)) { +mac = virGetEnvAllowSUID(DNSMASQ_MAC); +clientid=argv[2]; +} + +/* Since interfaces can be hot plugged, we need to make sure that the + * corresponding custom lease file exists. If not, 'touch' it */ +if (virFileTouch(custom_lease_file, 0644) 0) +goto cleanup; + +/* Read entire contents */ +if ((custom_lease_file_len = virFileReadAll(custom_lease_file
Re: [libvirt] [PATCH v3] Add helper program to create custom leases
On Mon, Feb 24, 2014 at 5:27 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports dhcpv4 and dhcpv6. The file is saved as interface-name.status. Each lease contains the following info: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: [ { iaid: 1221229, ip-address: 2001:db8:ca2:2:1::95, mac-address: 52:54:00:12:a2:6d, hostname: Fedora20, client-id: 00:04:1a:c1:d9:6b:5a:0a:e2:bc:f8:4b:1e:37:2e:38:22:55, expiry-time: 1393244216 }, { ip-address: 192.168.150.208, mac-address: 52:54:00:11:56:b3, hostname: Wani-PC, client-id: 01:52:54:00:11:56:b3, expiry-time: 1393244248 } ] src/Makefile.am: * Add options to compile the helper program src/network/bridge_driver.c: * Introduce networkDnsmasqLeaseFileNameCustom() * Invoke helper program along with dnsmasq * Delete the .status file when corresponding n/w is destroyed. src/util/leaseshelper.c * Helper program to create the custom lease file --- v3: * Improved file handling, removed redundant copying, introduced --help and --version v2: * Changed format to JSON * Refer: https://www.redhat.com/archives/libvir-list/2014-January/msg01234.html v1: * Refer: https://www.redhat.com/archives/libvir-list/2014-January/msg00626.html src/Makefile.am | 16 +++ src/network/bridge_driver.c | 19 +++ src/util/leaseshelper.c | 303 +++ 3 files changed, 338 insertions(+), 0 deletions(-) create mode 100644 src/util/leaseshelper.c Ping! -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] Fix memory leak in virDomainSnapshotDiskDefClear()
--- src/conf/snapshot_conf.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 12b0930..475525f 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -82,6 +82,7 @@ virDomainSnapshotDiskDefClear(virDomainSnapshotDiskDefPtr disk) { VIR_FREE(disk-name); VIR_FREE(disk-file); +virDomainDiskHostDefFree(disk-nhosts, disk-hosts); This leaves nhosts and hosts at their original values, which seems to be OK everywhere this function is called, but it might be a problem if someone tries to reuse the disk definition instead of freeing it. I'd rather write this as: while (disk-nhosts) virDomainDiskHostDefClear(disk-hosts[--def-nhosts]) VIR_FREE(disk-hosts) Jan 1. Since virDomainDiskHostDefFree() already calls VIR_FREE(hosts), shouldn't the modified patch just be: diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 12b0930..a233e8e 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -82,6 +82,8 @@ virDomainSnapshotDiskDefClear(virDomainSnapshotDiskDefPtr disk) { VIR_FREE(disk-name); VIR_FREE(disk-file); +virDomainDiskHostDefFree(disk-nhosts, disk-hosts); +disk-nhosts = 0; } void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def) 2. I have a question. Why don't we have disk-nhosts = 0; each time someone calls virDomainDiskHostDefFree(disk-nhosts, disk-hosts) in ./src/conf/domain_conf.c, ./src/storage/storage_driver.c and ./src/qemu/qemu_conf.c? Or we can change the definition of virDomainDiskHostDefFree to virDomainDiskHostDefFree(size_t *nhosts, virDomainDiskHostDefPtr hosts) and make *nhosts = 0 inside the function itself and make the necessary changes wherever this function is called? -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH v3] Add helper program to create custom leases
On Tue, Mar 4, 2014 at 12:18 AM, Nehal J Wani nehaljw.k...@gmail.com wrote: On Mon, Feb 24, 2014 at 5:27 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: Introduce helper program to catch events from dnsmasq and maintain a custom lease file per network. It supports dhcpv4 and dhcpv6. The file is saved as interface-name.status. Each lease contains the following info: expiry-time (epoch time) mac iaid ip-address hostname clientid Example of custom leases file content: [ { iaid: 1221229, ip-address: 2001:db8:ca2:2:1::95, mac-address: 52:54:00:12:a2:6d, hostname: Fedora20, client-id: 00:04:1a:c1:d9:6b:5a:0a:e2:bc:f8:4b:1e:37:2e:38:22:55, expiry-time: 1393244216 }, { ip-address: 192.168.150.208, mac-address: 52:54:00:11:56:b3, hostname: Wani-PC, client-id: 01:52:54:00:11:56:b3, expiry-time: 1393244248 } ] src/Makefile.am: * Add options to compile the helper program src/network/bridge_driver.c: * Introduce networkDnsmasqLeaseFileNameCustom() * Invoke helper program along with dnsmasq * Delete the .status file when corresponding n/w is destroyed. src/util/leaseshelper.c * Helper program to create the custom lease file --- v3: * Improved file handling, removed redundant copying, introduced --help and --version v2: * Changed format to JSON * Refer: https://www.redhat.com/archives/libvir-list/2014-January/msg01234.html v1: * Refer: https://www.redhat.com/archives/libvir-list/2014-January/msg00626.html src/Makefile.am | 16 +++ src/network/bridge_driver.c | 19 +++ src/util/leaseshelper.c | 303 +++ 3 files changed, 338 insertions(+), 0 deletions(-) create mode 100644 src/util/leaseshelper.c Ping! Ping! -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv3 2/4] net-dhcp-leases: Implement the remote protocol
+static int +remoteSerializeNetworkDHCPLeases(virNetworkDHCPLeasesPtr *leases, + int nleases, + remote_network_get_dhcp_leases_ret *ret) +{ +size_t i; + +if (nleases REMOTE_NETWORK_DHCP_LEASES_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of leases is %d, which exceeds max limit: %d), + nleases, REMOTE_NETWORK_DHCP_LEASES_MAX); +return -1; +} + +if (VIR_ALLOC_N(ret-leases.leases_val, nleases) 0) +return -1; + +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: +for (i = 0; i nleases; i++) { +remote_network_dhcp_lease *lease_ret = (ret-leases.leases_val[i]); +virNetworkDHCPLeaseFree((virNetworkDHCPLeasesPtr)lease_ret); [1] +} +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); +virNetworkFree(net); +return rv; +} + +static int +remoteDispatchNetworkGetDHCPLeasesForMAC(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_for_mac_args *args, + remote_network_get_dhcp_leases_for_mac_ret *ret) +{ +int rv = -1; +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) [2] +goto cleanup; + +rv = nleases; + I am a little skeptical about the typecasts involved in [1] and [2] Specifically for [2], although the APIs are different, the struct is same, only the name is different. But, what would be the other options? One option: (Suggested by Osier) Change remoteSerializeNetworkDHCPLeases to +remoteSerializeNetworkDHCPLeases(virNetworkDHCPLeasesPtr *leases, + int nleases, + (void *) ret, + int method) where the datatype for variable in which ret will be copied, will be decided based on the method (method's value will be taken from an enum or something similar, e.g: 1-DHCPLeases, 2-DHCPLeasesForMAC) OR Second Option: Since the APIs should be independent, make another function: remoteSerializeNetworkDHCPLeasesForMAC(...), but that will lead to code redundancy. Eric, what would you do in
Re: [libvirt] [PATCHv3 1/4] net-dhcp-leases: Implement the public APIs
On Mon, Sep 16, 2013 at 8:55 PM, Daniel P. Berrange berra...@redhat.com wrote: On Mon, Sep 16, 2013 at 08:45:09PM +0530, Nehal J Wani wrote: PFA: Diff On Mon, Sep 16, 2013 at 8:44 PM, Nehal J Wani nehaljw.k...@gmail.com wrote: On Mon, Sep 16, 2013 at 3:22 PM, Daniel P. Berrange berra...@redhat.com wrote: On Mon, Sep 16, 2013 at 11:19:13AM +0530, Nehal J Wani wrote: +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__); Don't pass __FUNCTION__ in this error message - that is already done automatically +goto error; +} 'mac' should be a mandatory parameter here. Attached diff should fix it. No, it makes it worse - you're now allowing a NULL mac parameter to be passed to virMacAddrParse which will cause a segv. You need to be checking for mac == NULL with virCheckNonNullArg I think you missed this, I am already using virCheckNonNullArg : +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; 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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] build: ensure 'make check' sees up-to-date config.h
On Thu, Sep 19, 2013 at 4:02 AM, Eric Blake ebl...@redhat.com wrote: Nehal J. Wani reported on IRC a rather interesting build failure: In file included from util/virnetdevbridge.c:53:0: /usr/include/linux/in6.h:30:8: error: redefinition of 'struct in6_addr' struct in6_addr { ^ I traced it to the fact that he ran 'git pull; make check' across commit e62e0094. What happened is that the configure changes result in a new variable that was set to be defined on his system, but config.h was not regenerated to contain the value of that variable. Running 'make' instead of 'make check' cleaned up the problem. A bit more investigation, and I see that in Makefile.am, automake sticks rules that rebuild config.h as part of 'make all', and that we also had a dependency 'check-local: all'; BUT the rule for check-local is run only at the point when the top-level directory is visited. Automake documents that SUBDIRS should contain an explicit '.' at the point the top-level should be visited (defaulting to last, if it doesn't appear). Sure enough, with this patch, 'make check' now does the top-level 'all' rules, which regenerates 'config.h' BEFORE compiling any code that might depend on changed content of that file. * Makefile.am (SUBDIRS): Put '.' first, not last. Signed-off-by: Eric Blake ebl...@redhat.com --- Tough to argue the build-breaker rule on this one, since a fresh checkout doesn't hit it (only a 'make check' without a 'make', across an incremental build that happened to need new configure substitutions). So I'll wait for a review for my one-liner. Makefile.am |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Makefile.am b/Makefile.am index 4e24ecf..66cb677 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ LCOV = lcov GENHTML = genhtml -SUBDIRS = gnulib/lib include src daemon tools docs gnulib/tests \ +SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ python tests po examples/domain-events/events-c examples/hellolibvirt \ examples/dominfo examples/domsuspend examples/python examples/apparmor \ examples/xml/nwfilter examples/openauth examples/systemtap -- 1.7.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list Ping. If there is a specific reason why this was not pushed, I would like to know. Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] build: ensure 'make check' sees up-to-date config.h
On Mon, Sep 23, 2013 at 9:13 PM, Eric Blake ebl...@redhat.com wrote: On 09/23/2013 09:07 AM, Nehal J Wani wrote: On Thu, Sep 19, 2013 at 4:02 AM, Eric Blake ebl...@redhat.com wrote: Nehal J. Wani reported on IRC a rather interesting build failure: In file included from util/virnetdevbridge.c:53:0: /usr/include/linux/in6.h:30:8: error: redefinition of 'struct in6_addr' struct in6_addr { ^ * Makefile.am (SUBDIRS): Put '.' first, not last. Signed-off-by: Eric Blake ebl...@redhat.com --- Tough to argue the build-breaker rule on this one, since a fresh checkout doesn't hit it (only a 'make check' without a 'make', across an incremental build that happened to need new configure substitutions). So I'll wait for a review for my one-liner. Ping. If there is a specific reason why this was not pushed, I would like to know. Pong - no one has reviewed it. Did it work for you? If so, state that, and your review will serve as enough for me to push it :) Running 'make' and then 'make check' worked for me. So, I guess there is no problem in pushing this patch. -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv4 0/4] Introduce APIs to extract DHCP leases info
This API returns the leases information stored in the DHCP leases file of dnsmasq for a given virtual network. It contacts the bridge network driver, which parses 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 v4 * Added support for DHCPv6, updated lease file parsing method v3 * Mostly small nits, change in MACRO names, use of virSocketAddrGetIpPrefix to retrieve IP prefix from @dom XML. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00832.html v2 * Since DHCPv6 is supposed to be suported in future, virNetworkGetDHCPLeasesForMAC changed, prefix and virIPAddrType added in virNetworkDHCPLeases struct. Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00732.html v1 * Refer: https://www.redhat.com/archives/libvir-list/2013-September/msg00620.html * The need for these APIs were result of a RFC was proposed on the list. Refer: http://www.redhat.com/archives/libvir-list/2013-July/msg01603.html Nehal J Wani (4): net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Implement the remote protocol net-dhcp-leases: Private implementation inside network driver net-dhcp-leases: Add virsh support daemon/remote.c | 157 include/libvirt/libvirt.h.in | 36 +++ python/generator.py | 3 + src/driver.h | 13 +++ src/libvirt.c| 177 +++ src/libvirt_public.syms | 3 + src/network/bridge_driver.c | 240 +++ src/remote/remote_driver.c | 169 +- src/remote/remote_protocol.x | 59 ++- src/remote_protocol-structs | 47 + src/rpc/gendispatch.pl | 1 + tools/virsh-network.c| 150 +++ tools/virsh.pod | 6 ++ 13 files changed, 1057 insertions(+), 4 deletions(-) -- 1.7.11.7 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
[libvirt] [PATCHv4 2/4] net-dhcp-leases: Implement the remote protocol
Implement RPC calls for virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeasesForMAC * Define helper function make_dhcp_lease src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeasesForMAC * Define helper function make_dhcp_lease 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 | 157 src/remote/remote_driver.c | 169 ++- src/remote/remote_protocol.x | 59 ++- src/remote_protocol-structs | 47 src/rpc/gendispatch.pl | 1 + 5 files changed, 429 insertions(+), 4 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 9497cc1..770f62a 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -88,6 +88,7 @@ static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNod static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src); static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src); static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src); +static void make_dhcp_lease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasesPtr lease_src); static virTypedParameterPtr remoteDeserializeTypedParameters(remote_typed_param *args_params_val, @@ -5209,6 +5210,136 @@ cleanup: } +static int +remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_args *args, + remote_network_get_dhcp_leases_ret *ret) +{ +int rv = -1; +size_t i; +struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); +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, + args-need_results ? leases : NULL, + args-flags)) 0) +goto cleanup; + +if (nleases REMOTE_NETWORK_DHCP_LEASES_MAX) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of leases is %d, which exceeds max limit: %d), + nleases, REMOTE_NETWORK_DHCP_LEASES_MAX); +return -1; +} + +if (leases nleases) { +if (VIR_ALLOC_N(ret-leases.leases_val, nleases) 0) +goto cleanup; + +ret-leases.leases_len = nleases; +for (i = 0; i nleases; i++) +make_dhcp_lease(ret-leases.leases_val + i, leases[i]); +} else { +ret-leases.leases_len = 0; +ret-leases.leases_val = NULL; +} + +ret-ret = nleases; + +rv = 0; + +cleanup: +if (rv 0) +virNetMessageSaveError(rerr); +if (leases) { +for (i = 0; i nleases; i++) +virNetworkDHCPLeaseFree(leases[i]); +VIR_FREE(leases); +} +virNetworkFree(net); +return rv; +} + + +static int +remoteDispatchNetworkGetDHCPLeasesForMAC(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_network_get_dhcp_leases_for_mac_args *args, + remote_network_get_dhcp_leases_for_mac_ret *ret) +{ +int rv = -1; +size_t i; +struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); +virNetworkDHCPLeasesPtr *leases = NULL; +virNetworkPtr net = NULL; +int nleases = 0; +
[libvirt] [PATCHv4 3/4] net-dhcp-leases: Private implementation inside network driver
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 | 240 1 file changed, 240 insertions(+) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 8787bdb..e1c97c7 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -109,6 +109,29 @@ static int networkPlugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); static int networkUnplugBandwidth(virNetworkObjPtr net, virDomainNetDefPtr iface); +/** + * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX: + * + * Macro providing the upper limit on the size of leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152 + +/** + * VIR_NETWORK_DHCP_LEASE_FIELDS: + * + * Macro providing the maximum number of fields in an entry in + * the leases file + */ +#define VIR_NETWORK_DHCP_LEASE_FIELDS 5 + +/** + * VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS: + * + * Macro providing the maximum number of fields in the separator + * line in the DHCPv6 leases file + */ +#define VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS 2 + static virNetworkDriverStatePtr driverState = NULL; @@ -2988,6 +3011,221 @@ cleanup: return ret; } +/* This function parses the leases file of dnsmasq. + * + * An example of DHCPv4 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 * * + * + * An example of DHCPv6 leases file content: + * + * 1380150262 52:54:00:2e:1d:22 192.168.122.80 * * + * 1380152517 52:54:00:72:0f:1e 192.168.122.119 * * + * duid 00:01:00:01:19:d3:ec:62:f0:4d:a2:8c:14:51 + * 1380152445 3022114 2001:db8:ca2:2:1::92 * 00:01:00:01:19:d6:0c:59:52:54:00:2e:1d:22 + * 1380152453 7474974 2001:db8:ca2:2:1::4e * 00:01:00:01:19:d5:e0:86:52:54:00:72:0f:1e + * + */ +static int +networkGetDHCPLeasesHelper(virNetworkPtr network, + virNetworkObjPtr obj, + const char *mac, + virNetworkDHCPLeasesPtr **leases) +{ +int rv = -1; +size_t i = 0; +size_t nleases = 0; +char *lease_file = NULL; +char **lease_fields = NULL; +char *lease_entries = NULL; +char *lease_entry = NULL; +virNetworkDHCPLeasesPtr *leases_ret = NULL; +virNetworkDHCPLeasesPtr lease = NULL; +int lease_file_len = 0; +bool ipv6 = false; +bool need_results = !!leases; + +/* Retrieve leases file location */ +lease_file = networkDnsmasqLeaseFileNameDefault(network-name); + +if ((lease_file_len = virFileReadAll(lease_file, +VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX, +lease_entries)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Unable to read leases file: %s), lease_file); +goto cleanup; +} + +lease_entry = lease_entries[0] == '\0' ? NULL : lease_entries; + +while (lease_entry) { +int nfields = 0; + +char *eol = strchr(lease_entry, '\n'); +*eol = '\0'; + +/* Split the lease line */ +if (!(lease_fields = virStringSplit(lease_entry, , +VIR_NETWORK_DHCP_LEASE_FIELDS))) +goto error; + +nfields = virStringListLength(lease_fields); + +/* Forward lease_entry to the next lease */ +lease_entry = strchr(lease_entry, '\0'); +if (lease_entry - lease_entries + 1 lease_file_len) +lease_entry++; +else +lease_entry = NULL; + +/* Ignore the separator line in case of DHCPv6 */ +if (nfields == VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS + STREQ(lease_fields[0], duid)) { +ipv6 = true; +virStringFreeList(lease_fields); +continue; +} + +if (nfields != VIR_NETWORK_DHCP_LEASE_FIELDS) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Number of lease params aren't equal to: %d), + VIR_NETWORK_DHCP_LEASE_FIELDS); +goto error; +} + +if (mac virMacAddrCompare(mac, lease_fields[1])) { +virStringFreeList(lease_fields); +continue; +} + +if (need_results) { +if (VIR_ALLOC(lease) 0) +goto error; + +/* Convert expirytime here */ +if (virStrToLong_ll(lease_fields[0], NULL, 10, (lease-expirytime)) 0) { +virReportError(VIR_ERR_INTERNAL_ERROR, + _(Unable to convert lease expiry time to integer: %s), + lease_fields[0]); +goto error; +
[libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC and virNetworkDHCPLeaseFree. * virNetworkGetDHCPLeases: returns the dhcp leases information for a given virtual network. For DHCPv4, the information includes: - Expirytime - MAC Address - IPv4 address (with type and prefix) - Hostname (can be NULL) - Client ID (can be NULL) For DHCPv6, the information includes - Expirytime - IAID - IPv6 address (with type and prefix) - Hostname (can be NULL) - Client DUID * 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 --- include/libvirt/libvirt.h.in | 36 + python/generator.py | 3 + src/driver.h | 13 src/libvirt.c| 177 +++ src/libvirt_public.syms | 3 + 5 files changed, 232 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 83c219e..557a4c1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2800,6 +2800,42 @@ 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; /* Seconds since epoch */ +union { +char *mac; /* MAC address */ +unsigned long iaid; /* Identity association identifier (IAID) */ +} id; +char *ipaddr; /* IP address */ +char *hostname; /* Hostname */ +char *clientid; /* Client ID or DUID */ +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 12c14f1..1079d6c 100755 --- a/python/generator.py +++ b/python/generator.py @@ -461,6 +461,8 @@ skip_impl = ( 'virNodeGetCPUMap', 'virDomainMigrate3', 'virDomainMigrateToURI3', +'virNetworkGetDHCPLeases', +'virNetworkGetDHCPLeasesForMAC', ) lxc_skip_impl = ( @@ -561,6 +563,7 @@ skip_function = ( virTypedParamsGetString, virTypedParamsGetUInt, virTypedParamsGetULLong, +'virNetworkDHCPLeaseFree', ) lxc_skip_function = ( diff --git a/src/driver.h b/src/driver.h index 8cd164a..e000b17 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1127,6 +1127,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; @@ -1458,6 +1469,8 @@ struct _virNetworkDriver
[libvirt] [PATCHv4 4/4] net-dhcp-leases: Add virsh support
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 default6 Expiry Time MAC address / IAIDProtocol IP address Hostname Client ID / DUID --- 2013-09-26 12:46:15 140483776435424 ipv6 2001:db8:ca2:2:1::92/24 (null) 00:01:00:01:19:d6:0c:59:52:54:00:2e:1d:22 2013-09-26 12:26:29 140483776438128 ipv6 2001:db8:ca2:2:1::4e/24 (null) 00:01:00:01:19:d5:e0:86:52:54:00:72:0f:1e 2013-09-26 12:34:31 52:54:00:2e:1d:22 ipv4 192.168.122.80/24 (null) (null) 2013-09-26 12:13:24 52:54:00:72:0f:1e ipv4 192.168.122.119/24(null) (null) tools/virsh.pod * Document new command --- tools/virsh-network.c | 150 ++ tools/virsh.pod | 6 ++ 2 files changed, 156 insertions(+) diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8ddd5ca..5786ca2 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1129,6 +1129,150 @@ 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 int +vshNetworkDHCPLeaseSorter(const void *a, const void *b) +{ +char *id1 = NULL; +char *id2 = NULL; +int rv = -1; + +virNetworkDHCPLeasesPtr *lease1 = (virNetworkDHCPLeasesPtr *) a; +virNetworkDHCPLeasesPtr *lease2 = (virNetworkDHCPLeasesPtr *) b; + +if (*lease1 !*lease2) +return -1; + +if (!*lease1) +return *lease2 != NULL; + + +switch ((*lease1)-type) { +case VIR_IP_ADDR_TYPE_IPV4: +ignore_value(virAsprintf(id1, %s, (*lease1)-id.mac)); +break; +case VIR_IP_ADDR_TYPE_IPV6: +ignore_value(virAsprintf(id1, %lu, (*lease1)-id.iaid)); +break; +} +switch ((*lease2)-type) { +case VIR_IP_ADDR_TYPE_IPV4: +ignore_value(virAsprintf(id2, %s, (*lease2)-id.mac)); +break; +case VIR_IP_ADDR_TYPE_IPV6: +ignore_value(virAsprintf(id2, %lu, (*lease2)-id.iaid)); +break; +} + +rv = vshStrcasecmp(id1, id2); +VIR_FREE(id1); +VIR_FREE(id2); +return rv; +} + +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) +return false; + +if (!(network = vshCommandOptNetwork(ctl, cmd, name))) +return false; + +nleases = mac ? virNetworkGetDHCPLeasesForMAC(network, mac, leases, flags) +: virNetworkGetDHCPLeases(network, leases, flags); + +if (nleases 0) { +vshError(ctl, _(Failed to get leases info for %s), name); +goto cleanup; +} + +/* Sort the list according to MAC Address/IAID */ +qsort(leases, nleases, sizeof(*leases), vshNetworkDHCPLeaseSorter); + +vshPrintExtra(ctl, %-20s %-25s %-10s %-25s %-12s %s\n%s%s\n, + _(Expiry Time), _(MAC address / IAID), _(Protocol), + _(IP address), _(Hostname), _(Client ID / DUID), + --, + -); + +for (i = 0; i nleases; i++) { +const char *type = NULL; +char *id = NULL; +char *cidr_format = 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), %Y-%m-%d %H:%M:%S, ts); + +switch (lease-type) { +case VIR_IP_ADDR_TYPE_IPV4: +type = ipv4; +ignore_value(virAsprintf(id, %s, lease-id.mac)); +
Re: [libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
Since we have lost the train for 1.1.3, changes in a/src/libvirt_public.syms attached. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 1.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 2/4] net-dhcp-leases: Implement the remote protocol
In accordance with latest changes in rules for making building src/remote_protocol-structs, diff attached. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 2.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 3/4] net-dhcp-leases: Private implementation inside network driver
Removing redundant if, diff attached. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 3.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 4/4] net-dhcp-leases: Add virsh support
In accordance with latest rule: use VIR_STRDUP instead of virAsprintf with %s Diff attached. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 4.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 4/4] net-dhcp-leases: Add virsh support
Rectified attachment. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 4.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
Rectified attachment. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 1.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 3/4] net-dhcp-leases: Private implementation inside network driver
Rectified attachment. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 3.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 2/4] net-dhcp-leases: Implement the remote protocol
Rectified attachment. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad 2.diff Description: Binary data -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
I sense some struggle in getting the interface right - for everyone's sake, let's FIRST get the interface nailed down, rather than churning on implementations of something that then has to be reworked because the interface wasn't correct. Agreed. I hope we can have some discussion on whether we should be supporting DHCPv6 or not, and how should IAID be exposed, if we do. -- Nehal J Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
According to commit 2d5cd1d724084d9975b2514fb31776627acbe997, libvirt supports DHCPv6. The virNetworkGetDHCPLeases API doesn't mention anywhere (in its name) that it is specific to DHCPv4. Hence I thought of adding the support for DHCPv6. Since the format for DHCPv6 leases is a bit different, it might be difficult to add it in the future by modifying the API. To understand the format for DHCPv6 better, one can follow the conversation: http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2013q3/007538.html and the RFC: https://tools.ietf.org/html/rfc3315 -- Nehal J Wani -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCHv4 1/4] net-dhcp-leases: Implement the public APIs
On Wed, Oct 2, 2013 at 1:43 PM, Daniel P. Berrange berra...@redhat.com wrote: On Tue, Oct 01, 2013 at 05:39:02PM -0600, Eric Blake wrote: On 09/26/2013 02:08 AM, Nehal J Wani wrote: Introduce 3 new APIs, virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC and virNetworkDHCPLeaseFree. * virNetworkGetDHCPLeases: returns the dhcp leases information for a given virtual network. For DHCPv4, the information includes: - Expirytime - MAC Address - IPv4 address (with type and prefix) - Hostname (can be NULL) - Client ID (can be NULL) For DHCPv6, the information includes - Expirytime - IAID - IPv6 address (with type and prefix) - Hostname (can be NULL) - Client DUID * 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. +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases; +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr; +struct _virNetworkDHCPLeases { +long long expirytime; /* Seconds since epoch */ +union { +char *mac; /* MAC address */ +unsigned long iaid; /* Identity association identifier (IAID) */ +} id; I'm not sure I like iaid - the whole point of this interface was to return IP addresses associated with a MAC. Either the iaid is important and deserves a separate field, or all we care about is the MAC address. Not to mention that you didn't document which leg of the id union is valid based on the type discriminator. Agreed, we want the MAC address to be unconditionally available here. IMHO the IAID is not something we care about exposing. That is a impl detail of the DHCP comms protocol that is not useful to people outside. So in case DHCPv6 is used by the client, should we report the rest of the lease fields and report MAC as NULL? 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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list