On Thu, Dec 12, 2013 at 5:14 PM, Daniel P. Berrange <berrange(a)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.
--
Nehal J Wani