]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Improve support for virtual networking
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 13 Mar 2007 22:43:22 +0000 (22:43 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 13 Mar 2007 22:43:22 +0000 (22:43 +0000)
ChangeLog
libvirt.spec.in
qemud/Makefile.am
qemud/bridge.c
qemud/bridge.h
qemud/conf.c
qemud/default-network.xml
qemud/internal.h
qemud/iptables.c
qemud/iptables.h
qemud/qemud.c

index cc30c38e9825516c3bcdf1ff853a6668c4d03825..804c30791646b8f43fe1f6532dd5cc4d822600e9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+Tue Mar 13 18:04:14 EST 2007 Daniel P. Berrange <berrange@redhat.com>
+
+       * qemud/qemud.c: Use the --dhcp-leasefile arg to dnsmasq to
+       ensure multiple instances of dnsmasq can co-exist without
+       splaterring each other's leases.
+
+       * qemud/bridge.c: Use a single ifname arg instead of two separate
+       ifnameOrFmt & ifname args to simply use by callers
+
+       * qemud/conf.c: Autogenerate a MAC address if none is provided.
+       Added support for ethernet, bridge, mcast, client and server
+       networking config types in XML parser, generator and command
+       line args. Use the 'vlan' attribute for all QEMU nics to ensure
+       they don't all appear on same virtual LAN. Ensure order of
+       QEMU NICs matches order they are declared in the XML. Tweak
+       existing XML generation of 'network' type to match syntax
+       used by Xen for specifying tap device name. Add support for
+       creating isolated networks, or networks forwarding to an
+       explicit named physical device.
+
+       * qemud/default-network.xml: Add <forward/> to make default network
+       automatically forward to any active physical device.
+
+       * qemud/internal.h: Added struct fields for new types of network
+       config, and for tracking network forward device.
+
+       * qemud/iptables.h, qemud/iptables.c: Allow an optional target
+       device name to be passed in to restrict IP tables forwarding
+       rules.
+
+       * qemud/Makefile.am: Create $sysconfdir/lib/libvirt for DHCP
+       leases file
+
+       * libvirt.spec.in: Include %{_sysconfdir}/lib/libvirt for DHCP
+       leases file
+
 Mon Mar 12 23:17:11 EST 2007 Daniel P. Berrange <berrange@redhat.com>
 
        * libvirt.spec.in: Don't run UUID generation on first install,
index a9015870a60d19427a1a87865edc2d7993bfb6fc..75c219895f83e46590c9c8eee8f1ac4e750222a7 100644 (file)
@@ -113,6 +113,7 @@ fi
 %config %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
 %{_sysconfdir}/rc.d/init.d/libvirtd
 %dir %{_localstatedir}/run/libvirt/
+%dir %{_localstatedir}/lib/libvirt/
 %attr(4755, root, root) %{_libexecdir}/libvirt_proxy
 %attr(0755, root, root) %{_sbindir}/libvirt_qemud
 %doc docs/libvirt.rng
index f4969b9fcb3bdaf6996e49afd1093552faa1e5b3..73b0c5e3d9a375350f8d2d4530cf66ce65ac782d 100644 (file)
@@ -28,12 +28,14 @@ install-data-local:
        test -e $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml || \
            ln -s ../default.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
        mkdir -p $(DESTDIR)$(localstatedir)/run/libvirt
+       mkdir -p $(DESTDIR)$(localstatedir)/lib/libvirt
 
 uninstall-local:
        rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
        rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
        rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || :
        rmdir $(DESTDIR)$(localstatedir)/run/libvirt || :
+       rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || :
 
 EXTRA_DIST = libvirtd.in default-network.xml
 
index 6d2d277ed51dfdbf09d74d9d704f8714c107cb33..14767dbe4217c9aeb1f18ecfec2f4708d036035b 100644 (file)
@@ -190,27 +190,22 @@ brDeleteInterface(brControl *ctl,
     return brAddDelInterface(ctl, SIOCBRDELIF, bridge, iface);
 }
 
+
 int
 brAddTap(brControl *ctl,
          const char *bridge,
-         const char *ifnameOrFmt,
          char *ifname,
          int maxlen,
          int *tapfd)
 {
     int id, subst, fd;
 
-    if (!ctl || !ctl->fd || !bridge || !ifnameOrFmt || !tapfd)
+    if (!ctl || !ctl->fd || !bridge || !ifname || !tapfd)
         return EINVAL;
 
-    if (!ifname)
-        maxlen = BR_IFNAME_MAXLEN;
-    else if (maxlen >= BR_IFNAME_MAXLEN)
-        maxlen = BR_IFNAME_MAXLEN;
-
     subst = id = 0;
 
-    if (strstr(ifnameOrFmt, "%d"))
+    if (strstr(ifname, "%d"))
         subst = 1;
 
     if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
@@ -225,19 +220,19 @@ brAddTap(brControl *ctl,
         try.ifr_flags = IFF_TAP|IFF_NO_PI;
 
         if (subst) {
-            len = snprintf(try.ifr_name, maxlen, ifnameOrFmt, id);
+            len = snprintf(try.ifr_name, maxlen, ifname, id);
             if (len >= maxlen) {
                 errno = EADDRINUSE;
                 goto error;
             }
         } else {
-            len = strlen(ifnameOrFmt);
+            len = strlen(ifname);
             if (len >= maxlen - 1) {
                 errno = EINVAL;
                 goto error;
             }
 
-            strncpy(try.ifr_name, ifnameOrFmt, len);
+            strncpy(try.ifr_name, ifname, len);
             try.ifr_name[len] = '\0';
         }
 
index 81099443752ebba753a6518b128160749a146e2a..df461e0dd2477122e40edb6c17c684b24c5e91d0 100644 (file)
@@ -49,7 +49,6 @@ int     brDeleteInterface       (brControl *ctl,
 
 int     brAddTap                (brControl *ctl,
                                  const char *bridge,
-                                 const char *ifnameOrFmt,
                                  char *ifname,
                                  int maxlen,
                                  int *tapfd);
index c8bdebdca9be0934b1fe60d8c374027610a62c75..a0f7e9919640257b16e2895209d14369acbcd0e8 100644 (file)
@@ -444,6 +444,15 @@ static struct qemud_vm_disk_def *qemudParseDiskXML(struct qemud_server *server,
     return NULL;
 }
 
+static void qemudRandomMAC(struct qemud_vm_net_def *net) {
+    net->mac[0] = 0x52;
+    net->mac[1] = 0x54;
+    net->mac[2] = 0x00;
+    net->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+    net->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+    net->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+}
+
 
 /* Parse the XML definition for a network interface */
 static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *server,
@@ -453,7 +462,11 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
     xmlChar *macaddr = NULL;
     xmlChar *type = NULL;
     xmlChar *network = NULL;
-    xmlChar *tapifname = NULL;
+    xmlChar *bridge = NULL;
+    xmlChar *ifname = NULL;
+    xmlChar *script = NULL;
+    xmlChar *address = NULL;
+    xmlChar *port = NULL;
 
     if (!net) {
         qemudReportError(server, VIR_ERR_NO_MEMORY, "net");
@@ -466,8 +479,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
     if (type != NULL) {
         if (xmlStrEqual(type, BAD_CAST "user"))
             net->type = QEMUD_NET_USER;
-        else if (xmlStrEqual(type, BAD_CAST "tap"))
-            net->type = QEMUD_NET_TAP;
+        else if (xmlStrEqual(type, BAD_CAST "ethernet"))
+            net->type = QEMUD_NET_ETHERNET;
         else if (xmlStrEqual(type, BAD_CAST "server"))
             net->type = QEMUD_NET_SERVER;
         else if (xmlStrEqual(type, BAD_CAST "client"))
@@ -476,10 +489,8 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
             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;
-        */
+        else if (xmlStrEqual(type, BAD_CAST "bridge"))
+            net->type = QEMUD_NET_BRIDGE;
         else
             net->type = QEMUD_NET_USER;
         xmlFree(type);
@@ -496,17 +507,32 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
                        (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");
+            } else if ((network == NULL) &&
+                       (net->type == QEMUD_NET_BRIDGE) &&
+                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+                bridge = xmlGetProp(cur, BAD_CAST "dev");
+            } else if ((network == NULL) &&
+                       ((net->type == QEMUD_NET_SERVER) ||
+                        (net->type == QEMUD_NET_CLIENT) ||
+                        (net->type == QEMUD_NET_MCAST)) &&
+                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+                address = xmlGetProp(cur, BAD_CAST "address");
+                port = xmlGetProp(cur, BAD_CAST "port");
+            } else if ((ifname == NULL) &&
+                       ((net->type == QEMUD_NET_NETWORK) ||
+                        (net->type == QEMUD_NET_ETHERNET) ||
+                        (net->type == QEMUD_NET_BRIDGE)) &&
+                       xmlStrEqual(cur->name, BAD_CAST "target")) {
+                ifname = xmlGetProp(cur, BAD_CAST "dev");
+            } else if ((script == NULL) &&
+                       (net->type == QEMUD_NET_ETHERNET) &&
+                       xmlStrEqual(cur->name, BAD_CAST "script")) {
+                script = xmlGetProp(cur, BAD_CAST "path");
             }
         }
         cur = cur->next;
     }
 
-    net->vlan = 0;
-
     if (macaddr) {
         unsigned int mac[6];
         sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
@@ -524,6 +550,9 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
         net->mac[5] = mac[5];
 
         xmlFree(macaddr);
+        macaddr = NULL;
+    } else {
+        qemudRandomMAC(net);
     }
 
     if (net->type == QEMUD_NET_NETWORK) {
@@ -533,7 +562,7 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
             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) {
+        } else if ((len = xmlStrlen(network)) >= (QEMUD_MAX_NAME_LEN-1)) {
             qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                              "Network name '%s' too long", network);
             goto error;
@@ -542,20 +571,118 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
             net->dst.network.name[len] = '\0';
         }
 
-        if (network)
+        if (network) {
             xmlFree(network);
+            network = NULL;
+        }
+
+        if (ifname != NULL) {
+            if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "TAP interface name '%s' is too long", ifname);
+                goto error;
+            } else {
+                strncpy(net->dst.network.ifname, (char *)ifname, len);
+                net->dst.network.ifname[len] = '\0';
+            }
+            xmlFree(ifname);
+            ifname = NULL;
+        }
+    } else if (net->type == QEMUD_NET_ETHERNET) {
+        int len;
 
-        if (tapifname != NULL) {
-            if ((len == xmlStrlen(tapifname)) >= BR_IFNAME_MAXLEN) {
+        if (script != NULL) {
+            if ((len = xmlStrlen(script)) >= (PATH_MAX-1)) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "TAP script path '%s' is too long", script);
+                goto error;
+            } else {
+                strncpy(net->dst.ethernet.script, (char *)script, len);
+                net->dst.ethernet.script[len] = '\0';
+            }
+            xmlFree(script);
+            script = NULL;
+        }
+        if (ifname != NULL) {
+            if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
                 qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                                 "TAP interface name '%s' is too long", tapifname);
+                                 "TAP interface name '%s' is too long", ifname);
                 goto error;
             } else {
-                strncpy(net->dst.network.tapifname, (char *)tapifname, len);
-                net->dst.network.tapifname[len] = '\0';
+                strncpy(net->dst.ethernet.ifname, (char *)ifname, len);
+                net->dst.ethernet.ifname[len] = '\0';
             }
