]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
network: allow guest to guest IPv6 without gateway definition
authorGene Czarcinski <gene@czarc.net>
Mon, 3 Dec 2012 16:13:36 +0000 (11:13 -0500)
committerLaine Stump <laine@laine.org>
Wed, 5 Dec 2012 19:58:32 +0000 (14:58 -0500)
This patch adds the capability for virtual guests to do IPv6
communication via a virtual network interface with no IPv6 (gateway)
addresses specified.  This capability has always been enabled by
default for IPv4, but disabled for IPv6 for security concerns, and
because it requires the ip6tables command to be operational (which
isn't the case on a system with the ipv6 module completely disabled).

This patch adds a new attribute "ipv6" at the toplevel of a <network>
object.  If ipv6='yes', the extra ip6tables rules required to permite
inter-guest communications are added when the network is started. If
it is 'no', or not present, those rules will not be added; thus the
default behavior doesn't change, so there should be no compatibility
issues with any existing installations.

Note that virtual guests cannot communication with the virtualization
host via this interface, because the following kernel tunable has
been set:

   net.ipv6.conf.<bridge_interface_name>.disable_ipv6 = 1

This assures that the bridge interface will not have an IPv6
link-local (fe80::) address.

To control this behavior so that it is not enabled by default, the parameter
ipv6='yes' on the <network> statement has been added.

Documentation related to this patch has been updated.
The network schema has also been updated.

docs/formatnetwork.html.in
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
src/network/bridge_driver.c
tests/networkxml2xmlin/empty-allow-ipv6.xml [new file with mode: 0644]
tests/networkxml2xmlin/isolated-network.xml
tests/networkxml2xmlout/empty-allow-ipv6.xml [new file with mode: 0644]
tests/networkxml2xmltest.c

index 49206dda1907240d5db082e9385c79065189b855..a3a5ced3e11a7a0dcd2b7d943fb4b23911aff0f3 100644 (file)
@@ -33,7 +33,7 @@
     </p>
 
     <pre>
-      &lt;network&gt;
+      &lt;network ipv6='yes'&gt;
         &lt;name&gt;default&lt;/name&gt;
         &lt;uuid&gt;3e3fce45-4f53-4fa7-bb32-11f34168b82b&lt;/uuid&gt;
         ...</pre>
         The format must be RFC 4122 compliant, eg <code>3e3fce45-4f53-4fa7-bb32-11f34168b82b</code>.
         If omitted when defining/creating a new network, a random
         UUID is generated. <span class="since">Since 0.3.0</span></dd>
+      <dt><code>ipv6='yes'</code></dt>
+      <dd>The new, optional parameter <code>ipv6='yes'</code> enables
+        a network definition with no IPv6 gateway addresses specified
+        to have guest-to-guest communications.  For further information,
+        see the example below for the example with no gateway addresses.
+        <span class="since">Since 1.0.1</span></dd>
     </dl>
 
     <h3><a name="elementsConnect">Connectivity</a></h3>
         &lt;/forward&gt;
       &lt;/network&gt;</pre>
 
+    <h3><a name="examplesNoGateway">Network config with no gateway addresses</a></h3>
+
+    <p>
+    A valid network definition can contain no IPv4 or IPv6 addresses.  Such a definition
+    can be used for a "very private" or "very isolated" network since it will not be
+    possible to communicate with the virtualization host via this network.  However,
+    this virtual network interface can be used for communication between virtual guest
+    systems.  This works for IPv4 and <span class="since">(Since 1.0.1)</span> IPv6.
+    However, the new ipv6='yes' must be added for guest-to-guest IPv6
+    communication.
+    </p>
+
+    <pre>
+      &lt;network ipv6='yes'&gt;
+        &lt;name&gt;nogw&lt;/name&gt;
+        &lt;uuid&gt;7a3b7497-1ec7-8aef-6d5c-38dff9109e93&lt;/uuid&gt;
+        &lt;bridge name="virbr2" stp="on" delay="0" /&gt;
+        &lt;mac address='00:16:3E:5D:C7:9E'/&gt;
+      &lt;/network&gt;</pre>
+
   </body>
 </html>
index 4abfd915dd719842041fdc1d0b241bda7f4f3cca..0d67f7f902b6c76e4bbfaa6a7e9f96a837799b34 100644 (file)
           <data type="unsignedInt"/>
         </attribute>
       </optional>
+      <!-- Enables IPv6 guest-to-guest communications on a network
+           with no gateways addresses specified -->
+      <optional>
+        <attribute name="ipv6">
+         <choice>
+          <value>yes</value>
+          <value>no</value>
+          </choice>
+         </attribute>
+       </optional>
       <interleave>
 
         <!-- The name of the network, used to refer to it through the API
index 6ce2e638bbedb7cf3ecd22f5f34a6dfa8d6e99bc..8c77c50a8cc6ce2d219f42bddaaedf963fbf45af 100644 (file)
@@ -1226,6 +1226,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     xmlNodePtr virtPortNode = NULL;
     xmlNodePtr forwardNode = NULL;
     int nIps, nPortGroups, nForwardIfs, nForwardPfs, nForwardAddrs;
+    char *ipv6nogwStr = NULL;
     char *forwardDev = NULL;
     char *forwardManaged = NULL;
     char *type = NULL;
@@ -1264,6 +1265,22 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
         def->uuid_specified = true;
     }
 
