Tue Feb 14 16:08:55 IST 2007 Mark McLoughlin <markmc@redhat.com>

* 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 <interface type="network">
        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.
This commit is contained in:
Mark McLoughlin 2007-02-14 16:09:37 +00:00
parent 3fbd82faa0
commit 0c15bd8b87
4 changed files with 311 additions and 19 deletions

124
ChangeLog
View File

@ -1,26 +1,128 @@
Tue Feb 14 15:07:26 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 16:08:55 IST 2007 Mark McLoughlin <markmc@redhat.com>
* 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 <interface type="network">
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 <markmc@redhat.com>
* 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 <markmc@redhat.com>
* 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 <markmc@redhat.com>
* 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 <markmc@redhat.com>
* 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 <markmc@redhat.com>
* src/virsh.c: add the net-* commands.
Tue Feb 14 15:37:17 IST 2007 Mark McLoughlin <markmc@redhat.com>
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 <markmc@redhat.com>
* 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 <markmc@redhat.com>
* src/conf.h: fix merge error - remove the argc argument * src/conf.h: fix merge error - remove the argc argument
from qemudBuildCommandLine() from qemudBuildCommandLine()
Tue Feb 14 15:03:22 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 15:03:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
* src/virsh.c: Re-name some of the VSH_DOMBYFOO stuff * src/virsh.c: Re-name some of the VSH_DOMBYFOO stuff
to VSH_BYFOO in order to re-use it for the network stuff. to VSH_BYFOO in order to re-use it for the network stuff.
Tue Feb 14 14:58:35 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:58:35 IST 2007 Mark McLoughlin <markmc@redhat.com>
* src/hash.c, src/internal.h: Re-name virConnect->domains_mux * src/hash.c, src/internal.h: Re-name virConnect->domains_mux
to virConnect->hashes_mux since it will also be used to to virConnect->hashes_mux since it will also be used to
protect the networks hash. protect the networks hash.
Tue Feb 14 14:57:52 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:57:52 IST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/conf.c: qemudSaveConfig() will always report a * qemud/conf.c: qemudSaveConfig() will always report a
more specific error, so we should avoid overwriting more specific error, so we should avoid overwriting
this error. this error.
Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:54:25 IST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/qemud.c: Re-factor out qemudExec() so that it can * qemud/qemud.c: Re-factor out qemudExec() so that it can
be used to launch dnsmasq. be used to launch dnsmasq.
@ -28,7 +130,7 @@ Tue Feb 14 14:54:25 EST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/conf.c: don't return argc from qemudBuildCommandLine() * qemud/conf.c: don't return argc from qemudBuildCommandLine()
as exec() doesn't need it. as exec() doesn't need it.
Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:52:12 IST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/conf.c: Re-factor bits of conf.c so that: * 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 <markmc@redhat.com>
- split qemudScanConfigDir() out so that qemudScanConfigs() - split qemudScanConfigDir() out so that qemudScanConfigs()
can scan multiple configDirs can scan multiple configDirs
Tue Feb 14 14:50:22 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:50:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/conf.c: handle an unspecified MAC address, * qemud/conf.c: handle an unspecified MAC address,
fix the argv freeing code in qemudBuildCommandLine() fix the argv freeing code in qemudBuildCommandLine()
and fix copy and paste error in qemudGenerateXML() and fix copy and paste error in qemudGenerateXML()
Tue Feb 14 14:42:38 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:42:38 IST 2007 Mark McLoughlin <markmc@redhat.com>
* src/internal.h: add virConnect->qemud_fd so that * src/internal.h: add virConnect->qemud_fd so that
xen and qemu don't share the handle member. xen and qemu don't share the handle member.
* src/hash.c, src/qemu_internal.c: update * src/hash.c, src/qemu_internal.c: update
Tue Feb 14 14:40:52 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:40:52 IST 2007 Mark McLoughlin <markmc@redhat.com>
* qemud/conf.c, qemud/dispatch.c, qemud/driver.c, * qemud/conf.c, qemud/dispatch.c, qemud/driver.c,
qemud/qemud.c: include autoconf's config.h qemud/qemud.c: include autoconf's config.h
Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:39:18 IST 2007 Mark McLoughlin <markmc@redhat.com>
* conf.[ch]: rename from config.[ch] so we can use * conf.[ch]: rename from config.[ch] so we can use
autoconf's config.h autoconf's config.h
@ -65,7 +167,7 @@ Tue Feb 14 14:39:18 EST 2007 Mark McLoughlin <markmc@redhat.com>
* driver.c, qemud.c: upd. * driver.c, qemud.c: upd.
Tue Feb 14 14:33:22 EST 2007 Mark McLoughlin <markmc@redhat.com> Tue Feb 14 14:33:22 IST 2007 Mark McLoughlin <markmc@redhat.com>
* autogen.sh: run autoheader * autogen.sh: run autoheader

View File

