This patch makes dnsmasq daemon started from libvirtd with a
--dhcp-hostsfile option instead of --dhcp-host options for each
'//ip/dhcp/host' entries defined in network xml file.
NOTE: I'm not sure where and when to save the dnsmasq hostsfile so that
make it saved in dnsmasq's local statedir when network is defined or
started in the meantime. Especially, I would like to get some advices
for this. (I'm afraid that NETWORK_STATE_DIR is inappropriate as
dnsmasq process will run as nobody and it will not be able to
read the saved hostsfile.)
Signed-off-by: Satoru SATOH <satoru.satoh(a)gmail.com>
---
src/network/bridge_driver.c | 78 +++++++++++++++++++++++++++++++++---------
1 files changed, 61 insertions(+), 17 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 83ab00e..59b0de9 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -57,10 +57,13 @@
#include "iptables.h"
#include "bridge.h"
#include "logging.h"
+#include "dnsmasq.h"
#define NETWORK_PID_DIR LOCAL_STATE_DIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCAL_STATE_DIR "/lib/libvirt/network"
+#define DNSMASQ_STATE_DIR LOCAL_STATE_DIR "/lib/dnsmasq"
+
#define VIR_FROM_THIS VIR_FROM_NETWORK
#define networkReportError(code, ...) \
@@ -361,6 +364,29 @@ networkShutdown(void) {
static int
+networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
+ dnsmasqContext *dctx,
+ int force)
+{
+ int r;
+
+ if (! force && virFileExists(dctx->hostsfile->path))
+ return 1;
+
+ for (r = 0 ; r < network->def->nhosts ; r++) {
+ virNetworkDHCPHostDefPtr host = &(network->def->hosts[r]);
+ if ((host->mac) && (host->ip))
+ dnsmasqAddDhcpHost(dctx, host->mac, host->ip, host->name);
+ }
+
+ if (dnsmasqSave(dctx) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+static int
networkBuildDnsmasqArgv(virNetworkObjPtr network,
const char *pidfile,
const char ***argv) {
@@ -401,8 +427,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
(2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
/* --dhcp-lease-max=xxx if needed */
(network->def->nranges ? 0 : 1) +
- /* --dhcp-host 01:23:45:67:89:0a,hostname,10.0.0.3 */
- (2 * network->def->nhosts) +
+ /* --dhcp-hostsfile=/var/lib/dnsmasq/$NAME.hostsfile */
+ (network->def->nhosts > 0 ? 1 : 0) +
/* --enable-tftp --tftp-root /srv/tftp */
(network->def->tftproot ? 3 : 0) +
/* --dhcp-boot pxeboot.img[,,12.34.56.78] */
@@ -473,22 +499,22 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
APPEND_ARG(*argv, i++, buf);
}
- for (r = 0 ; r < network->def->nhosts ; r++) {
- virNetworkDHCPHostDefPtr host = &(network->def->hosts[r]);
- if ((host->mac) && (host->name)) {
- snprintf(buf, sizeof(buf), "%s,%s,%s",
- host->mac, host->name, host->ip);
- } else if (host->mac) {
- snprintf(buf, sizeof(buf), "%s,%s",
- host->mac, host->ip);
- } else if (host->name) {
- snprintf(buf, sizeof(buf), "%s,%s",
- host->name, host->ip);
- } else
- continue;
+ if (network->def->nhosts > 0) {
+ dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
+ char *hostsfileArg;
- APPEND_ARG(*argv, i++, "--dhcp-host");
- APPEND_ARG(*argv, i++, buf);
+ if (dctx == NULL)
+ goto no_memory;
+
+ if (networkSaveDnsmasqHostsfile(network, dctx, 0)) {
+ if (virAsprintf(&hostsfileArg, "--dhcp-hostsfile=%s",
dctx->hostsfile->path) < 0) {
+ dnsmasqContextFree(dctx);
+ goto no_memory;
+ }
+ APPEND_ARG_LIT(*argv, i++, hostsfileArg);
+ }
+
+ dnsmasqContextFree(dctx);
}
if (network->def->tftproot) {
@@ -1294,6 +1320,15 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char
*xml) {
goto cleanup;
}
+ if (network->def->nhosts > 0) {
+ dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
+ if (dctx == NULL)
+ goto cleanup;
+
+ networkSaveDnsmasqHostsfile(network, dctx, 1);
+ dnsmasqContextFree(dctx);
+ }
+
ret = virGetNetwork(conn, network->def->name, network->def->uuid);
cleanup:
@@ -1329,6 +1364,15 @@ static int networkUndefine(virNetworkPtr net) {
network) < 0)
goto cleanup;
+ if (network->def->nhosts > 0) {
+ dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
+ if (dctx == NULL)
+ goto cleanup;
+
+ dnsmasqDelete(dctx);
+ dnsmasqContextFree(dctx);
+ }
+
virNetworkRemoveInactive(&driver->networks,
network);
network = NULL;
--
1.6.2.5