-            xmlFree(tapifname);
+            xmlFree(ifname);
+        }
+    } else if (net->type == QEMUD_NET_BRIDGE) {
+        int len;
+
+        if (bridge == NULL) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "No <source> 'dev' attribute specified with <interface type='bridge'/>");
+            goto error;
+        } else if ((len = xmlStrlen(bridge)) >= (BR_IFNAME_MAXLEN-1)) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "TAP bridge path '%s' is too long", bridge);
+            goto error;
+        } else {
+            strncpy(net->dst.bridge.brname, (char *)bridge, len);
+            net->dst.bridge.brname[len] = '\0';
         }
+
+        xmlFree(bridge);
+        bridge = NULL;
+
+        if (ifname != NULL) {
+            if ((len = xmlStrlen(ifname)) >= (BR_IFNAME_MAXLEN-1)) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "TAP interface name '%s' is too long", ifname);
+                goto error;
+            } else {
+                strncpy(net->dst.bridge.ifname, (char *)ifname, len);
+                net->dst.bridge.ifname[len] = '\0';
+            }
+            xmlFree(ifname);
+        }
+    } else if (net->type == QEMUD_NET_CLIENT ||
+               net->type == QEMUD_NET_SERVER ||
+               net->type == QEMUD_NET_MCAST) {
+        int len;
+        char *ret;
+
+        if (port == NULL) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "No <source> 'port' attribute specified with socket interface");
+            goto error;
+        }
+        if (!(net->dst.socket.port = strtol((char*)port, &ret, 10)) &&
+            ret == (char*)port) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Cannot parse <source> 'port' attribute with socket interface");
+            goto error;
+        }
+        xmlFree(port);
+        port = NULL;
+
+        if (address == NULL) {
+            if (net->type == QEMUD_NET_CLIENT ||
+                net->type == QEMUD_NET_MCAST) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "No <source> 'address' attribute specified with socket interface");
+                goto error;
+            }
+        } else if ((len = xmlStrlen(address)) >= (BR_INET_ADDR_MAXLEN)) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "IP address '%s' is too long", address);
+            goto error;
+        }
+        if (address == NULL) {
+            net->dst.socket.address[0] = '\0';
+        } else {
+            strncpy(net->dst.socket.address, (char*)address,len);
+            net->dst.socket.address[len] = '\0';
+        }
+        xmlFree(address);
     }
 
     return net;
