[Libvir] A whole tonne of networking fixes / enhancements

Daniel P. Berrange berrange at redhat.com
Tue Mar 13 04:28:16 UTC 2007


I've been testing the networking support and found various bugs / missing
features that I thought we really need to have in the release - some of
them impact the XML so we have to get this right now.

 - Build up in memory linked-list of network devices & disk devices in
   same order as they are listed in XML. Currently they are built up
   in reversed order, which makes the XML not be idempotent, and also
   means that if you have multiple NICs, what you think is eth0 ends
   up being eth4 and what you think is eth4 is eth0. This patch fixes
   the ordering to match XML.

 - Set the 'vlan' attribute in command line args to QEMU. This ensures
   that separate network devices are in fact separated. Previously if
   you had multiple NICs, QEMU connected them all to the same VLAN so
   any traffic on one NIC got sent to all NICs. Most definitely not
   what you want in any usual scenario, and created a traffic storm
   from the resultant network loops !

 - Added support for networking of  type='bridge'. This gives parity
   with equivalent Xen networking, eg

      <interface type='bridge'>
        <source dev='xenbr0'/>
        <target dev='vnet3'/>
      </interface>

   Will create a tap device called vnet3 and bridge it into xenbr0

 - Added support for networking of type='ethernet'. This give parity
   with equivlent Xen networking, eg

     <interface type='ethernet'>
       <script path='/etc/qemu-ifup'/>
       <target dev='vnet5'/>
     </interface>

   Will create a tap device called vnet5 and run 'qemu-ifup' to setup
   its configuration. Think the various non-bridge Xen networking configs.

 - Added support for 'client', 'server', 'mcast' networking types. These
   are QEMU specific types, allowing unprivileged (or privileged) users
   to create virtual networks without TAP devices.

   eg two machines, one with

      <interface type='server'>
        <source address="127.0.0.1" port="5555"/>
      </interface>

   And the other with

      <interface type='client'>
        <source address="127.0.0.1" port="5555"/>
      </interface>

   Or both using multicast:

      <interface type='mcast'>
        <source address="230.0.0.1" port="5558"/>
      </interface>

   Both these options allow QEMU instancs on different physical machines
   to talk to each other. The multicast protocol is also compatible with
   the UserModeLinux multicast protocol.

 - Fix the 'type=network' config use the <target dev='vnet3'> element
   instead of a custom  tapifname=vnet3 attribute - this gives consistent
   way to name tap devices that - most importantly -  matches the 
   Xen XML format for specifying vifname, eg

       <interface type='network'>
         <source network='default'/>
         <target dev='vnet2'/>
       </interface>

   Will create a tapdevice called vnet2 and connect it to the bridge
   device associated with the network 'default'.

 - Removed references to 'vde' - we're not using this explicitly - at
   some time in the future, we'll perhaps use VDE for doing virtual
   networking for unprivileged users where bridge devices are not
   available

 - Removed references to 'tap' network type - this is basically handled
   by the 'ethernet' network type to give XML compatability with the
   same functionality in the Xen backend.

 - The virtual network configuration currently always adds whole bunch
   of IPTables rules to the FORWARD/POSTROUTING chain which allow traffic
   from the virtual network to be masqueraded out through any active
   physical interface.  This may be correct thing todo for the default
   network, but we also need the ability to create totally isolated
   networks (no forwarding at all), or directed networks (eg forwarding
   to an explicit physical device). 

   To deal with this scenario I introduce a new element in the network
   XML called '<forward>'. If this is not present, then no forwarding
   rules are added at all. If it is present, but with no attributes
   then a generic rule allowing forwarding to any interface is added.
   If it is present and the 'dev' attribute is specific then forwarding
   is only allowed to that named interface. The default network XML thus
   now includes

        <forward/>

   So that by default we have a virtual network connected to all physical
   devices.

 - MAC addreses were not be autogenerated inside libvirt_qemud. If you
   don't provide a MAC address, QEMU (insanely) uses a hardcoded default.
   So all NICs end up with an identical MAC. We now always autogenerate
   a MAC address if not explicitly listed in XML.


