Add support for starting dnsmasq and a <dhcp> element to configure
the behaviour of the dhcp server.
Note, there's quite a bit more interesting stuff we can do with
dnsmasq to e.g. pre-define a set of mac <-> ip address mappings
but we can add that later.
Signed-off-by: Mark McLoughlin <markmc(a)redhat.com>
Index: libvirt-foo/qemud/conf.c
===================================================================
--- libvirt-foo.orig/qemud/conf.c 2007-02-14 15:59:02.000000000 +0000
+++ libvirt-foo.orig/qemud/conf.c 2007-02-14 15:59:02.000000000 +0000
@@ -1099,6 +1099,12 @@ struct qemud_vm *qemudLoadConfigXML(stru
void qemudFreeNetwork(struct qemud_network *network) {
+ struct qemud_dhcp_range_def *range = network->def.ranges;
+ while (range) {
+ struct qemud_dhcp_range_def *next = range->next;
+ free(range);
+ range = next;
+ }
free(network);
}
@@ -1177,11 +1183,61 @@ static int qemudParseBridgeXML(struct qe
return 1;
}
+static int qemudParseDhcpRangesXML(struct qemud_server *server,
+ struct qemud_network *network,
+ xmlNodePtr node) {
+
+ xmlNodePtr cur;
+
+ cur = node->children;
+ while (cur != NULL) {
+ struct qemud_dhcp_range_def *range;
+ xmlChar *start, *end;
+
+ if (cur->type != XML_ELEMENT_NODE ||
+ !xmlStrEqual(cur->name, BAD_CAST "range")) {
+ cur = cur->next;
+ continue;
+ }
+
+ if (!(range = calloc(1, sizeof(struct qemud_dhcp_range_def)))) {
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "range");
+ return 0;
+ }
+
+ start = xmlGetProp(cur, BAD_CAST "start");
+ end = xmlGetProp(cur, BAD_CAST "end");
+
+ if (start && start[0] && end && end[0]) {
+ strncpy(range->start, (const char *)start, BR_INET_ADDR_MAXLEN-1);
+ range->start[BR_INET_ADDR_MAXLEN-1] = '\0';
+
+ strncpy(range->end, (const char *)end, BR_INET_ADDR_MAXLEN-1);
+ range->end[BR_INET_ADDR_MAXLEN-1] = '\0';
+
+ range->next = network->def.ranges;
+ network->def.ranges = range;
+ network->def.nranges++;
+ } else {
+ free(range);
+ }
+
+ if (start)
+ xmlFree(start);
+ if (end)
+ xmlFree(end);
+
+ cur = cur->next;
+ }
+
+ return 1;
+}
static int qemudParseInetXML(struct qemud_server *server ATTRIBUTE_UNUSED,
struct qemud_network *network,
xmlNodePtr node) {
xmlChar *address, *netmask;
+ xmlNodePtr cur;
address = xmlGetProp(node, BAD_CAST "address");
if (address != NULL) {
@@ -1199,6 +1255,15 @@ static int qemudParseInetXML(struct qemu
netmask = NULL;
}
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "dhcp") &&
+ !qemudParseDhcpRangesXML(server, network, cur))
+ return 0;
+ cur = cur->next;
+ }
+
return 1;
}
@@ -1724,7 +1789,24 @@ char *qemudGenerateNetworkXML(struct qem
qemudBufferPrintf(&buf, " netmask='%s'",
network->def.netmask) < 0)
goto no_memory;
- if (qemudBufferAdd(&buf, "/>\n") < 0)
+ if (qemudBufferAdd(&buf, ">\n") < 0)
+ goto no_memory;
+
+ if (network->def.ranges) {
+ struct qemud_dhcp_range_def *range = network->def.ranges;
+ if (qemudBufferAdd(&buf, " <dhcp>\n") < 0)
+ goto no_memory;
+ while (range) {
+ if (qemudBufferPrintf(&buf, " <range start='%s'
end='%s' />\n",
+ range->start, range->end) < 0)
+ goto no_memory;
+ range = range->next;
+ }
+ if (qemudBufferAdd(&buf, " </dhcp>\n") < 0)
+ goto no_memory;
+ }
+
+ if (qemudBufferAdd(&buf, " </ip>\n") < 0)
goto no_memory;
}
Index: libvirt-foo/qemud/internal.h
===================================================================
--- libvirt-foo.orig/qemud/internal.h 2007-02-14 15:59:02.000000000 +0000
+++ libvirt-foo.orig/qemud/internal.h 2007-02-14 15:59:02.000000000 +0000
@@ -200,6 +200,14 @@ struct qemud_vm {
struct qemud_vm *next;
};
+/* Store start and end addresses of a dhcp range */
+struct qemud_dhcp_range_def {
+ char start[BR_INET_ADDR_MAXLEN];
+ char end[BR_INET_ADDR_MAXLEN];
+
+ struct qemud_dhcp_range_def *next;
+};
+
/* Virtual Network main configuration */
struct qemud_network_def {
unsigned char uuid[QEMUD_UUID_RAW_LEN];
@@ -211,6 +219,9 @@ struct qemud_network_def {
char ipAddress[BR_INET_ADDR_MAXLEN];
char netmask[BR_INET_ADDR_MAXLEN];
+
+ int nranges;
+ struct qemud_dhcp_range_def *ranges;
};
/* Virtual Network runtime state */
@@ -220,6 +231,7 @@ struct qemud_network {
struct qemud_network_def def;
char bridge[BR_IFNAME_MAXLEN];
+ int dnsmasqPid;
unsigned int active : 1;
Index: libvirt-foo/qemud/qemud.c
===================================================================
--- libvirt-foo.orig/qemud/qemud.c 2007-02-14 15:59:02.000000000 +0000
+++ libvirt-foo.orig/qemud/qemud.c 2007-02-14 15:59:02.000000000 +0000
@@ -703,6 +703,105 @@ static int qemudDispatchVMFailure(struct
return 0;
}
+static int
+qemudBuildDnsmasqArgv(struct qemud_server *server,
+ struct qemud_network *network,
+ char ***argv) {
+ int i, len;
+ char buf[BR_INET_ADDR_MAXLEN * 2];
+ struct qemud_dhcp_range_def *range;
+
+ len =
+ 1 + /* dnsmasq */
+ 1 + /* --keep-in-foreground */
+ 1 + /* --bind-interfaces */
+ 2 + /* --pid-file "" */
+ 2 + /* --conf-file "" */
+ 2 + /* --except-interface lo */
+ 2 + /* --listen-address 10.0.0.1 */
+ (2 * network->def.nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
+ 1; /* NULL */
+
+ if (!(*argv = malloc(len * sizeof(char *))))
+ goto no_memory;
+
+ memset(*argv, 0, len * sizeof(char *));
+
+#define APPEND_ARG(v, n, s) do { \
+ if (!((v)[(n)] = strdup(s))) \
+ goto no_memory; \
+ } while (0)
+
+ i = 0;
+
+ APPEND_ARG(*argv, i++, "dnsmasq");
+
+ APPEND_ARG(*argv, i++, "--keep-in-foreground");
+ APPEND_ARG(*argv, i++, "--bind-interfaces");
+
+ APPEND_ARG(*argv, i++, "--pid-file");
+ APPEND_ARG(*argv, i++, "");
+
+ APPEND_ARG(*argv, i++, "--conf-file");
+ APPEND_ARG(*argv, i++, "");
+
+ APPEND_ARG(*argv, i++, "--except-interface");
+ APPEND_ARG(*argv, i++, "lo");
+
+ APPEND_ARG(*argv, i++, "--listen-address");
+ APPEND_ARG(*argv, i++, network->def.ipAddress);
+
+ range = network->def.ranges;
+ while (range) {
+ snprintf(buf, sizeof(buf), "%s,%s",
+ range->start, range->end);
+
+ APPEND_ARG(*argv, i++, "--dhcp-range");
+ APPEND_ARG(*argv, i++, buf);
+
+ range = range->next;
+ }
+
+#undef APPEND_ARG
+
+ return 0;
+
+ no_memory:
+ if (argv) {
+ for (i = 0; (*argv)[i]; i++)
+ free((*argv)[i]);
+ free(*argv);
+ }
+ qemudReportError(server, VIR_ERR_NO_MEMORY, "dnsmasq argv");
+ return -1;
+}
+
+
+static int
+dhcpStartDhcpDaemon(struct qemud_server *server,
+ struct qemud_network *network)
+{
+ char **argv;
+ int ret, i;
+
+ if (network->def.ipAddress[0] == '\0') {
+ qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+ "cannot start dhcp daemon without IP address for
server");
+ return -1;
+ }
+
+ argv = NULL;
+ if (qemudBuildDnsmasqArgv(server, network, &argv) < 0)
+ return -1;
+
+ ret = qemudExec(server, argv, &network->dnsmasqPid, NULL, NULL);
+
+ for (i = 0; argv[i]; i++)
+ free(argv[i]);
+ free(argv);
+
+ return ret;
+}
int qemudStartNetworkDaemon(struct qemud_server *server,
struct qemud_network *network) {
@@ -758,10 +857,21 @@ int qemudStartNetworkDaemon(struct qemud
goto err_delbr;
}
+ if (network->def.ranges &&
+ dhcpStartDhcpDaemon(server, network) < 0)
+ goto err_delbr1;
+
network->active = 1;
return 0;
+ err_delbr1:
+ if (network->def.ipAddress[0] &&
+ (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
+ printf("Damn! Failed to bring down bridge '%s' : %s\n",
+ network->bridge, strerror(err));
+ }
+
err_delbr:
if ((err = brDeleteBridge(server->brctl, network->bridge))) {
printf("Damn! Couldn't delete bridge '%s' : %s\n",
@@ -780,6 +890,9 @@ int qemudShutdownNetworkDaemon(struct qe
if (!network->active)
return 0;
+ if (network->dnsmasqPid > 0)
+ kill(network->dnsmasqPid, SIGTERM);
+
if (network->def.ipAddress[0] &&
(err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
printf("Damn! Failed to bring down bridge '%s' : %s\n",
@@ -812,7 +925,15 @@ int qemudShutdownNetworkDaemon(struct qe
curr = curr->next;
}
+ if (network->dnsmasqPid > 0 &&
+ waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) {
+ kill(network->dnsmasqPid, SIGKILL);
+ if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid)
+ printf("Got unexpected pid for dnsmasq, damn\n");
+ }
+
network->bridge[0] = '\0';
+ network->dnsmasqPid = -1;
network->active = 0;
return 0;
--