@@ -563,8 +690,16 @@ static struct qemud_vm_net_def *qemudParseInterfaceXML(struct qemud_server *serv
  error:
     if (network)
         xmlFree(network);
-    if (tapifname)
-        xmlFree(tapifname);
+    if (address)
+        xmlFree(address);
+    if (port)
+        xmlFree(port);
+    if (ifname)
+        xmlFree(ifname);
+    if (script)
+        xmlFree(script);
+    if (bridge)
+        xmlFree(bridge);
     free(net);
     return NULL;
 }
@@ -886,14 +1021,20 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
     obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
     if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
         (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+        struct qemud_vm_disk_def *prev = NULL;
         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
             struct qemud_vm_disk_def *disk;
             if (!(disk = qemudParseDiskXML(server, obj->nodesetval->nodeTab[i]))) {
                 goto error;
             }
             def->ndisks++;
-            disk->next = def->disks;
-            def->disks = disk;
+            disk->next = NULL;
+            if (i == 0) {
+                def->disks = disk;
+            } else {
+                prev->next = disk;
+            }
+            prev = disk;
         }
     }
     xmlXPathFreeObject(obj);
@@ -903,14 +1044,20 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
     obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
     if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
         (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
+        struct qemud_vm_net_def *prev = NULL;
         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
             struct qemud_vm_net_def *net;
             if (!(net = qemudParseInterfaceXML(server, obj->nodesetval->nodeTab[i]))) {
                 goto error;
             }
             def->nnets++;
-            net->next = def->nets;
-            def->nets = net;
+            net->next = NULL;
+            if (i == 0) {
+                def->nets = net;
+            } else {
+                prev->next = net;
+            }
+            prev = net;
         }
     }
     xmlXPathFreeObject(obj);
@@ -933,49 +1080,65 @@ static struct qemud_vm_def *qemudParseXML(struct qemud_server *server,
 static char *
 qemudNetworkIfaceConnect(struct qemud_server *server,
                          struct qemud_vm *vm,
-                         struct qemud_vm_net_def *net)
+                         struct qemud_vm_net_def *net,
+                         int vlan)
 {
-    struct qemud_network *network;
-    const char *tapifname;
+    struct qemud_network *network = NULL;
+    char *brname;
+    char *ifname;
     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') {
+    if (net->type == QEMUD_NET_NETWORK) {
+        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;
+        }
+        brname = network->bridge;
+        if (net->dst.network.ifname[0] == '\0' ||
+            strchr(net->dst.network.ifname, '%')) {
+            strcpy(net->dst.network.ifname, "vnet%d");
+        }
+        ifname = net->dst.network.ifname;
+    } else if (net->type == QEMUD_NET_BRIDGE) {
+        brname = net->dst.bridge.brname;
+        if (net->dst.bridge.ifname[0] == '\0' ||
+            strchr(net->dst.bridge.ifname, '%')) {
+            strcpy(net->dst.bridge.ifname, "vnet%d");
+        }
+        ifname = net->dst.bridge.ifname;
+    } else {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "Network '%s' not active", net->dst.network.name);
+                         "Network type %d is not supported", net->type);
         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))) {
+    if ((err = brAddTap(server->brctl, brname,
+                        ifname, 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));
+                         ifname, brname, strerror(err));
         goto error;
     }
 
