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
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
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
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 <markmc@redhat.com>
Tue Feb 14 14:57:52 IST 2007 Mark McLoughlin <markmc@redhat.com>
* 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 <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
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()
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:
@ -38,25 +140,25 @@ Tue Feb 14 14:52:12 EST 2007 Mark McLoughlin <markmc@redhat.com>
- split qemudScanConfigDir() out so that qemudScanConfigs()
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,
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 <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
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 <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/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
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.
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

View File

@ -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 <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;
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, " <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)
goto no_memory;

View File

@ -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;

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
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]);