Add support for starting dnsmasq and a 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 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, " \n") < 0) + goto no_memory; + while (range) { + if (qemudBufferPrintf(&buf, " \n", + range->start, range->end) < 0) + goto no_memory; + range = range->next; + } + if (qemudBufferAdd(&buf, " \n") < 0) + goto no_memory; + } + + if (qemudBufferAdd(&buf, " \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; --