-    if ((err = iptablesAddPhysdevForward(server->iptables, net->dst.network.tapifname))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "Failed to add iptables rule to allow bridging from '%s' :%s",
-                         net->dst.network.tapifname, strerror(err));
-        goto error;
+    if (net->type == QEMUD_NET_NETWORK && network->def->forward) {
+        if ((err = iptablesAddPhysdevForward(server->iptables, ifname, network->def->forwardDev))) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Failed to add iptables rule to allow bridging from '%s' :%s",
+                             ifname, strerror(err));
+            goto error;
+        }
     }
 
-    snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=", tapfd);
+    snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=,vlan=%d", tapfd, vlan);
 
     if (!(retval = strdup(tapfdstr)))
         goto no_memory;
@@ -990,7 +1153,8 @@ qemudNetworkIfaceConnect(struct qemud_server *server,
     return retval;
 
  no_memory:
-    iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname);
+    if (net->type == QEMUD_NET_NETWORK && network->def->forward)
+        iptablesRemovePhysdevForward(server->iptables, ifname, network->def->forwardDev);
     qemudReportError(server, VIR_ERR_NO_MEMORY, "tapfds");
  error:
     if (retval)
@@ -1137,36 +1301,88 @@ int qemudBuildCommandLine(struct qemud_server *server,
         if (!((*argv)[++n] = strdup("none")))
             goto no_memory;
     } else {
+        int vlan = 0;
         while (net) {
             char nic[3+1+7+1+17+1];
 
-            if (!net->mac[0] && !net->mac[1] && !net->mac[2] &&
-                !net->mac[3] && !net->mac[4] && !net->mac[5]) {
-                strncpy(nic, "nic", 4);
-            } else {
-                sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-                        net->mac[0], net->mac[1],
-                        net->mac[2], net->mac[3],
-                        net->mac[4], net->mac[5]);
-            }
+            sprintf(nic, "nic,macaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d",
+                    net->mac[0], net->mac[1],
+                    net->mac[2], net->mac[3],
+                    net->mac[4], net->mac[5],
+                    vlan);
 
             if (!((*argv)[++n] = strdup("-net")))
                 goto no_memory;
             if (!((*argv)[++n] = strdup(nic)))
                 goto no_memory;
+
             if (!((*argv)[++n] = strdup("-net")))
                 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)))
+            switch (net->type) {
+            case QEMUD_NET_NETWORK:
+            case QEMUD_NET_BRIDGE:
+                if (!((*argv)[++n] = qemudNetworkIfaceConnect(server, vm, net, vlan)))
                     goto error;
+                break;
+
+            case QEMUD_NET_ETHERNET:
+                {
+                    char arg[PATH_MAX];
+                    if (snprintf(arg, PATH_MAX-1, "tap,ifname=%s,script=%s,vlan=%d",
+                                 net->dst.ethernet.ifname,
+                                 net->dst.ethernet.script,
+                                 vlan) >= (PATH_MAX-1))
+                        goto error;
+
+                    if (!((*argv)[++n] = strdup(arg)))
+                        goto no_memory;
+                }
+                break;
+
+            case QEMUD_NET_CLIENT:
+            case QEMUD_NET_SERVER:
+            case QEMUD_NET_MCAST:
+                {
+                    char arg[PATH_MAX];
+                    const char *mode = NULL;
+                    switch (net->type) {
+                    case QEMUD_NET_CLIENT:
+                        mode = "connect";
+                        break;
+                    case QEMUD_NET_SERVER:
+                        mode = "listen";
+                        break;
+                    case QEMUD_NET_MCAST:
+                        mode = "mcast";
+                        break;
+                    }
+                    if (snprintf(arg, PATH_MAX-1, "socket,%s=%s:%d,vlan=%d",
+                                 mode,
+                                 net->dst.socket.address,
+                                 net->dst.socket.port,
+                                 vlan) >= (PATH_MAX-1))
+                        goto error;
+
+                    if (!((*argv)[++n] = strdup(arg)))
+                        goto no_memory;
+                }
+                break;
+
+            case QEMUD_NET_USER:
+            default:
+                {
+                    char arg[PATH_MAX];
+                    if (snprintf(arg, PATH_MAX-1, "user,vlan=%d", vlan) >= (PATH_MAX-1))
+                        goto error;
+
+                    if (!((*argv)[++n] = strdup(arg)))
+                        goto no_memory;
+                }
             }
 
             net = net->next;
+            vlan++;
         }
     }
 
