[libvirt] [PATCHv5 1/4] net-dhcp-leases: Implement the public APIs
Nehal J Wani
nehaljw.kkd1 at gmail.com
Thu Dec 12 12:30:17 UTC 2013
On Thu, Dec 12, 2013 at 5:14 PM, Daniel P. Berrange <berrange at redhat.com> wrote:
> On Tue, Nov 26, 2013 at 02:35:58AM +0530, Nehal J Wani wrote:
>> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
>> index 5aad75c..20ea40a 100644
>> --- a/include/libvirt/libvirt.h.in
>> +++ b/include/libvirt/libvirt.h.in
>> +
>> +typedef struct _virNetworkDHCPLeases virNetworkDHCPLeases;
>> +typedef virNetworkDHCPLeases *virNetworkDHCPLeasesPtr;
>> +struct _virNetworkDHCPLeases {
>
> s/Leases/Lease/ - each struct only stores a single lease
>
>> + char *interface; /* Network interface name */
>> + long long expirytime; /* Seconds since epoch */
>> + int type; /* virIPAddrType */
>> + char *mac; /* MAC address */
>> + char *iaid; /* IAID */
>> + char *ipaddr; /* IP address */
>> + unsigned int prefix; /* IP address prefix */
>> + char *hostname; /* Hostname */
>> + char *clientid; /* Client ID or DUID */
>> +};
>
>> @@ -2019,6 +2022,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \
>> util/virtypedparam.c \
>> util/viruri.c \
>> util/virutil.c \
>> + util/virmacaddr.c \
>> util/viruuid.c \
>> conf/domain_event.c \
>> rpc/virnetsocket.c \
>
> Don't add this here.
The code didn't compile without making the above addition. It kept
throwing the error:
../src/.libs/libvirt-setuid-rpc-client.a(libvirt_setuid_rpc_client_la-libvirt.o):
In function `virNetworkGetDHCPLeasesForMAC':
/home/Wani/Hobby/libvirt/src/libvirt.c:22187: undefined reference to
`virMacAddrParse'
>
>> diff --git a/src/libvirt.c b/src/libvirt.c
>> index eff44eb..9a0b872 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"
>
>> +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();
>> +
>> + if (leases)
>> + *leases = NULL;
>> +
>> + virCheckNonNullArgGoto(mac, error);
>> +
>> + if (!VIR_IS_CONNECTED_NETWORK(network)) {
>> + virLibNetworkError(VIR_ERR_INVALID_NETWORK, __FUNCTION__);
>> + virDispatchError(NULL);
>> + return -1;
>> + }
>> +
>> + /* Validate the MAC address */
>> + if (virMacAddrParse(mac, &addr) < 0) {
>> + virReportInvalidArg(mac, "%s",
>> + _("Given MAC Address doesn't comply "
>> + "with the standard (IEEE 802) format"));
>> + goto error;
>> + }
>
> Don't do this here - it is the job of driver APIs todo semantic
> validation of parameters.
Do you mean, I need to put this check inside
networkGetDHCPLeasesForMAC in src/network/bridge_driver.c ?
>
>
>> diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
>> index fe9b497..f1a9707 100644
>> --- a/src/libvirt_public.syms
>> +++ b/src/libvirt_public.syms
>> @@ -639,4 +639,11 @@ LIBVIRT_1.1.3 {
>> virConnectGetCPUModelNames;
>> } LIBVIRT_1.1.1;
>>
>> +LIBVIRT_1.1.4 {
>> + global:
>> + virNetworkDHCPLeaseFree;
>> + virNetworkGetDHCPLeases;
>> + virNetworkGetDHCPLeasesForMAC;
>> +} LIBVIRT_1.1.3;
>
> Can move this into the 1.2.1 version block now.
>
>> +/*
>> + * Use this when passing possibly-NULL strings to printf-a-likes.
>> + */
>> +# define NULL_STR(s) ((s) ? (s) : "*")
>
> I'd suggest calling this EMPTY_STR to avoid confusion with
> the existing NULLSTR macro which prints "(null)"
>
>> +
>> +int
>> +main(int argc, char **argv) {
>> +
>> + /* Doesn't hurt to check */
>> + if (argc < 4)
>> + return -1;
>
> You should print an error message to stderr along with
> usage text.
>
>> +
>> + const char *action = argv[1];
>> + const char *interface = NULL_STR(getenv("DNSMASQ_INTERFACE"));
>> + const char *expirytime = NULL_STR(getenv("DNSMASQ_LEASE_EXPIRES"));
>> + const char *mac = argv[2];
>> + const char *ip = argv[3];
>> + const char *iaid = NULL_STR(getenv("DNSMASQ_IAID"));
>> + const char *hostname = NULL_STR(getenv("DNSMASQ_SUPPLIED_HOSTNAME"));
>> + const char *clientid = NULL_STR(getenv("DNSMASQ_CLIENT_ID"));
>
> All use of getenv is banned in libvirt code - please make sure
> to run 'make syntax-check' and 'make check'. Use virGetEnvAllowSUID
> here
I did run both the commands. Unfortunately, they didn't detect that I
had been using getenv().
>
>> + 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;
>> + virBuffer buf_new_lease = VIR_BUFFER_INITIALIZER;
>> + virBuffer buf_all_leases = VIR_BUFFER_INITIALIZER;
>
> You must call the following before invoking any other libvir
> APIs at all
>
> 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);
> }
>
>
Just a suggestion: It would be good if someone adds this to hacking.html
>> +
>> + if (virAsprintf(&lease_file, "%s/%s.status", LOCALSTATEDIR
>> + "/lib/libvirt/dnsmasq/", interface) < 0)
>> + goto cleanup;
>> +
>> + if (getenv("DNSMASQ_IAID")) {
>> + mac = NULL_STR(getenv("DNSMASQ_MAC"));
>> + clientid = argv[2];
>> + }
>> +
>> + /* Make sure the file exists. If not, 'touch' it */
>> + fp = fopen(lease_file, "a+");
>> + fclose(fp);
>
> We have a virFileTouch method todo this.
>
>> +
>> + /* 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 */
>> + virBufferAsprintf(&buf_new_lease, "%s %s %s %s %s %s\n",
>> + expirytime, mac, iaid, ip, hostname, clientid);
>> +
>> + if (virBufferError(&buf_new_lease)) {
>> + virBufferFreeAndReset(&buf_new_lease);
>> + virReportOOMError();
>> + 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 cleanup;
>> +
>> + 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;
>> +
>> + if (nfields != VIR_NETWORK_DHCP_LEASE_FIELDS)
>> + goto cleanup;
>> +
>> + if (delete && STREQ(lease_fields[3], ip))
>> + continue;
>> + else {
>> + virBufferAsprintf(&buf_all_leases, "%s %s %s %s %s %s\n",
>> + lease_fields[0], lease_fields[1], lease_fields[2],
>> + lease_fields[3], lease_fields[4], lease_fields[5]);
>> +
>> + if (virBufferError(&buf_all_leases)) {
>> + virBufferFreeAndReset(&buf_all_leases);
>> + virReportOOMError();
>> + goto cleanup;
>> + }
>> + }
>> + }
>> +
>> + if (add)
>> + virBufferAsprintf(&buf_all_leases, "%s", virBufferContentAndReset(&buf_new_lease));
>> +
>
> Need virBufferError check on buf_all_leases here
>
>> + rv = 0;
>> +
>> + /* Write to file */
>> + leases_str = virBufferContentAndReset(&buf_all_leases);
>> + if (!leases_str)
>> + leases_str = "";
>> +
>> + if (virFileWriteStr(lease_file, leases_str, 0) < 0)
>> + rv = -1;
>> +
>> +cleanup:
>> + VIR_FREE(lease_file);
>> + VIR_FREE(lease_entries);
>> + if (lease_fields)
>> + virStringFreeList(lease_fields);
>> + return rv;
>> +}
>
>
> I'd suggest that the lease helper program should be added in a separate
> patch from the public API, sine there's no real dependancy between
> them.
Would do that in the next series.
Thanks for reviewing the series. I'll continue to furnish them.
>
> 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
More information about the libvir-list
mailing list