summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2007-02-14 16:09:37 +0000
committerMark McLoughlin <markmc@redhat.com>2007-02-14 16:09:37 +0000
commit0c15bd8b87d8e75262e08c58012ffc6eb950e7e4 (patch)
treec3a615bd6f21d7954bfcd9a189438f9edfb20292
parent3fbd82faa0d4499dd19c57554499121e2c1fbd06 (diff)
downloadlibvirt-0c15bd8b87d8e75262e08c58012ffc6eb950e7e4.tar.gz
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.
-rw-r--r--ChangeLog124
-rw-r--r--qemud/conf.c148
-rw-r--r--qemud/internal.h8
-rw-r--r--qemud/qemud.c50
4 files changed, 311 insertions, 19 deletions
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 <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
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 <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;
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
@@ -333,8 +333,23 @@ 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]);