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; + } + + lease->type = ipv6 ? VIR_IP_ADDR_TYPE_IPV6 : VIR_IP_ADDR_TYPE_IPV4; + lease->prefix = virSocketAddrGetIpPrefix(&obj->def->ips->address, + &obj->def->ips->netmask, + obj->def->ips->prefix); + + if ((VIR_STRDUP(lease->id.mac, lease_fields[1]) < 0) || + (VIR_STRDUP(lease->ipaddr, lease_fields[2]) < 0)) + goto error; + + /* Only two fields, hostname and clientid can be NULL + * Refer: http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2013q3/007544.html + */ + if (STREQ(lease_fields[3], "*")) + lease->hostname = NULL; + else if (VIR_STRDUP(lease->hostname, lease_fields[3]) < 0) + goto error; + + if (STREQ(lease_fields[4], "*")) + lease->clientid = NULL; + else if (VIR_STRDUP(lease->clientid, lease_fields[4]) < 0) + goto error; + + if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0) + goto error; + } + else + nleases++; + + VIR_FREE(lease); + virStringFreeList(lease_fields); + } + + lease_fields = NULL; + + if (need_results && 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: + if (lease) + VIR_FREE(lease); + VIR_FREE(lease_file); + VIR_FREE(lease_entries); + if (lease_fields) + virStringFreeList(lease_fields); + return rv; + +error: + if (leases_ret) { + for (i = 0; i < nleases; i++) + virNetworkDHCPLeaseFree(leases_ret[i]); + VIR_FREE(leases_ret); + } + goto cleanup; +} + +static int +networkGetDHCPLeases(virNetworkPtr network, + virNetworkDHCPLeasesPtr **leases, + unsigned int flags) +{ + int rv = -1; + virNetworkObjPtr obj; + + virCheckFlags(0, -1); + + if (!(obj = networkObjFromNetwork(network))) + return rv; + + if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, NULL, leases); + +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); + + if (!(obj = networkObjFromNetwork(network))) + return rv; + + if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0) + goto cleanup; + + rv = networkGetDHCPLeasesHelper(network, obj, mac, leases); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return rv; +} static virNetworkDriver networkDriver = { "Network", @@ -3012,6 +3250,8 @@ static virNetworkDriver networkDriver = { .networkSetAutostart = networkSetAutostart, /* 0.2.1 */ .networkIsActive = networkIsActive, /* 0.7.3 */ .networkIsPersistent = networkIsPersistent, /* 0.7.3 */ + .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.3 */ + .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.1.3 */ }; static virStateDriver networkStateDriver = { -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list