@@ -1567,7 +1783,7 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
                                                       xmlDocPtr xml) {
     xmlNodePtr root = NULL;
     xmlXPathContextPtr ctxt = NULL;
-    xmlXPathObjectPtr obj = NULL;
+    xmlXPathObjectPtr obj = NULL, tmp = NULL;
     struct qemud_network_def *def;
 
     if (!(def = calloc(1, sizeof(struct qemud_network_def)))) {
@@ -1620,6 +1836,31 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
     }
     xmlXPathFreeObject(obj);
 
+    obj = xmlXPathEval(BAD_CAST "count(/network/forward) > 0", ctxt);
+    if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) &&
+        obj->boolval) {
+        def->forward = 1;
+        tmp = xmlXPathEval(BAD_CAST "string(/network/forward[1]/@dev)", ctxt);
+        if ((tmp != NULL) && (tmp->type == XPATH_STRING) &&
+            (tmp->stringval != NULL) && (tmp->stringval[0] != 0)) {
+            int len;
+            if ((len = xmlStrlen(tmp->stringval)) >= (BR_IFNAME_MAXLEN-1)) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "forward device name '%s' is too long",
+                                 (char*)tmp->stringval);
+                goto error;
+            }
+            strcpy(def->forwardDev, (char*)tmp->stringval);
+        } else {
+            def->forwardDev[0] = '\0';
+        }
+        xmlXPathFreeObject(tmp);
+        tmp = NULL;
+    } else {
+        def->forward = 0;
+    }
+    xmlXPathFreeObject(obj);
+
     /* Parse bridge information */
     obj = xmlXPathEval(BAD_CAST "/network/bridge[1]", ctxt);
     if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