One final thing to be aware of - the Fedora Core 6 Xen kernel currently has
totally fubar TCP checksum offland. So if you try to bridge a Xen guest into
the libvirt virtual networking, it'll fail to get a DHCP address from dnsmasq.
Even if you fix that by turning off TX checksums in Dom0, you'll get checksum
failures for the actual TCP data transmission too. The only solution is to
either upgrade the Dom0 kernel to a RHEL-5 vintage, or to also turn off
checksumming in the guest. A new FC6 xen kernel is in the works which should
hopefully fix this for real.

With fixed kernel, I can easily setup virtual networks connecting both
Xen PV, Xen FV and QEMU instances together.

Anyway, the upshot of all this, is that we can now trivially create really
complicated & fun networking layouts across QEMU & Xen, using a mixture of
bridging, NAT, isolated LANs, and tunnelled VLANS :-)  We really ought to
document it a little though

Since Mark is off on vacation for a while, I'd appreciate people taking a
close look at this / actually giving it a try if you can.

It is possible to create a totally isolated network using

  <network>
    <name>private</name>
    <uuid>d237ce44-8efa-452c-b8e6-1ae9cf53aeb1</uuid>
    <bridge name="virbr0" />
    <ip address="192.168.122.1" netmask="255.255.255.0">
      <dhcp>
        <range start="192.168.122.2" end="192.168.122.254" />
      </dhcp>
    </ip>
  </network>

And a QEMU guest with 5 (yes, 5)  network cards

<domain type='qemu'>
  <name>QEMUFirewall</name>
  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
  <memory>219200</memory>
  <currentMemory>219200</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type arch='i686' machine='pc'>hvm</type>
    <boot dev='hd'/>
  </os>
  <devices>
    <emulator>/usr/bin/qemu</emulator>
    <disk type='block' device='disk'>
      <source dev='/dev/HostVG/QEMUGuest1'/>
      <target dev='hda'/>
    </disk>
    <interface type='network'>
      <source network='private'/>
      <target dev='vnet1'/>
    </interface>
    <interface type='bridge'>
      <source dev='xenbr0'/>
      <target dev='vnet2'/>
    </interface>
    <interface type='ethernet'>
      <script path='/etc/dan-test-ifup'/>
      <target dev='vnet3'/>
    </interface>
    <interface type='server'>
      <source address="127.0.0.1" port="5555"/>
    </interface>
    <interface type='mcast'>
      <source address="230.0.0.1" port="5558"/>
    </interface>
    <graphics type='vnc' port='-1'/>
  </devices>
</domain>


In this XML, only eth1  is connected to the hosts public facing network.
The other NICs are all on various private networks. So this QEMU guest
is in essence a router/firewall box. eg, you could connected various
other guests to the 'private' virtual network, and the only way they
could reach the outside world is via this QEMU instance doing routing.

