[Libvir] Patch for routed virtual networks

Mads Chr. Olesen shiyee at shiyee.dk
Mon Mar 10 21:08:56 UTC 2008


søn, 09 03 2008 kl. 21:09 +0000, skrev Daniel P. Berrange:
> On Sat, Mar 08, 2008 at 04:33:32PM +0100, Mads Chr. Olesen wrote:
> > I have added a <route dev="ethX" /> stanza (dev is optional), completely
> > equivalent to the <forward /> stanza.
> 
> This is still forwarding of traffic, so I think we should just use the
> existing  <forward/> element and have an extra attribute to indiciate
> the type of forwarding, eg
> 
>    <forward/>                      (defaults to mode="nat" for compat)
>    <forward mode="nat"/>
>    <forward mode="route"/>
>    <forward mode="nat" dev="ethX"/>
>    <forward mode="route" dev="ethX"/>

Sure, makes sense - an updated patch is attached.

> I'm a little unclear on how this actually works. You add iptables rules to
> allow traffic in/out, but you're not adding any routing table entries, nor
> turning on proxy_arp, so I don't see how this will actually work in practice.
> 
> Are you assuming the admin has already added suitable routing rules & turned
> on proxy arp ?

Well, in my case (dedicated server, hetzner.de) this is all that is
needed. My physical interface has IP 85.10.XXX.XXX, and then I have a
secondary IP range which gets routed at that interface, IP range
78.47.YYY.YYY/30. I then setup my virtual interface with an IP in that
range, by setting 
<ip address="78.47.YYY.YYY" netmask="255.255.255.248" />

Thus, to get packets routed at the virtual machines, it just needs to be
allowed by iptables, and /proc/sys/net/ipv4/ip_forward needs to be set
to 1.

Other setups obviously might need more work.

-- 
Mads Chr. Olesen <shiyee at shiyee.dk>
shiyee.dk
-------------- next part --------------
? routed-virtual-net.cvs.patch
? routed-virtual-net.cvs.patch2
? docs/.network.rng.swp
? src/.iptables.c.swp
? src/.iptables.h.swp
? src/.qemu_conf.c.swp
? src/.qemu_conf.h.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	10 Mar 2008 20:51:19 -0000
@@ -56,6 +56,14 @@
          rest of the network -->
     <element name="forward">
       <optional><attribute name="dev"><text/></attribute></optional>
+      <optional>
+        <attribute name="mode">
+          <choice>
+            <value>nat</value>
+            <value>routed</value>
+          </choice>
+        </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	10 Mar 2008 20:51:22 -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/iptables.h
===================================================================
RCS file: /data/cvs/libvirt/src/iptables.h,v
retrieving revision 1.3
diff -u -r1.3 iptables.h
--- src/iptables.h	10 Jan 2008 14:01:00 -0000	1.3
+++ src/iptables.h	10 Mar 2008 20:51:23 -0000
@@ -55,6 +55,15 @@
                                                   const char *iface,
                                                   const char *physdev);
 
+int              iptablesAddForwardAllowRelatedIn(iptablesContext *ctx,
+                                                  const char *network,
+                                                  const char *iface,
+                                                  const char *physdev);
+int              iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx,
+                                                  const char *network,
+                                                  const char *iface,
+                                                  const char *physdev);
+
 int              iptablesAddForwardAllowIn       (iptablesContext *ctx,
                                                   const char *network,
                                                   const char *iface,
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	10 Mar 2008 20:51:31 -0000
@@ -2451,6 +2451,17 @@
         }
 
         def->forward = 1;
+
+        tmp = xmlXPathEval(BAD_CAST "string(/network/forward[1]/@mode)", ctxt);
+        if ((tmp != NULL) && (tmp->type == XPATH_STRING) &&
+            (tmp->stringval != NULL) && (xmlStrEqual(tmp->stringval, BAD_CAST "route"))) {
+            def->forwardMode = QEMUD_NET_FORWARD_ROUTE;
+        } else {
+            def->forwardMode = QEMUD_NET_FORWARD_NAT;
+        }
+        xmlXPathFreeObject(tmp);
+        tmp = NULL;
+
         tmp = xmlXPathEval(BAD_CAST "string(/network/forward[1]/@dev)", ctxt);
         if ((tmp != NULL) && (tmp->type == XPATH_STRING) &&
             (tmp->stringval != NULL) && (tmp->stringval[0] != 0)) {
@@ -3085,10 +3096,10 @@
 
     if (def->forward) {
         if (def->forwardDev[0]) {
-            virBufferVSprintf(buf, "  <forward dev='%s'/>\n",
-                              def->forwardDev);
+            virBufferVSprintf(buf, "  <forward dev='%s' mode='%s'/>\n",
+                              def->forwardDev, (def->forwardMode == QEMUD_NET_FORWARD_ROUTE ? "route" : "nat"));
         } else {
-            virBufferAddLit(buf, "  <forward/>\n");
+            virBufferVSprintf(buf, "  <forward mode='%s'/>\n", (def->forwardMode == QEMUD_NET_FORWARD_ROUTE ? "route" : "nat"));
         }
     }
 
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	10 Mar 2008 20:51:32 -0000
@@ -83,6 +83,12 @@
     QEMUD_NET_BRIDGE,
 };
 
+/* 2 possible types of forwarding */
+enum qemud_vm_net_forward_type {
+    QEMUD_NET_FORWARD_NAT,
+    QEMUD_NET_FORWARD_ROUTE,
+};
+
 #define QEMUD_MAX_NAME_LEN 50
 #define QEMUD_MAX_XML_LEN 4096
 #define QEMUD_MAX_ERROR_LEN 1024
@@ -266,6 +272,7 @@
     int forwardDelay;
 
     int forward;
+    int forwardMode; /* From qemud_vm_net_forward_type */
     char forwardDev[BR_IFNAME_MAXLEN];
 
     char ipAddress[BR_INET_ADDR_MAXLEN];
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	10 Mar 2008 20:51:40 -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->forwardDev))) {
+        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->forwardDev))) {
+        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) {
@@ -1021,52 +1113,17 @@
         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;
-    }
-
-    /* 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;
+    /* If masquerading is enabled, set up the rules*/
+    if (network->def->forwardMode == QEMUD_NET_FORWARD_NAT) {
+        if (qemudAddMasqueradingIptablesRules(conn, driver, network))
+            return 1;
+    }
+    /* else if routing is enabled, set up the rules*/
+    else if (network->def->forwardMode == QEMUD_NET_FORWARD_ROUTE) {
+        if (qemudAddRoutingIptablesRules(conn, driver, network))
+            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);


More information about the libvir-list mailing list