@@ -1649,6 +1890,8 @@ static struct qemud_network_def *qemudParseNetworkXML(struct qemud_server *serve
        the caller ? */
     if (obj)
         xmlXPathFreeObject(obj);
+    if (tmp)
+        xmlXPathFreeObject(tmp);
     if (ctxt)
         xmlXPathFreeContext(ctxt);
     qemudFreeNetworkDef(def);
@@ -2320,34 +2563,65 @@ char *qemudGenerateXML(struct qemud_server *server,
     while (net) {
         const char *types[] = {
             "user",
-            "tap",
+            "ethernet",
             "server",
             "client",
             "mcast",
             "network",
-            "vde",
+            "bridge",
         };
         if (qemudBufferPrintf(&buf, "    <interface type='%s'>\n",
                               types[net->type]) < 0)
             goto no_memory;
 
-        if (net->mac[0] && net->mac[1] && net->mac[2] &&
-            net->mac[3] && net->mac[4] && net->mac[5] &&
-            qemudBufferPrintf(&buf, "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+        if (qemudBufferPrintf(&buf, "      <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
                               net->mac[0], net->mac[1], net->mac[2],
                               net->mac[3], net->mac[4], net->mac[5]) < 0)
             goto no_memory;
 
-        if (net->type == QEMUD_NET_NETWORK) {
-            if (qemudBufferPrintf(&buf, "      <source network='%s'", net->dst.network.name) < 0)
+        switch (net->type) {
+        case QEMUD_NET_NETWORK:
+            if (qemudBufferPrintf(&buf, "      <source network='%s'/>\n", 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 (net->dst.network.ifname[0] != '\0') {
+                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.network.ifname) < 0)
+                    goto no_memory;
+            }
+            break;
 
-            if (qemudBufferPrintf(&buf, "/>\n") < 0)
+        case QEMUD_NET_ETHERNET:
+            if (net->dst.ethernet.ifname[0] != '\0') {
+                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.ethernet.ifname) < 0)
+                    goto no_memory;
+            }
+            if (net->dst.ethernet.script[0] != '\0') {
+                if (qemudBufferPrintf(&buf, "      <script path='%s'/>\n", net->dst.ethernet.script) < 0)
+                    goto no_memory;
+            }
+            break;
+
+        case QEMUD_NET_BRIDGE:
+            if (qemudBufferPrintf(&buf, "      <source dev='%s'/>\n", net->dst.bridge.brname) < 0)
                 goto no_memory;
+            if (net->dst.bridge.ifname[0] != '\0') {
+                if (qemudBufferPrintf(&buf, "      <target dev='%s'/>\n", net->dst.bridge.ifname) < 0)
+                    goto no_memory;
+            }
+            break;
+
+        case QEMUD_NET_SERVER:
+        case QEMUD_NET_CLIENT:
+        case QEMUD_NET_MCAST:
+            if (net->dst.socket.address[0] != '\0') {
+                if (qemudBufferPrintf(&buf, "      <source address='%s' port='%d'/>\n",
+                                      net->dst.socket.address, net->dst.socket.port) < 0)
+                    goto no_memory;
+            } else {
+                if (qemudBufferPrintf(&buf, "      <source port='%d'/>\n",
+                                      net->dst.socket.port) < 0)
+                    goto no_memory;
+            }
         }
 
         if (qemudBufferPrintf(&buf, "    </interface>\n") < 0)
@@ -2428,6 +2702,15 @@ char *qemudGenerateNetworkXML(struct qemud_server *server,
                           uuid[12], uuid[13], uuid[14], uuid[15]) < 0)
         goto no_memory;
 
+    if (def->forward) {
+        if (def->forwardDev[0]) {
+            qemudBufferPrintf(&buf, "  <forward dev='%s'/>\n",
+                              def->forwardDev);
+        } else {
+            qemudBufferAdd(&buf, "  <forward/>\n");
+        }
+    }
+
     if ((def->bridge != '\0' || def->disableSTP || def->forwardDelay) &&
         qemudBufferPrintf(&buf, "  <bridge name='%s' stp='%s' delay='%d' />\n",
                           def->bridge,
index b8f039536d78d1d5a569b1033b283605a34213d2..9cfc01ed78047f47f9e3c3bd1cc0951057b242bf 100644 (file)
@@ -1,6 +1,7 @@
 <network>
   <name>default</name>
   <bridge name="virbr0" />
+  <forward/>
   <ip address="192.168.122.1" netmask="255.255.255.0">
     <dhcp>
       <range start="192.168.122.2" end="192.168.122.254" />
index a4a890a3b1cad8b2faa5ca31871b951ceb3c9b79..777b625d73b1a31c277970a1ac2a4509e687e945 100644 (file)
@@ -103,43 +103,35 @@ struct qemud_vm_disk_def {
 /* 5 different types of networking config */
 enum qemud_vm_net_type {
     QEMUD_NET_USER,
-    QEMUD_NET_TAP,
+    QEMUD_NET_ETHERNET,
     QEMUD_NET_SERVER,
     QEMUD_NET_CLIENT,
     QEMUD_NET_MCAST,
     QEMUD_NET_NETWORK,
-    /*  QEMUD_NET_VDE*/
+    QEMUD_NET_BRIDGE,
 };
 
 /* Stores the virtual network interface configuration */
 struct qemud_vm_net_def {
     int type;
-    int vlan;
     unsigned char mac[QEMUD_MAC_ADDRESS_LEN];
     union {
         struct {
-            char ifname[NAME_MAX];
+            char ifname[BR_IFNAME_MAXLEN];
             char script[PATH_MAX];
-        } tap;
+        } ethernet;
         struct {
-            struct sockaddr_in listen;
+            char address[BR_INET_ADDR_MAXLEN];
             int port;
-        } server;
-        struct {
-            struct sockaddr_in connect;
-            int port;
-        } client;
-        struct {
-            struct sockaddr_in group;
-            int port;
-        } mcast;
-        struct {
-            char vlan[PATH_MAX];
-        } vde;
+        } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
         struct {
             char name[QEMUD_MAX_NAME_LEN];
-            char tapifname[BR_IFNAME_MAXLEN];
+            char ifname[BR_IFNAME_MAXLEN];
         } network;
+        struct {
+            char brname[BR_IFNAME_MAXLEN];
+            char ifname[BR_IFNAME_MAXLEN];
+        } bridge;
     } dst;
 
     struct qemud_vm_net_def *next;
@@ -249,6 +241,9 @@ struct qemud_network_def {
     int disableSTP;
     int forwardDelay;
 
+    int forward;
+    char forwardDev[BR_IFNAME_MAXLEN];
+
     char ipAddress[BR_INET_ADDR_MAXLEN];
     char netmask[BR_INET_ADDR_MAXLEN];
 
index 366b2dee0ce2109b9c0102df95eeaac976eea6ef..6731224e2302aa7efffeb55363bca1d068ecd0c9 100644 (file)
@@ -532,20 +532,17 @@ iptablesInput(iptablesContext *ctx,
               int tcp)
 {
     char portstr[32];
-    int ret;
 
     snprintf(portstr, sizeof(portstr), "%d", port);
     portstr[sizeof(portstr) - 1] = '\0';
 
-    ret = iptablesAddRemoveRule(ctx->input_filter,
-                                action,
-                                "--in-interface", iface,
-                                "--protocol", tcp ? "tcp" : "udp",
-                                "--destination-port", portstr,
-                                "--jump", "ACCEPT",
-                                NULL);
-
-    return ret;
+    return iptablesAddRemoveRule(ctx->input_filter,
+                                 action,
+                                 "--in-interface", iface,
+                                 "--protocol", tcp ? "tcp" : "udp",
+                                 "--destination-port", portstr,
+                                 "--jump", "ACCEPT",
+                                 NULL);
 }
 
 int
@@ -583,106 +580,158 @@ iptablesRemoveUdpInput(iptablesContext *ctx,
 static int
 iptablesPhysdevForward(iptablesContext *ctx,
                        const char *iface,
+                       const char *target,
                        int action)
 {
-    return iptablesAddRemoveRule(ctx->forward_filter,
-                                 action,
-                                 "--match", "physdev",
-                                 "--physdev-in", iface,
-                                 "--jump", "ACCEPT",
-                                 NULL);
+    if (target && target[0]) {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--match", "physdev",
+                                     "--physdev-in", iface,
+                                     "--out", target,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    } else {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--match", "physdev",
+                                     "--physdev-in", iface,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    }
 }
 
 int
 iptablesAddPhysdevForward(iptablesContext *ctx,
-                          const char *iface)
+                          const char *iface,
+                          const char *target)
 {
-    return iptablesPhysdevForward(ctx, iface, ADD);
+    return iptablesPhysdevForward(ctx, iface, target, ADD);
 }
 
 int
 iptablesRemovePhysdevForward(iptablesContext *ctx,
-                             const char *iface)
+                             const char *iface,
+                             const char *target)
 {
-    return iptablesPhysdevForward(ctx, iface, REMOVE);
+    return iptablesPhysdevForward(ctx, iface, target, REMOVE);
 }
 
 static int
 iptablesInterfaceForward(iptablesContext *ctx,
                          const char *iface,
+                         const char *target,
                          int action)
 {
-    return iptablesAddRemoveRule(ctx->forward_filter,
-                                 action,
-                                 "--in-interface", iface,
-                                 "--jump", "ACCEPT",
-                                 NULL);
+    if (target && target[0]) {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--in-interface", iface,
+                                     "--out-interface", target,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    } else {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--in-interface", iface,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    }
 }
 
 int
 iptablesAddInterfaceForward(iptablesContext *ctx,
-                            const char *iface)
+                            const char *iface,
+                            const char *target)
 {
-    return iptablesInterfaceForward(ctx, iface, ADD);
+    return iptablesInterfaceForward(ctx, iface, target, ADD);
 }
 
 int
 iptablesRemoveInterfaceForward(iptablesContext *ctx,
-                               const char *iface)
+                               const char *iface,
+                               const char *target)
 {
-    return iptablesInterfaceForward(ctx, iface, REMOVE);
+    return iptablesInterfaceForward(ctx, iface, target, REMOVE);
 }
 
 static int
 iptablesStateForward(iptablesContext *ctx,
                      const char *iface,
+                     const char *target,
                      int action)
 {
-    return iptablesAddRemoveRule(ctx->forward_filter,
-                                 action,
-                                 "--out-interface", iface,
-                                 "--match", "state",
-                                 "--state", "ESTABLISHED,RELATED",
-                                 "--jump", "ACCEPT",
-                                 NULL);
+    if (target && target[0]) {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--in-interface", target,
+                                     "--out-interface", iface,
+                                     "--match", "state",
+                                     "--state", "ESTABLISHED,RELATED",
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    } else {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--out-interface", iface,
+                                     "--match", "state",
+                                     "--state", "ESTABLISHED,RELATED",
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    }
 }
 
 int
 iptablesAddStateForward(iptablesContext *ctx,
-                        const char *iface)
+                        const char *iface,
+                        const char *target)
 {
-    return iptablesStateForward(ctx, iface, ADD);
+    return iptablesStateForward(ctx, iface, target, ADD);
 }
 
 int
 iptablesRemoveStateForward(iptablesContext *ctx,
-                           const char *iface)
+                           const char *iface,
+                           const char *target)
 {
-    return iptablesStateForward(ctx, iface, REMOVE);
+    return iptablesStateForward(ctx, iface, target, REMOVE);
 }
 
 static int
 iptablesNonBridgedMasq(iptablesContext *ctx,
+                       const char *target,
                        int action)
 {
-    return iptablesAddRemoveRule(ctx->nat_postrouting,
-                                 action,
-                                 "--match", "physdev",
-                                 "!", "--physdev-is-bridged",
-                                 "--jump", "MASQUERADE",
-                                 NULL);
+    if (target && target[0]) {
+        return iptablesAddRemoveRule(ctx->nat_postrouting,
+                                     action,
+                                     "--out-interface", target,
+                                     "--match", "physdev",
+                                     "!", "--physdev-is-bridged",
+                                     "--jump", "MASQUERADE",
+                                     NULL);
+    } else {
+        return iptablesAddRemoveRule(ctx->nat_postrouting,
+                                     action,
+                                     "--match", "physdev",
+                                     "!", "--physdev-is-bridged",
+                                     "--jump", "MASQUERADE",
+                                     NULL);
+    }
 }
 
 int