Regards,
Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
Index: qemud/bridge.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/bridge.c,v
retrieving revision 1.4
diff -u -p -r1.4 bridge.c
--- qemud/bridge.c	20 Feb 2007 09:57:47 -0000	1.4
+++ qemud/bridge.c	13 Mar 2007 03:53:20 -0000
@@ -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: qemud/bridge.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/bridge.h,v
retrieving revision 1.1
diff -u -p -r1.1 bridge.h
--- qemud/bridge.h	14 Feb 2007 16:02:40 -0000	1.1
+++ qemud/bridge.h	13 Mar 2007 03:53:20 -0000
@@ -49,7 +49,6 @@ int     brDeleteInterface       (brContr
 
 int     brAddTap                (brControl *ctl,
                                  const char *bridge,
-                                 const char *ifnameOrFmt,
                                  char *ifname,
                                  int maxlen,
                                  int *tapfd);
Index: qemud/conf.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/conf.c,v
retrieving revision 1.40
diff -u -p -r1.40 conf.c
--- qemud/conf.c	9 Mar 2007 03:08:34 -0000	1.40
+++ qemud/conf.c	13 Mar 2007 03:53:22 -0000
@@ -444,6 +444,15 @@ static struct qemud_vm_disk_def *qemudPa
     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 *qemudPar
     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 *qemudPar
     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 *qemudPar
             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 *qemudPar
                        (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 *qemudPar
         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 *qemudPar
             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 *qemudPar
             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 *qemudPar
  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 *qemudParseXM
     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 *qemudParseXM
     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 *qemudParseXM
 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_se
     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_s
         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 *qemudPa
                                                       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 *qemudPa
     }
     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 *qemudPa
        the caller ? */
     if (obj)
         xmlXPathFreeObject(obj);
+    if (tmp)
+        xmlXPathFreeObject(tmp);
     if (ctxt)
         xmlXPathFreeContext(ctxt);
     qemudFreeNetworkDef(def);
@@ -2320,34 +2563,65 @@ char *qemudGenerateXML(struct qemud_serv
     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 qem
                           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: qemud/default-network.xml
===================================================================
RCS file: /data/cvs/libvirt/qemud/default-network.xml,v
retrieving revision 1.1
diff -u -p -r1.1 default-network.xml
--- qemud/default-network.xml	7 Mar 2007 11:54:29 -0000	1.1
+++ qemud/default-network.xml	13 Mar 2007 03:53:22 -0000
@@ -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: qemud/internal.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/internal.h,v
retrieving revision 1.18
diff -u -p -r1.18 internal.h
--- qemud/internal.h	5 Mar 2007 17:15:20 -0000	1.18
+++ qemud/internal.h	13 Mar 2007 03:53:22 -0000
@@ -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: qemud/iptables.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/iptables.c,v
retrieving revision 1.3
diff -u -p -r1.3 iptables.c
--- qemud/iptables.c	20 Feb 2007 17:51:41 -0000	1.3
+++ qemud/iptables.c	13 Mar 2007 03:53:22 -0000
@@ -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 *
 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: qemud/iptables.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/iptables.h,v
retrieving revision 1.1
diff -u -p -r1.1 iptables.h
--- qemud/iptables.h	14 Feb 2007 16:26:42 -0000	1.1
+++ qemud/iptables.h	13 Mar 2007 03:53:22 -0000
@@ -42,22 +42,30 @@ int              iptablesRemoveUdpInput 
                                                   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: qemud/qemud.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/qemud.c,v
retrieving revision 1.32
diff -u -p -r1.32 qemud.c
--- qemud/qemud.c	6 Mar 2007 16:51:48 -0000	1.32
+++ qemud/qemud.c	13 Mar 2007 03:53:23 -0000
@@ -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_serve
                       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,8 @@ qemudBuildDnsmasqArgv(struct qemud_serve
         1 + /* --bind-interfaces */
         2 + /* --pid-file "" */
         2 + /* --conf-file "" */
+        2 + /* --interface virbr0 */
         2 + /* --except-interface lo */
-        2 + /* --listen-address 10.0.0.1 */
         (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
         1;  /* NULL */
 
@@ -1142,12 +1153,21 @@ qemudBuildDnsmasqArgv(struct qemud_serve
     APPEND_ARG(*argv, i++, "--conf-file");
     APPEND_ARG(*argv, i++, "");
 
-    APPEND_ARG(*argv, i++, "--except-interface");
-    APPEND_ARG(*argv, i++, "lo");
-
+    /*
+     * XXX does not actually work, due to some kind of
+     * race condition setting up ipv6 addresses on the
+     * interface. A sleep(10) makes it wor, 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");
+
     range = network->def->ranges;
     while (range) {
         snprintf(buf, sizeof(buf), "%s,%s",
@@ -1211,7 +1231,7 @@ qemudAddIptablesRules(struct qemud_serve
     }
 
     /* 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 +1239,7 @@ qemudAddIptablesRules(struct qemud_serve
     }
 
     /* 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 +1247,7 @@ qemudAddIptablesRules(struct qemud_serve
     }
 
     /* 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 +1255,7 @@ qemudAddIptablesRules(struct qemud_serve
     }
 
     /* 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 +1301,13 @@ qemudAddIptablesRules(struct qemud_serve
  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 +1315,16 @@ qemudAddIptablesRules(struct qemud_serve
 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 +1401,12 @@ int qemudStartNetworkDaemon(struct qemud
         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;


More information about the libvir-list mailing list