@ -366,6 +366,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
xmlNodePtr cur; xmlNodePtr cur;
xmlChar *macaddr = NULL; xmlChar *macaddr = NULL;
xmlChar *type = NULL; xmlChar *type = NULL;
xmlChar *network = NULL;
xmlChar *tapifname = NULL;
if (!net) { if (!net) {
qemudReportError(server, VIR_ERR_NO_MEMORY, "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; net->type = QEMUD_NET_CLIENT;
else if (xmlStrEqual(type, BAD_CAST "mcast")) else if (xmlStrEqual(type, BAD_CAST "mcast"))
net->type = QEMUD_NET_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")) else if (xmlStrEqual(type, BAD_CAST "vde"))
typ = QEMUD_NET_VDE; typ = QEMUD_NET_VDE;
@ -402,6 +406,14 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
if ((macaddr == NULL) && if ((macaddr == NULL) &&
(xmlStrEqual(cur->name, BAD_CAST "mac"))) { (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
macaddr = xmlGetProp(cur, BAD_CAST "address"); 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; cur = cur->next;
@ -421,7 +433,47 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
xmlFree(macaddr); xmlFree(macaddr);
} }
if (net->type == QEMUD_NET_NETWORK) {
int len;
if (network == NULL) {
qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
"No <source> 'network' attribute specified with <interface type='network'/>");
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; 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 * Constructs a argv suitable for launching qemu with config defined
* for a given virtual machine. * for a given virtual machine.
@ -921,9 +1035,15 @@ int qemudBuildCommandLine(struct qemud_server *server,
goto no_memory; goto no_memory;
if (!((*argv)[++n] = strdup("-net"))) if (!((*argv)[++n] = strdup("-net")))
goto no_memory; goto no_memory;
/* XXX don't hardcode user */
if (!((*argv)[++n] = strdup("user"))) if (net->type != QEMUD_NET_NETWORK) {
goto no_memory; /* 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; net = net->next;
} }
@ -948,12 +1068,20 @@ int qemudBuildCommandLine(struct qemud_server *server,
return 0; return 0;
no_memory: 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) { if (argv) {
for (i = 0 ; i < n ; i++) for (i = 0 ; i < n ; i++)
free((*argv)[i]); free((*argv)[i]);
free(*argv); free(*argv);
} }
qemudReportError(server, VIR_ERR_NO_MEMORY, "argv");
return -1; 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) net->mac[3], net->mac[4], net->mac[5]) < 0)
goto no_memory; goto no_memory;
if (net->type == QEMUD_NET_NETWORK) {
if (qemudBufferPrintf(&buf, " <network name='%s", net->dst.network.name) < 0)
goto no_memory;
if (net->dst.network.tapifname[0] != '\0' &&
qemudBufferPrintf(&buf, " tapifname='%s'", net->dst.network.tapifname) < 0)
goto no_memory;
if (qemudBufferPrintf(&buf, "/>\n") < 0)
goto no_memory;
}
if (qemudBufferPrintf(&buf, " </interface>\n") < 0) if (qemudBufferPrintf(&buf, " </interface>\n") < 0)
goto no_memory; goto no_memory;

View File

@ -95,6 +95,7 @@ enum qemud_vm_net_type {
QEMUD_NET_SERVER, QEMUD_NET_SERVER,
QEMUD_NET_CLIENT, QEMUD_NET_CLIENT,
QEMUD_NET_MCAST, QEMUD_NET_MCAST,
QEMUD_NET_NETWORK,
/* QEMUD_NET_VDE*/ /* QEMUD_NET_VDE*/
}; };
@ -123,6 +124,10 @@ struct qemud_vm_net_def {
struct { struct {
char vlan[PATH_MAX]; char vlan[PATH_MAX];
} vde; } vde;
struct {
char name[QEMUD_MAX_NAME_LEN];
char tapifname[BR_IFNAME_MAXLEN];
} network;
} dst; } dst;
struct qemud_vm_net_def *next; struct qemud_vm_net_def *next;
@ -193,6 +198,9 @@ struct qemud_vm {
int monitor; int monitor;
int pid; int pid;
int *tapfds;
int ntapfds;
char configFile[PATH_MAX]; char configFile[PATH_MAX];
struct qemud_vm_def def; struct qemud_vm_def def;

View File

@ -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 static int
qemudExec(struct qemud_server *server, char **argv, 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 pid, null;
int pipeout[2] = {-1,-1}; int pipeout[2] = {-1,-1};
int pipeerr[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++) for (i = 0; i < open_max; i++)
if (i != STDOUT_FILENO && if (i != STDOUT_FILENO &&
i != STDERR_FILENO && i != STDERR_FILENO &&
i != STDIN_FILENO) i != STDIN_FILENO &&
!qemudLeaveFdOpen(openfds, i))
close(i); close(i);
execvp(argv[0], argv); execvp(argv[0], argv);
@ -429,10 +445,20 @@ int qemudStartVMDaemon(struct qemud_server *server,
if (qemudBuildCommandLine(server, vm, &argv) < 0) if (qemudBuildCommandLine(server, vm, &argv) < 0)
return -1; 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++; vm->def.id = server->nextvmid++;
ret = 0; 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++) for (i = 0 ; argv[i] ; i++)
free(argv[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) { int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
struct qemud_vm *prev = NULL, *curr = server->activevms; struct qemud_vm *prev = NULL, *curr = server->activevms;
struct qemud_vm_net_def *net;
/* Already cleaned-up */ /* Already cleaned-up */
if (vm->pid < 0) if (vm->pid < 0)
@ -676,6 +711,13 @@ int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
curr->monitor = -1; curr->monitor = -1;
server->nvmfds -= 2; 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) { if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) {
kill(vm->pid, SIGKILL); kill(vm->pid, SIGKILL);
if (waitpid(vm->pid, NULL, 0) != vm->pid) { if (waitpid(vm->pid, NULL, 0) != vm->pid) {
@ -794,7 +836,7 @@ dhcpStartDhcpDaemon(struct qemud_server *server,
if (qemudBuildDnsmasqArgv(server, network, &argv) < 0) if (qemudBuildDnsmasqArgv(server, network, &argv) < 0)
return -1; 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++) for (i = 0; argv[i]; i++)
free(argv[i]); free(argv[i]);