-iptablesAddNonBridgedMasq(iptablesContext *ctx)
+iptablesAddNonBridgedMasq(iptablesContext *ctx,
+                          const char *target)
 {
-    return iptablesNonBridgedMasq(ctx, ADD);
+    return iptablesNonBridgedMasq(ctx, target, ADD);
 }
 
 int
-iptablesRemoveNonBridgedMasq(iptablesContext *ctx)
+iptablesRemoveNonBridgedMasq(iptablesContext *ctx,
+                             const char *target)
 {
-    return iptablesNonBridgedMasq(ctx, REMOVE);
+    return iptablesNonBridgedMasq(ctx, target, REMOVE);
 }
 
 /*
index 3e1e79ec659342e69af033f4e7639c20ce0a3e9f..395d5b37806793b976dd16e45b5c393064f79e4d 100644 (file)
@@ -42,22 +42,30 @@ int              iptablesRemoveUdpInput          (iptablesContext *ctx,
                                                   int port);
 
 int              iptablesAddPhysdevForward       (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 int              iptablesRemovePhysdevForward    (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 
 int              iptablesAddInterfaceForward     (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 int              iptablesRemoveInterfaceForward  (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 
 int              iptablesAddStateForward         (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 int              iptablesRemoveStateForward      (iptablesContext *ctx,
-                                                  const char *iface);
+                                                  const char *iface,
+                                                  const char *target);
 
-int              iptablesAddNonBridgedMasq       (iptablesContext *ctx);
-int              iptablesRemoveNonBridgedMasq    (iptablesContext *ctx);
+int              iptablesAddNonBridgedMasq       (iptablesContext *ctx,
+                                                  const char *target);
+int              iptablesRemoveNonBridgedMasq    (iptablesContext *ctx,
+                                                  const char *target);
 
 #endif /* __QEMUD_IPTABLES_H__ */
 
index 0aab7c91b83b452888449abf4a83ab4f7eab806d..e1914a379d776842b5e0071237952b56c63d323a 100644 (file)
@@ -1032,7 +1032,18 @@ static void
 qemudNetworkIfaceDisconnect(struct qemud_server *server,
                             struct qemud_vm *vm ATTRIBUTE_UNUSED,
                             struct qemud_vm_net_def *net) {
-    iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname);
+    struct qemud_network *network;
+    if (net->type != QEMUD_NET_NETWORK)
+        return;
+
+    if (!(network = qemudFindNetworkByName(server, net->dst.network.name))) {
+        return;
+    } else if (network->bridge[0] == '\0') {
+        return;
+    }
+
+    if (network->def->forward)
+        iptablesRemovePhysdevForward(server->iptables, net->dst.network.ifname, network->def->forwardDev);
 }
 
 int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
