diff --git a/ChangeLog b/ChangeLog index b7b3050c1a..9383275edd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,26 +1,128 @@ -Tue Feb 14 15:07:26 EST 2007 Mark McLoughlin +Tue Feb 14 16:08:55 IST 2007 Mark McLoughlin + + * qemud/conf.c: add support for connecting a qemu + guest to a bridge using a tap device in order to + connect it to a virtual network. + + * qemud/internal.h: add + config and track tapfds so as to not close them + on exec. + + * qemud/qemud.c: don't close tapfds on exec and + disconnect the iface when the guest shuts down. + +Tue Feb 14 16:04:48 IST 2007 Mark McLoughlin + + * qemud/conf.c, qemud/internal.h: add dhcp config + + * qemud/qemud.c: start dnsmasq to provide dns/dhcp + for virtual networks. + +Tue Feb 14 16:02:23 IST 2007 Mark McLoughlin + + * configure.in: add --disable-bridge-params, check + for libsysfs and various kernel headers + + * bridge.[ch]: add code for managing bridges + + * qemud/Makefile.am: add bridge.[ch] and link against + libsysfs if enabled. + + * qemud/conf.c: add support for bridge config. + + * qemud/internal.h: add various bridging bits + + * qemud/qemud.c: implement qemudStartNetworkDaemon() + and qemudShutdownNetworkDaemon(). + +Tue Feb 14 15:55:02 IST 2007 Mark McLoughlin + + * qemud/conf.[ch]: implement parsing and saving network + configs. + + * qemud/driver.c: flesh out the stubs + + * qemud/internal.h: add networks list etc. to + struct qemud_server + + * qemud/qemud.c: add qemudStartNetworkDaemon() and + qemudShutdownNetworkDaemon() stubs. + +Tue Feb 14 15:52:34 EST 2007 Mark McLoughlin + + * qemud/protocol.h: add the protocol for virtual networks + + * qemud/dispatch.c: implement the protocol + + * qemud/driver.[ch]: add stubs for the driver + + * qemud/internal.h: add struct qemud_network + + * src/qemu_internal.c: add a virtual networks driver + +Tue Feb 14 15:43:28 IST 2007 Mark McLoughlin + + * src/virsh.c: add the net-* commands. + +Tue Feb 14 15:37:17 IST 2007 Mark McLoughlin + + Note: potential ABI break here, but people should + only really be using virError structs returned from + libvirt itself. + + * include/libvirt/virterror.h: add virNetwork + to virError + + * src/internal.h, src/virterror.c: add network param + to __virRaiseError() + + * src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c, + src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c, + src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c, + src/xs_internal.c: update. + +Tue Feb 14 15:33:05 IST 2007 Mark McLoughlin + + * include/libvirt/libvirt.h.in: add the networks APIs + + * include/libvirt/virterror.h: add some error codes + + * src/driver.h: add network driver vtable + + * src/hash.c: add networks hash + + * src/internal.h: add virNetwork + + * src/libvirt.c: hook up the APIs to the network + driver + + * src/libvirt_sym.version: add the new APIs + + * src/virterror.c: handle the new error codes + +Tue Feb 14 15:07:26 IST 2007 Mark McLoughlin * src/conf.h: fix merge error - remove the argc argument from qemudBuildCommandLine() -Tue Feb 14 15:03:22 EST 2007 Mark McLoughlin +Tue Feb 14 15:03:22 IST 2007 Mark McLoughlin * src/virsh.c: Re-name some of the VSH_DOMBYFOO stuff to VSH_BYFOO in order to re-use it for the network stuff. -Tue Feb 14 14:58:35 EST 2007 Mark McLoughlin +Tue Feb 14 14:58:35 IST 2007 Mark McLoughlin * src/hash.c, src/internal.h: Re-name virConnect->domains_mux to virConnect->hashes_mux since it will also be used to protect the networks hash. -Tue Feb 14 14:57:52 EST 2007 Mark McLoughlin +Tue Feb 14 14:57:52 IST 2007 Mark McLoughlin * qemud/conf.c: qemudSaveConfig() will always report a more specific error, so we should avoid overwriting this error. -Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin +Tue Feb 14 14:54:25 IST 2007 Mark McLoughlin * qemud/qemud.c: Re-factor out qemudExec() so that it can be used to launch dnsmasq. @@ -28,7 +130,7 @@ Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin * qemud/conf.c: don't return argc from qemudBuildCommandLine() as exec() doesn't need it. -Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin +Tue Feb 14 14:52:12 IST 2007 Mark McLoughlin * qemud/conf.c: Re-factor bits of conf.c so that: @@ -38,25 +140,25 @@ Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin - split qemudScanConfigDir() out so that qemudScanConfigs() can scan multiple configDirs -Tue Feb 14 14:50:22 EST 2007 Mark McLoughlin +Tue Feb 14 14:50:22 IST 2007 Mark McLoughlin * qemud/conf.c: handle an unspecified MAC address, fix the argv freeing code in qemudBuildCommandLine() and fix copy and paste error in qemudGenerateXML() -Tue Feb 14 14:42:38 EST 2007 Mark McLoughlin +Tue Feb 14 14:42:38 IST 2007 Mark McLoughlin * src/internal.h: add virConnect->qemud_fd so that xen and qemu don't share the handle member. * src/hash.c, src/qemu_internal.c: update -Tue Feb 14 14:40:52 EST 2007 Mark McLoughlin +Tue Feb 14 14:40:52 IST 2007 Mark McLoughlin * qemud/conf.c, qemud/dispatch.c, qemud/driver.c, qemud/qemud.c: include autoconf's config.h -Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin +Tue Feb 14 14:39:18 IST 2007 Mark McLoughlin * conf.[ch]: rename from config.[ch] so we can use autoconf's config.h @@ -65,7 +167,7 @@ Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin * driver.c, qemud.c: upd. -Tue Feb 14 14:33:22 EST 2007 Mark McLoughlin +Tue Feb 14 14:33:22 IST 2007 Mark McLoughlin * autogen.sh: run autoheader diff --git a/qemud/conf.c b/qemud/conf.c index cbca964d4c..79340e5fd0 100644 --- a/qemud/conf.c +++ b/qemud/conf.c @@ -366,6 +366,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv xmlNodePtr cur; xmlChar *macaddr = NULL; xmlChar *type = NULL; + xmlChar *network = NULL; + xmlChar *tapifname = NULL; if (!net) { qemudReportError(server, VIR_ERR_NO_MEMORY, "net"); @@ -386,6 +388,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv net->type = QEMUD_NET_CLIENT; else if (xmlStrEqual(type, BAD_CAST "mcast")) net->type = QEMUD_NET_MCAST; + else if (xmlStrEqual(type, BAD_CAST "network")) + net->type = QEMUD_NET_NETWORK; /* else if (xmlStrEqual(type, BAD_CAST "vde")) typ = QEMUD_NET_VDE; @@ -402,6 +406,14 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv if ((macaddr == NULL) && (xmlStrEqual(cur->name, BAD_CAST "mac"))) { macaddr = xmlGetProp(cur, BAD_CAST "address"); + } else if ((network == NULL) && + (net->type == QEMUD_NET_NETWORK) && + (xmlStrEqual(cur->name, BAD_CAST "source"))) { + network = xmlGetProp(cur, BAD_CAST "network"); + } else if ((tapifname == NULL) && + (net->type == QEMUD_NET_NETWORK) && + xmlStrEqual(cur->name, BAD_CAST "tap")) { + tapifname = xmlGetProp(cur, BAD_CAST "ifname"); } } cur = cur->next; @@ -421,7 +433,47 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv xmlFree(macaddr); } + if (net->type == QEMUD_NET_NETWORK) { + int len; + + if (network == NULL) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "No 'network' attribute specified with "); + goto error; + } else if ((len = xmlStrlen(network)) >= QEMUD_MAX_NAME_LEN) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "Network name '%s' too long", network); + goto error; + } else { + strncpy(net->dst.network.name, (char *)network, len); + net->dst.network.name[len] = '\0'; + } + + if (network) + xmlFree(network); + + if (tapifname != NULL) { + if ((len == xmlStrlen(tapifname)) >= BR_IFNAME_MAXLEN) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "TAP interface name '%s' is too long", tapifname); + goto error; + } else { + strncpy(net->dst.network.tapifname, (char *)tapifname, len); + net->dst.network.tapifname[len] = '\0'; + } + xmlFree(tapifname); + } + } + return net; + + error: + if (network) + xmlFree(network); + if (tapifname) + xmlFree(tapifname); + free(net); + return NULL; } @@ -770,6 +822,68 @@ static int qemudParseXML(struct qemud_server *server, } +static char * +qemudNetworkIfaceConnect(struct qemud_server *server, + struct qemud_vm *vm, + struct qemud_vm_net_def *net) +{ + struct qemud_network *network; + const char *tapifname; + char tapfdstr[4+3+32+7]; + char *retval = NULL; + int err; + int tapfd = -1; + int *tapfds; + + if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "Network '%s' not found", net->dst.network.name); + goto error; + } else if (network->bridge[0] == '\0') { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "Network '%s' not active", net->dst.network.name); + goto error; + } + + if (net->dst.network.tapifname[0] == '\0' || + strchr(net->dst.network.tapifname, '%')) { + tapifname = "vnet%d"; + } else { + tapifname = net->dst.network.tapifname; + } + + if ((err = brAddTap(server->brctl, network->bridge, tapifname, + &net->dst.network.tapifname[0], BR_IFNAME_MAXLEN, &tapfd))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "Failed to add tap interface '%s' to bridge '%s' : %s", + tapifname, network->bridge, strerror(err)); + goto error; + } + + snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=", tapfd); + + if (!(retval = strdup(tapfdstr))) + goto no_memory; + + if (!(tapfds = realloc(vm->tapfds, sizeof(int) * (vm->ntapfds+2)))) + goto no_memory; + + vm->tapfds = tapfds; + vm->tapfds[vm->ntapfds++] = tapfd; + vm->tapfds[vm->ntapfds] = -1; + + return retval; + + no_memory: + qemudReportError(server, VIR_ERR_NO_MEMORY, "tapfds"); + error: + if (retval) + free(retval); + if (tapfd != -1) + close(tapfd); + return NULL; +} + /* * Constructs a argv suitable for launching qemu with config defined * for a given virtual machine. @@ -921,9 +1035,15 @@ int qemudBuildCommandLine(struct qemud_server *server, goto no_memory; if (!((*argv)[++n] = strdup("-net"))) goto no_memory; - /* XXX don't hardcode user */ - if (!((*argv)[++n] = strdup("user"))) - goto no_memory; + + if (net->type != QEMUD_NET_NETWORK) { + /* XXX don't hardcode user */ + if (!((*argv)[++n] = strdup("user"))) + goto no_memory; + } else { + if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net))) + goto error; + } net = net->next; } @@ -948,12 +1068,20 @@ int qemudBuildCommandLine(struct qemud_server *server, return 0; no_memory: + qemudReportError(server, VIR_ERR_NO_MEMORY, "argv"); + error: + if (vm->tapfds) { + for (i = 0; vm->tapfds[i] != -1; i++) + close(vm->tapfds[i]); + free(vm->tapfds); + vm->tapfds = NULL; + vm->ntapfds = 0; + } if (argv) { for (i = 0 ; i < n ; i++) free((*argv)[i]); free(*argv); } - qemudReportError(server, VIR_ERR_NO_MEMORY, "argv"); return -1; } @@ -1716,6 +1844,18 @@ char *qemudGenerateXML(struct qemud_server *server, struct qemud_vm *vm) { net->mac[3], net->mac[4], net->mac[5]) < 0) goto no_memory; + if (net->type == QEMUD_NET_NETWORK) { + if (qemudBufferPrintf(&buf, " dst.network.tapifname) < 0) + goto no_memory; + + if (qemudBufferPrintf(&buf, "/>\n") < 0) + goto no_memory; + } + if (qemudBufferPrintf(&buf, " \n") < 0) goto no_memory; diff --git a/qemud/internal.h b/qemud/internal.h index 6f249f603e..72281a19e3 100644 --- a/qemud/internal.h +++ b/qemud/internal.h @@ -95,6 +95,7 @@ enum qemud_vm_net_type { QEMUD_NET_SERVER, QEMUD_NET_CLIENT, QEMUD_NET_MCAST, + QEMUD_NET_NETWORK, /* QEMUD_NET_VDE*/ }; @@ -123,6 +124,10 @@ struct qemud_vm_net_def { struct { char vlan[PATH_MAX]; } vde; + struct { + char name[QEMUD_MAX_NAME_LEN]; + char tapifname[BR_IFNAME_MAXLEN]; + } network; } dst; struct qemud_vm_net_def *next; @@ -193,6 +198,9 @@ struct qemud_vm { int monitor; int pid; + int *tapfds; + int ntapfds; + char configFile[PATH_MAX]; struct qemud_vm_def def; diff --git a/qemud/qemud.c b/qemud/qemud.c index 32310966cb..19cc5875cb 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -332,9 +332,24 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket } +static int +qemudLeaveFdOpen(int *openfds, int fd) +{ + int i; + + if (!openfds) + return 0; + + for (i = 0; openfds[i] != -1; i++) + if (fd == openfds[i]) + return 1; + + return 0; +} + static int qemudExec(struct qemud_server *server, char **argv, - int *retpid, int *outfd, int *errfd) { + int *retpid, int *outfd, int *errfd, int *openfds) { int pid, null; int pipeout[2] = {-1,-1}; int pipeerr[2] = {-1,-1}; @@ -392,7 +407,8 @@ qemudExec(struct qemud_server *server, char **argv, for (i = 0; i < open_max; i++) if (i != STDOUT_FILENO && i != STDERR_FILENO && - i != STDIN_FILENO) + i != STDIN_FILENO && + !qemudLeaveFdOpen(openfds, i)) close(i); execvp(argv[0], argv); @@ -429,10 +445,20 @@ int qemudStartVMDaemon(struct qemud_server *server, if (qemudBuildCommandLine(server, vm, &argv) < 0) return -1; - if (qemudExec(server, argv, &vm->pid, &vm->stdout, &vm->stderr) == 0) { + if (qemudExec(server, argv, &vm->pid, &vm->stdout, &vm->stderr, vm->tapfds) == 0) { vm->def.id = server->nextvmid++; ret = 0; } + + if (vm->tapfds) { + for (i = 0; vm->tapfds[i] != -1; i++) { + close(vm->tapfds[i]); + vm->tapfds[i] = -1; + } + free(vm->tapfds); + vm->tapfds = NULL; + vm->ntapfds = 0; + } for (i = 0 ; argv[i] ; i++) free(argv[i]); @@ -632,8 +658,17 @@ static int qemudVMData(struct qemud_server *server ATTRIBUTE_UNUSED, } } +static void +qemudNetworkIfaceDisconnect(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_vm *vm ATTRIBUTE_UNUSED, + struct qemud_vm_net_def *net) { + /* FIXME: will be needed to remove iptables rules */ + net = NULL; +} + int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) { struct qemud_vm *prev = NULL, *curr = server->activevms; + struct qemud_vm_net_def *net; /* Already cleaned-up */ if (vm->pid < 0) @@ -676,6 +711,13 @@ int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) { curr->monitor = -1; server->nvmfds -= 2; + net = vm->def.nets; + while (net) { + if (net->type == QEMUD_NET_NETWORK) + qemudNetworkIfaceDisconnect(server, vm, net); + net = net->next; + } + if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) { kill(vm->pid, SIGKILL); if (waitpid(vm->pid, NULL, 0) != vm->pid) { @@ -794,7 +836,7 @@ dhcpStartDhcpDaemon(struct qemud_server *server, if (qemudBuildDnsmasqArgv(server, network, &argv) < 0) return -1; - ret = qemudExec(server, argv, &network->dnsmasqPid, NULL, NULL); + ret = qemudExec(server, argv, &network->dnsmasqPid, NULL, NULL, NULL); for (i = 0; argv[i]; i++) free(argv[i]);