]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Tue Feb 14 16:08:55 IST 2007 Mark McLoughlin <markmc@redhat.com>
authorMark McLoughlin <markmc@redhat.com>
Wed, 14 Feb 2007 16:09:37 +0000 (16:09 +0000)
committerMark McLoughlin <markmc@redhat.com>
Wed, 14 Feb 2007 16:09:37 +0000 (16:09 +0000)
        * 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.

ChangeLog
qemud/conf.c
qemud/internal.h
qemud/qemud.c

index b7b3050c1a9d1be5daf667fc2c9a53b46ae4620f..9383275edd82f6f2b60a201419ae768709e154f7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-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
 
index cbca964d4c6bb71b5a9630c316a39d07a6ffaa21..79340e5fd0fa67f135663d697ea69133099e7fbc 100644 (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;
 
index 6f249f603ec6607e1501eb2f32ca343b27bd76e3..72281a19e38ca2fd8bbc4565c82392f39e1c0185 100644 (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;
index 32310966cb778508a89840c2ed109e6af9d89e00..19cc5875cb32520d7549ae8801ff1c07f66baa0e 100644 (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]);