? routed-virtual-net.cvs.patch
? src/.qemu_conf.c.swp
? src/.qemu_driver.c.swp
Index: docs/network.rng
===================================================================
RCS file: /data/cvs/libvirt/docs/network.rng,v
retrieving revision 1.1
diff -u -r1.1 network.rng
--- docs/network.rng	24 Jul 2007 09:19:40 -0000	1.1
+++ docs/network.rng	8 Mar 2008 18:59:13 -0000
@@ -58,4 +58,11 @@
       <optional><attribute name="dev"><text/></attribute></optional>
     </element>
   </optional>
+  <optional>
+    <!-- The device through which the bridge is to be routed -->
+    <element name="route">
+      <optional><attribute name="dev"><text/></attribute></optional>
+    </element>
+  </optional>
+
 </element>
Index: src/iptables.c
===================================================================
RCS file: /data/cvs/libvirt/src/iptables.c,v
retrieving revision 1.23
diff -u -r1.23 iptables.c
--- src/iptables.c	27 Feb 2008 10:37:19 -0000	1.23
+++ src/iptables.c	8 Mar 2008 18:59:43 -0000
@@ -793,7 +793,7 @@
  * and associated with an existing connection
  */
 static int
-iptablesForwardAllowIn(iptablesContext *ctx,
+iptablesForwardAllowRelatedIn(iptablesContext *ctx,
                        const char *network,
                        const char *iface,
                        const char *physdev,
@@ -822,6 +822,77 @@
 }
 
 /**
+ * iptablesAddForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow the traffic for the
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
+                          const char *network,
+                          const char *iface,
+                          const char *physdev)
+{
+    return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * iptablesRemoveForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context hence forbidding the traffic for
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
+                             const char *network,
+                             const char *iface,
+                             const char *physdev)
+{
+    return iptablesForwardAllowRelatedIn(ctx, network, iface, physdev, REMOVE);
+}
+
+/* Allow all traffic destined to the bridge, with a valid network address
+ */
+static int
+iptablesForwardAllowIn(iptablesContext *ctx,
+                       const char *network,
+                       const char *iface,
+                       const char *physdev,
+                       int action)
+{
+    if (physdev && physdev[0]) {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--destination", network,
+                                     "--in-interface", physdev,
+                                     "--out-interface", iface,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    } else {
+        return iptablesAddRemoveRule(ctx->forward_filter,
+                                     action,
+                                     "--destination", network,
+                                     "--out-interface", iface,
+                                     "--jump", "ACCEPT",
+                                     NULL);
+    }
+}
+
+/**
  * iptablesAddForwardAllowIn:
  * @ctx: pointer to the IP table context
  * @network: the source network name
Index: src/qemu_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_conf.c,v
retrieving revision 1.41
diff -u -r1.41 qemu_conf.c
--- src/qemu_conf.c	3 Mar 2008 18:11:16 -0000	1.41
+++ src/qemu_conf.c	8 Mar 2008 18:59:51 -0000
@@ -2472,6 +2472,41 @@
     }
     xmlXPathFreeObject(obj);
 
+    /* IPv4 routing setup */
+    obj = xmlXPathEval(BAD_CAST "count(/network/route) > 0", ctxt);
+    if ((obj != NULL) && (obj->type == XPATH_BOOLEAN) &&
+        obj->boolval) {
+        if (!def->ipAddress[0] ||
+            !def->netmask[0] ||
+            def->forward) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "Routing requested, but no IPv4 address/netmask provided, or forwarding already enabled");
+            goto error;
+        }
+
+        def->route = 1;
+        tmp = xmlXPathEval(BAD_CAST "string(/network/route[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(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 "route device name '%s' is too long",
+                                 (char*)tmp->stringval);
+                goto error;
+            }
+            strcpy(def->routeDev, (char*)tmp->stringval);
+        } else {
+            def->routeDev[0] = '\0';
+        }
+        xmlXPathFreeObject(tmp);
+        tmp = NULL;
+    } else {
+        def->route = 0;
+    }
+    xmlXPathFreeObject(obj);
+
+
     xmlXPathFreeContext(ctxt);
 
     return def;
@@ -3092,6 +3127,15 @@
         }
     }
 
+    if (def->route) {
+        if (def->routeDev[0]) {
+            virBufferVSprintf(buf, "  <route dev='%s'/>\n",
+                              def->routeDev);
+        } else {
+            virBufferAddLit(buf, "  <route/>\n");
+        }
+    }
+
     virBufferAddLit(buf, "  <bridge");
     if (qemudIsActiveNetwork(network)) {
         if (virBufferVSprintf(buf, " name='%s'", network->bridge) < 0)
Index: src/qemu_conf.h
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_conf.h,v
retrieving revision 1.19
diff -u -r1.19 qemu_conf.h
--- src/qemu_conf.h	27 Feb 2008 04:35:08 -0000	1.19
+++ src/qemu_conf.h	8 Mar 2008 18:59:52 -0000
@@ -268,6 +268,9 @@
     int forward;
     char forwardDev[BR_IFNAME_MAXLEN];
 
+    int route;
+    char routeDev[BR_IFNAME_MAXLEN];
+
     char ipAddress[BR_INET_ADDR_MAXLEN];
     char netmask[BR_INET_ADDR_MAXLEN];
     char network[BR_INET_ADDR_MAXLEN+BR_INET_ADDR_MAXLEN+1];
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.57
diff -u -r1.57 qemu_driver.c
--- src/qemu_driver.c	27 Feb 2008 04:37:07 -0000	1.57
+++ src/qemu_driver.c	8 Mar 2008 18:59:59 -0000
@@ -948,6 +948,98 @@
 }
 
 static int