@@ -1105,7 +1116,7 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
                       struct qemud_network *network,
                       char ***argv) {
     int i, len;
-    char buf[BR_INET_ADDR_MAXLEN * 2];
+    char buf[PATH_MAX];
     struct qemud_dhcp_range_def *range;
 
     len =
@@ -1114,8 +1125,10 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
         1 + /* --bind-interfaces */
         2 + /* --pid-file "" */
         2 + /* --conf-file "" */
+        /*2 + *//* --interface virbr0 */
         2 + /* --except-interface lo */
         2 + /* --listen-address 10.0.0.1 */
+        1 + /* --dhcp-leasefile=path */
         (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
         1;  /* NULL */
 
@@ -1142,11 +1155,29 @@ qemudBuildDnsmasqArgv(struct qemud_server *server,
     APPEND_ARG(*argv, i++, "--conf-file");
     APPEND_ARG(*argv, i++, "");
 
+    /*
+     * XXX does not actually work, due to some kind of
+     * race condition setting up ipv6 addresses on the
+     * interface. A sleep(10) makes it work, but that's
+     * clearly not practical
+     *
+     * APPEND_ARG(*argv, i++, "--interface");
+     * APPEND_ARG(*argv, i++, network->def->bridge);
+     */
+    APPEND_ARG(*argv, i++, "--listen-address");
+    APPEND_ARG(*argv, i++, network->def->ipAddress);
+
     APPEND_ARG(*argv, i++, "--except-interface");
     APPEND_ARG(*argv, i++, "lo");
 
-    APPEND_ARG(*argv, i++, "--listen-address");
-    APPEND_ARG(*argv, i++, network->def->ipAddress);
+    /*
+     * NB, dnsmasq command line arg bug means we need to
+     * use a single arg '--dhcp-leasefile=path' rather than
+     * two separate args in '--dhcp-leasefile path' style
+     */
+    snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases",
+             LOCAL_STATE_DIR, network->def->name);
+    APPEND_ARG(*argv, i++, buf);
 
     range = network->def->ranges;
     while (range) {
@@ -1211,7 +1242,7 @@ qemudAddIptablesRules(struct qemud_server *server,
     }
 
     /* allow bridging from the bridge interface itself */
-    if ((err = iptablesAddPhysdevForward(server->iptables, network->bridge))) {
+    if ((err = iptablesAddPhysdevForward(server->iptables, network->bridge, network->def->forwardDev))) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                          "failed to add iptables rule to allow bridging from '%s' : %s\n",
                          network->bridge, strerror(err));
@@ -1219,7 +1250,7 @@ qemudAddIptablesRules(struct qemud_server *server,
     }
 
     /* allow forwarding packets from the bridge interface */
-    if ((err = iptablesAddInterfaceForward(server->iptables, network->bridge))) {
+    if ((err = iptablesAddInterfaceForward(server->iptables, network->bridge, network->def->forwardDev))) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                          "failed to add iptables rule to allow forwarding from '%s' : %s\n",
                          network->bridge, strerror(err));
@@ -1227,7 +1258,7 @@ qemudAddIptablesRules(struct qemud_server *server,
     }
 
     /* allow forwarding packets to the bridge interface if they are part of an existing connection */
-    if ((err = iptablesAddStateForward(server->iptables, network->bridge))) {
+    if ((err = iptablesAddStateForward(server->iptables, network->bridge, network->def->forwardDev))) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                          "failed to add iptables rule to allow forwarding to '%s' : %s\n",
                          network->bridge, strerror(err));
@@ -1235,7 +1266,7 @@ qemudAddIptablesRules(struct qemud_server *server,
     }
 
     /* enable masquerading */
-    if ((err = iptablesAddNonBridgedMasq(server->iptables))) {
+    if ((err = iptablesAddNonBridgedMasq(server->iptables, network->def->forwardDev))) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                          "failed to add iptables rule to enable masquerading : %s\n",
                          strerror(err));
@@ -1281,13 +1312,13 @@ qemudAddIptablesRules(struct qemud_server *server,
  err6:
     iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
  err5:
-    iptablesRemoveNonBridgedMasq(server->iptables);
+    iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
  err4:
-    iptablesRemoveStateForward(server->iptables, network->bridge);
+    iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
  err3:
-    iptablesRemoveInterfaceForward(server->iptables, network->bridge);
+    iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
  err2:
-    iptablesRemovePhysdevForward(server->iptables, network->bridge);
+    iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
  err1:
     return 0;
 }
@@ -1295,14 +1326,16 @@ qemudAddIptablesRules(struct qemud_server *server,
 static void
 qemudRemoveIptablesRules(struct qemud_server *server,
                          struct qemud_network *network) {
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
-    iptablesRemoveNonBridgedMasq(server->iptables);
-    iptablesRemoveStateForward(server->iptables, network->bridge);
-    iptablesRemoveInterfaceForward(server->iptables, network->bridge);
-    iptablesRemovePhysdevForward(server->iptables, network->bridge);
+    if (network->def->forward) {
+        iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
+        iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
+        iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
+        iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
+        iptablesRemoveNonBridgedMasq(server->iptables, network->def->forwardDev);
+        iptablesRemoveStateForward(server->iptables, network->bridge, network->def->forwardDev);
+        iptablesRemoveInterfaceForward(server->iptables, network->bridge, network->def->forwardDev);
+        iptablesRemovePhysdevForward(server->iptables, network->bridge, network->def->forwardDev);
+    }
 }
 
 static int
@@ -1379,10 +1412,12 @@ int qemudStartNetworkDaemon(struct qemud_server *server,
         goto err_delbr;
     }
 
-    if (!qemudAddIptablesRules(server, network))
+    if (network->def->forward &&
+        !qemudAddIptablesRules(server, network))
         goto err_delbr1;
 
-    if (!qemudEnableIpForwarding()) {
+    if (network->def->forward &&
+        !qemudEnableIpForwarding()) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
                          "failed to enable IP forwarding : %s\n", strerror(err));
         goto err_delbr2;