+    /* check if definitions with no IPv6 gateway addresses is to
+     * allow guest-to-guest communications.
+     */
+    ipv6nogwStr = virXPathString("string(./@ipv6)", ctxt);
+    if (ipv6nogwStr) {
+        if (STREQ(ipv6nogwStr, "yes")) {
+            def->ipv6nogw = true;
+        } else if (STRNEQ(ipv6nogwStr, "no")) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid ipv6 setting '%s' in network '%s'"),
+                           ipv6nogwStr, def->name);
+            goto error;
+        }
+        VIR_FREE(ipv6nogwStr);
+    }
+
     /* Parse network domain information */
     def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
 
@@ -1591,6 +1608,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     VIR_FREE(portGroupNodes);
     VIR_FREE(forwardIfNodes);
     VIR_FREE(forwardPfNodes);
+    VIR_FREE(ipv6nogwStr);
     VIR_FREE(forwardDev);
     ctxt->node = save;
     return NULL;
@@ -1839,6 +1857,8 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags)
     if (!(flags & VIR_NETWORK_XML_INACTIVE) && (def->connections > 0)) {
         virBufferAsprintf(&buf, " connections='%d'", def->connections);
     }
+    if (def->ipv6nogw)
+        virBufferAddLit(&buf, " ipv6='yes'");
     virBufferAddLit(&buf, ">\n");
     virBufferAdjustIndent(&buf, 2);
     virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
index 3e463047f829176302a5322e39c5ab55a6d18199..949b3d280ae2559224c22f23d7f724713c5b7260 100644 (file)
@@ -184,6 +184,11 @@ struct _virNetworkDef {
     virMacAddr mac; /* mac address of bridge device */
     bool mac_specified;
 
+    /* specified if ip6tables rules added
+     * when no ipv6 gateway addresses specified.
+     */
+    bool ipv6nogw;
+
     int forwardType;    /* One of virNetworkForwardType constants */
     int managed;        /* managed attribute for hostdev mode */
 
index e8be00adb564bd8b3098dc13f40be23452eb7140..e8ea77f387f1577c6010ba0028e88e092a67e1db 100644 (file)
@@ -1593,14 +1593,22 @@ networkRemoveRoutingIptablesRules(struct network_driver *driver,
     }
 }
 
-/* Add all once/network rules required for IPv6 (if any IPv6 addresses are defined) */
+/* Add all once/network rules required for IPv6.
+
+ * If no IPv6 addresses are defined and <network ipv6='yes'> is
+ * specified, then allow IPv6 commuinications between guests connected
+ * to this network. If any IPv6 addresses are defined, then add all
+ * rules for regular operation (including inter-guest communication).
+ */
 static int
 networkAddGeneralIp6tablesRules(struct network_driver *driver,
                                virNetworkObjPtr network)
 {
 
-    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
+    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
+        !network->def->ipv6nogw) {
         return 0;
+    }
 
     /* Catch all rules to block forwarding to/from bridges */
 
@@ -1629,6 +1637,10 @@ networkAddGeneralIp6tablesRules(struct network_driver *driver,
         goto err3;
     }
 
+    /* if no IPv6 addresses are defined, we are done. */
+    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
+        return 0;
+
     /* allow DNS over IPv6 */
     if (iptablesAddTcpInput(driver->iptables, AF_INET6,
                             network->def->bridge, 53) < 0) {
@@ -1665,11 +1677,17 @@ static void
 networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
                                   virNetworkObjPtr network)
 {
-    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
+    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
+                !network->def->ipv6nogw)
         return;
+    if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
+        iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
+        iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
+    }
 
-    iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
-    iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53);
+    /* the following rules are there if no IPv6 address has been defined
+     * but network->def->ipv6nogw == true
+     */
     iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge);
     iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge);
     iptablesRemoveForwardRejectOut(driver->iptables, AF_INET6, network->def->bridge);
diff --git a/tests/networkxml2xmlin/empty-allow-ipv6.xml b/tests/networkxml2xmlin/empty-allow-ipv6.xml
new file mode 100644 (file)
index 0000000..9d1e4e4
--- /dev/null
@@ -0,0 +1,6 @@
+<network ipv6='yes'>
+  <name>empty</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+  <bridge name='virbr7' />
+  <mac address='52:54:00:17:3F:47'/>
+</network>
index 0d562ea2021bd7d6ca7dfb639dda75c883e15b84..5aa88c12742292d3ee9d38a094e9a69174a377f3 100644 (file)
@@ -1,4 +1,4 @@
-<network>
+<network ipv6='no'>
   <name>private</name>
   <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
   <bridge name="virbr2" />
diff --git a/tests/networkxml2xmlout/empty-allow-ipv6.xml b/tests/networkxml2xmlout/empty-allow-ipv6.xml
new file mode 100644 (file)
index 0000000..6ee55ad
--- /dev/null
@@ -0,0 +1,6 @@
+<network ipv6='yes'>
+  <name>empty</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9c</uuid>
+  <bridge name='virbr7' stp='on' delay='0' />
+  <mac address='52:54:00:17:3F:47'/>
+</network>
index e57d1903993e2b69d63014f773707f2129d5a496..1cd74d101817834a0d9970e8d5a96bbcfbfaa504 100644 (file)
@@ -92,6 +92,7 @@ mymain(void)
     } while (0)
 #define DO_TEST(name) DO_TEST_FULL(name, 0)
 
+    DO_TEST("empty-allow-ipv6");
     DO_TEST("isolated-network");
     DO_TEST("routed-network");
     DO_TEST("nat-network");