+qemudAddMasqueradingIptablesRules(virConnectPtr conn,
+                      struct qemud_driver *driver,
+                      struct qemud_network *network) {
+    int err;
+    /* allow forwarding packets from the bridge interface */
+    if ((err = iptablesAddForwardAllowOut(driver->iptables,
+                                          network->def->network,
+                                          network->bridge,
+                                          network->def->forwardDev))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow forwarding from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto masqerr1;
+    }
+
+    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
+    if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables,
+                                         network->def->network,
+                                         network->bridge,
+                                         network->def->forwardDev))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow forwarding to '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto masqerr2;
+    }
+
+    /* enable masquerading */
+    if ((err = iptablesAddForwardMasquerade(driver->iptables,
+                                            network->def->network,
+                                            network->def->forwardDev))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to enable masquerading : %s\n",
+                         strerror(err));
+        goto masqerr3;
+    }
+
+    return 1;
+
+ masqerr3:
+    iptablesRemoveForwardAllowRelatedIn(driver->iptables,
+                                 network->def->network,
+                                 network->bridge,
+                                 network->def->forwardDev);
+ masqerr2:
+    iptablesRemoveForwardAllowOut(driver->iptables,
+                                  network->def->network,
+                                  network->bridge,
+                                  network->def->forwardDev);
+ masqerr1:
+    return 0;
+}
+
+static int
+qemudAddRoutingIptablesRules(virConnectPtr conn,
+                      struct qemud_driver *driver,
+                      struct qemud_network *network) {
+    int err;
+    /* allow routing packets from the bridge interface */
+    if ((err = iptablesAddForwardAllowOut(driver->iptables,
+                                          network->def->network,
+                                          network->bridge,
+                                          network->def->routeDev))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow routing from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto routeerr1;
+    }
+
+    /* allow routing packets to the bridge interface */
+    if ((err = iptablesAddForwardAllowIn(driver->iptables,
+                                         network->def->network,
+                                         network->bridge,
+                                         network->def->routeDev))) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow routing to '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto routeerr2;
+    }
+
+    return 1;
+
+
+ routeerr2:
+    iptablesRemoveForwardAllowOut(driver->iptables,
+                                  network->def->network,
+                                  network->bridge,
+                                  network->def->forwardDev);
+ routeerr1:
+    return 0;
+}
+
+static int
 qemudAddIptablesRules(virConnectPtr conn,
                       struct qemud_driver *driver,
                       struct qemud_network *network) {
@@ -1014,59 +1106,19 @@
         goto err7;
     }
 
-
-    /* The remaining rules are only needed for IP forwarding */
-    if (!network->def->forward) {
-        iptablesSaveRules(driver->iptables);
-        return 1;
-    }
-
-    /* allow forwarding packets from the bridge interface */
-    if ((err = iptablesAddForwardAllowOut(driver->iptables,
-                                          network->def->network,
-                                          network->bridge,
-                                          network->def->forwardDev))) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow forwarding from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err8;
-    }
-
-    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
-    if ((err = iptablesAddForwardAllowIn(driver->iptables,
-                                         network->def->network,
-                                         network->bridge,
-                                         network->def->forwardDev))) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow forwarding to '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err9;
+    /* If masquerading is enabled, set up the rules*/
+    if (network->def->forward) {
+        if (qemudAddMasqueradingIptablesRules(conn, driver, network))
+            return 1;
     }
-
-    /* enable masquerading */
-    if ((err = iptablesAddForwardMasquerade(driver->iptables,
-                                            network->def->network,
-                                            network->def->forwardDev))) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to enable masquerading : %s\n",
-                         strerror(err));
-        goto err10;
+    /* else if routing is enabled, set up the rules*/
+    else if (network->def->route) {
+        if (qemudAddRoutingIptablesRules(conn, driver, network))
+            return 1;
     }
+    else
+        return 1;
 
-    iptablesSaveRules(driver->iptables);
-
-    return 1;
-
- err10:
-    iptablesRemoveForwardAllowIn(driver->iptables,
-                                 network->def->network,
-                                 network->bridge,
-                                 network->def->forwardDev);
- err9:
-    iptablesRemoveForwardAllowOut(driver->iptables,
-                                  network->def->network,
-                                  network->bridge,
-                                  network->def->forwardDev);
  err8:
     iptablesRemoveForwardAllowCross(driver->iptables,
                                     network->bridge);
@@ -1208,7 +1260,7 @@
     if (!qemudAddIptablesRules(conn, driver, network))
         goto err_delbr1;
 
-    if (network->def->forward &&
+    if ((network->def->forward || network->def->route) &&
         !qemudEnableIpForwarding()) {
         qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                          "failed to enable IP forwarding : %s\n", strerror(err));
