6ae9ed
From b238953664fffd85c3dc35554ba7ab62638aeb5e Mon Sep 17 00:00:00 2001
6ae9ed
Message-Id: <b238953664fffd85c3dc35554ba7ab62638aeb5e@dist-git>
6ae9ed
From: Laine Stump <laine@laine.org>
6ae9ed
Date: Sat, 27 Aug 2016 12:28:08 -0400
6ae9ed
Subject: [PATCH] network: new network forward mode 'open'
6ae9ed
6ae9ed
The new forward mode 'open' is just like mode='route', except that no
6ae9ed
firewall rules are added to assure that any traffic does or doesn't
6ae9ed
pass. It is assumed that either they aren't necessary, or they will be
6ae9ed
setup outside the scope of libvirt.
6ae9ed
6ae9ed
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=846810
6ae9ed
6ae9ed
(cherry picked from commit 25e8112d7c32ab271b9cae28f3ccbf5835206693)
6ae9ed
---
6ae9ed
 docs/formatnetwork.html.in                         | 22 ++++++++++++
6ae9ed
 docs/schemas/network.rng                           |  1 +
6ae9ed
 src/conf/network_conf.c                            | 25 +++++++++++--
6ae9ed
 src/conf/network_conf.h                            |  1 +
6ae9ed
 src/network/bridge_driver.c                        | 41 +++++++++++++++-------
6ae9ed
 tests/networkxml2confdata/open-network.conf        | 11 ++++++
6ae9ed
 tests/networkxml2confdata/open-network.xml         |  9 +++++
6ae9ed
 tests/networkxml2conftest.c                        |  1 +
6ae9ed
 .../open-network-with-forward-dev.xml              |  9 +++++
6ae9ed
 tests/networkxml2xmlin/open-network.xml            |  9 +++++
6ae9ed
 tests/networkxml2xmlout/open-network.xml           |  9 +++++
6ae9ed
 tests/networkxml2xmltest.c                         |  2 ++
6ae9ed
 12 files changed, 125 insertions(+), 15 deletions(-)
6ae9ed
 create mode 100644 tests/networkxml2confdata/open-network.conf
6ae9ed
 create mode 100644 tests/networkxml2confdata/open-network.xml
6ae9ed
 create mode 100644 tests/networkxml2xmlin/open-network-with-forward-dev.xml
6ae9ed
 create mode 100644 tests/networkxml2xmlin/open-network.xml
6ae9ed
 create mode 100644 tests/networkxml2xmlout/open-network.xml
6ae9ed
6ae9ed
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
6ae9ed
index 1cea931..619b10e 100644
6ae9ed
--- a/docs/formatnetwork.html.in
6ae9ed
+++ b/docs/formatnetwork.html.in
6ae9ed
@@ -250,6 +250,28 @@
6ae9ed
             Since 0.4.2
6ae9ed
           
6ae9ed
 
6ae9ed
+          
open
6ae9ed
+          
6ae9ed
+            As with mode='route', guest network traffic will be
6ae9ed
+            forwarded to the physical network via the host's IP
6ae9ed
+            routing stack, but there will be no firewall rules added
6ae9ed
+            to either enable or prevent any of this traffic. When
6ae9ed
+            forward='open' is set, the dev attribute
6ae9ed
+            cannot be set (because the forward dev is enforced with
6ae9ed
+            firewall rules, and the purpose of forward='open' is to
6ae9ed
+            have a forwarding mode where libvirt doesn't add any
6ae9ed
+            firewall rules).  This mode presumes that the local LAN
6ae9ed
+            router has suitable routing table entries to return
6ae9ed
+            traffic to this host, and that some other management
6ae9ed
+            system has been used to put in place any necessary
6ae9ed
+            firewall rules. Although no firewall rules will be added
6ae9ed
+            for the network, it is of course still possible to add
6ae9ed
+            restrictions for specific guests using
6ae9ed
+            nwfilter rules on the
6ae9ed
+            guests' interfaces.)
6ae9ed
+            Since 2.2.0
6ae9ed
+          
6ae9ed
+
6ae9ed
           
bridge
6ae9ed
           
6ae9ed
             This network describes either 1) an existing host bridge
6ae9ed
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
6ae9ed
index 4edb6eb..8a1be68 100644
6ae9ed
--- a/docs/schemas/network.rng
6ae9ed
+++ b/docs/schemas/network.rng
6ae9ed
@@ -101,6 +101,7 @@
6ae9ed
                 <choice>
6ae9ed
                   <value>nat</value>
6ae9ed
                   <value>route</value>
6ae9ed
+                  <value>open</value>
6ae9ed
                   <value>bridge</value>
6ae9ed
                   <value>passthrough</value>
6ae9ed
                   <value>private</value>
6ae9ed
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
6ae9ed
index 2d904df..1990cfc 100644
6ae9ed
--- a/src/conf/network_conf.c
6ae9ed
+++ b/src/conf/network_conf.c
6ae9ed
@@ -57,7 +57,9 @@ struct _virNetworkObjList {
6ae9ed
 
6ae9ed
 VIR_ENUM_IMPL(virNetworkForward,
6ae9ed
               VIR_NETWORK_FORWARD_LAST,
6ae9ed
-              "none", "nat", "route", "bridge", "private", "vepa", "passthrough", "hostdev")
6ae9ed
+              "none", "nat", "route", "open",
6ae9ed
+              "bridge", "private", "vepa", "passthrough",
6ae9ed
+              "hostdev")
6ae9ed
 
6ae9ed
 VIR_ENUM_IMPL(virNetworkBridgeMACTableManager,
6ae9ed
               VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST,
6ae9ed
@@ -2329,6 +2331,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
6ae9ed
 
6ae9ed
     case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
     case VIR_NETWORK_FORWARD_NAT:
6ae9ed
+    case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         /* It's pointless to specify L3 forwarding without specifying
6ae9ed
          * the network we're on.
6ae9ed
          */
6ae9ed
@@ -2347,6 +2350,19 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
6ae9ed
                            def->name);
6ae9ed
             goto error;
6ae9ed
         }
6ae9ed
+
6ae9ed
+        if (def->forward.type == VIR_NETWORK_FORWARD_OPEN && def->forward.nifs) {
6ae9ed
+            /* an open network by definition can't place any restrictions
6ae9ed
+             * on what traffic is allowed or where it goes, so specifying
6ae9ed
+             * a forwarding device is nonsensical.
6ae9ed
+             */
6ae9ed
+            virReportError(VIR_ERR_XML_ERROR,
6ae9ed
+                           _("forward dev not allowed for "
6ae9ed
+                             "network '%s' with forward mode='%s'"),
6ae9ed
+                           def->name,
6ae9ed
+                           virNetworkForwardTypeToString(def->forward.type));
6ae9ed
+            goto error;
6ae9ed
+        }
6ae9ed
         break;
6ae9ed
 
6ae9ed
     case VIR_NETWORK_FORWARD_PRIVATE:
6ae9ed
@@ -2820,13 +2836,15 @@ virNetworkDefFormatBuf(virBufferPtr buf,
6ae9ed
     if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
6ae9ed
         def->forward.type == VIR_NETWORK_FORWARD_NAT ||
6ae9ed
         def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
6ae9ed
+        def->forward.type == VIR_NETWORK_FORWARD_OPEN ||
6ae9ed
         def->bridge || def->macTableManager) {
6ae9ed
 
6ae9ed
         virBufferAddLit(buf, "
6ae9ed
         virBufferEscapeString(buf, " name='%s'", def->bridge);
6ae9ed
         if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
6ae9ed
             def->forward.type == VIR_NETWORK_FORWARD_NAT ||
6ae9ed
-            def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
6ae9ed
+            def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
6ae9ed
+            def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
6ae9ed
             virBufferAsprintf(buf, " stp='%s' delay='%ld'",
6ae9ed
                               def->stp ? "on" : "off", def->delay);
6ae9ed
         }
6ae9ed
@@ -3199,7 +3217,8 @@ virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
6ae9ed
 
6ae9ed
     if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
6ae9ed
         def->forward.type == VIR_NETWORK_FORWARD_NAT ||
6ae9ed
-        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
6ae9ed
+        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
6ae9ed
+        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
6ae9ed
 
6ae9ed
         if (!def->mac_specified) {
6ae9ed
             virNetworkSetBridgeMacAddr(def);
6ae9ed
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
6ae9ed
index e7ce674..bba99e2 100644
6ae9ed
--- a/src/conf/network_conf.h
6ae9ed
+++ b/src/conf/network_conf.h
6ae9ed
@@ -46,6 +46,7 @@ typedef enum {
6ae9ed
     VIR_NETWORK_FORWARD_NONE   = 0,
6ae9ed
     VIR_NETWORK_FORWARD_NAT,
6ae9ed
     VIR_NETWORK_FORWARD_ROUTE,
6ae9ed
+    VIR_NETWORK_FORWARD_OPEN,
6ae9ed
     VIR_NETWORK_FORWARD_BRIDGE,
6ae9ed
     VIR_NETWORK_FORWARD_PRIVATE,
6ae9ed
     VIR_NETWORK_FORWARD_VEPA,
6ae9ed
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
6ae9ed
index 0221a38..c6ab6a1 100644
6ae9ed
--- a/src/network/bridge_driver.c
6ae9ed
+++ b/src/network/bridge_driver.c
6ae9ed
@@ -400,6 +400,7 @@ networkUpdateState(virNetworkObjPtr obj,
6ae9ed
     case VIR_NETWORK_FORWARD_NONE:
6ae9ed
     case VIR_NETWORK_FORWARD_NAT:
6ae9ed
     case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
+    case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         /* If bridge doesn't exist, then mark it inactive */
6ae9ed
         if (!(obj->def->bridge && virNetDevExists(obj->def->bridge) == 1))
6ae9ed
             obj->active = 0;
6ae9ed
@@ -1815,7 +1816,8 @@ networkRefreshDaemonsHelper(virNetworkObjPtr net,
6ae9ed
     if (virNetworkObjIsActive(net) &&
6ae9ed
         ((net->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
6ae9ed
          (net->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
6ae9ed
-         (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
6ae9ed
+         (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
6ae9ed
+         (net->def->forward.type == VIR_NETWORK_FORWARD_OPEN))) {
6ae9ed
         /* Only the three L3 network types that are configured by
6ae9ed
          * libvirt will have a dnsmasq or radvd daemon associated
6ae9ed
          * with them.  Here we send a SIGHUP to an existing
6ae9ed
@@ -1851,8 +1853,10 @@ networkReloadFirewallRulesHelper(virNetworkObjPtr net,
6ae9ed
         ((net->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
6ae9ed
          (net->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
6ae9ed
          (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
6ae9ed
-        /* Only the three L3 network types that are configured by libvirt
6ae9ed
-         * need to have iptables rules reloaded.
6ae9ed
+        /* Only three of the L3 network types that are configured by
6ae9ed
+         * libvirt need to have iptables rules reloaded. The 4th L3
6ae9ed
+         * network type, forward='open', doesn't need this because it
6ae9ed
+         * has no iptables rules.
6ae9ed
          */
6ae9ed
         networkRemoveFirewallRules(net->def);
6ae9ed
         if (networkAddFirewallRules(net->def) < 0) {
6ae9ed
@@ -2135,7 +2139,8 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
6ae9ed
         goto err1;
6ae9ed
 
6ae9ed
     /* Add "once per network" rules */
6ae9ed
-    if (networkAddFirewallRules(network->def) < 0)
6ae9ed
+    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
6ae9ed
+        networkAddFirewallRules(network->def) < 0)
6ae9ed
         goto err1;
6ae9ed
 
6ae9ed
     for (i = 0;
6ae9ed
@@ -2237,7 +2242,8 @@ networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
6ae9ed
  err2:
6ae9ed
     if (!save_err)
6ae9ed
         save_err = virSaveLastError();
6ae9ed
-    networkRemoveFirewallRules(network->def);
6ae9ed
+    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
6ae9ed
+        networkRemoveFirewallRules(network->def);
6ae9ed
 
6ae9ed
  err1:
6ae9ed
     if (!save_err)
6ae9ed
@@ -2293,7 +2299,8 @@ networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
6ae9ed
 
6ae9ed
     ignore_value(virNetDevSetOnline(network->def->bridge, 0));
6ae9ed
 
6ae9ed
-    networkRemoveFirewallRules(network->def);
6ae9ed
+    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
6ae9ed
+        networkRemoveFirewallRules(network->def);
6ae9ed
 
6ae9ed
     ignore_value(virNetDevBridgeDelete(network->def->bridge));
6ae9ed
 
6ae9ed
@@ -2400,6 +2407,7 @@ networkCreateInterfacePool(virNetworkDefPtr netdef)
6ae9ed
         case VIR_NETWORK_FORWARD_NONE:
6ae9ed
         case VIR_NETWORK_FORWARD_NAT:
6ae9ed
         case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
+        case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         case VIR_NETWORK_FORWARD_LAST:
6ae9ed
             /* by definition these will never be encountered here */
6ae9ed
             break;
6ae9ed
@@ -2493,6 +2501,7 @@ networkStartNetwork(virNetworkDriverStatePtr driver,
6ae9ed
     case VIR_NETWORK_FORWARD_NONE:
6ae9ed
     case VIR_NETWORK_FORWARD_NAT:
6ae9ed
     case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
+    case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         if (networkStartNetworkVirtual(driver, network) < 0)
6ae9ed
             goto cleanup;
6ae9ed
         break;
6ae9ed
@@ -2571,6 +2580,7 @@ networkShutdownNetwork(virNetworkDriverStatePtr driver,
6ae9ed
     case VIR_NETWORK_FORWARD_NONE:
6ae9ed
     case VIR_NETWORK_FORWARD_NAT:
6ae9ed
     case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
+    case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         ret = networkShutdownNetworkVirtual(driver, network);
6ae9ed
         break;
6ae9ed
 
6ae9ed
@@ -2919,7 +2929,8 @@ networkValidate(virNetworkDriverStatePtr driver,
6ae9ed
      */
6ae9ed
     if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
6ae9ed
         def->forward.type == VIR_NETWORK_FORWARD_NAT ||
6ae9ed
-        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
6ae9ed
+        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
6ae9ed
+        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
6ae9ed
 
6ae9ed
         /* if no bridge name was given in the config, find a name
6ae9ed
          * unused by any other libvirt networks and assign it.
6ae9ed
@@ -3360,8 +3371,10 @@ networkUpdate(virNetworkPtr net,
6ae9ed
                  * old rules (and remember to load new ones after the
6ae9ed
                  * update).
6ae9ed
                  */
6ae9ed
-                networkRemoveFirewallRules(network->def);
6ae9ed
-                needFirewallRefresh = true;
6ae9ed
+                if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN) {
6ae9ed
+                    networkRemoveFirewallRules(network->def);
6ae9ed
+                    needFirewallRefresh = true;
6ae9ed
+                }
6ae9ed
                 break;
6ae9ed
             default:
6ae9ed
                 break;
6ae9ed
@@ -4037,7 +4050,8 @@ networkAllocateActualDevice(virDomainDefPtr dom,
6ae9ed
 
6ae9ed
     if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
6ae9ed
         (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
6ae9ed
-        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
6ae9ed
+        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
6ae9ed
+        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
6ae9ed
         /* for these forward types, the actual net type really *is*
6ae9ed
          * NETWORK; we just keep the info from the portgroup in
6ae9ed
          * iface->data.network.actual
6ae9ed
@@ -4581,7 +4595,8 @@ networkReleaseActualDevice(virDomainDefPtr dom,
6ae9ed
     if (iface->data.network.actual &&
6ae9ed
         (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
6ae9ed
          netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
6ae9ed
-         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) &&
6ae9ed
+         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
6ae9ed
+         netdef->forward.type == VIR_NETWORK_FORWARD_OPEN) &&
6ae9ed
         networkUnplugBandwidth(network, iface) < 0)
6ae9ed
         goto error;
6ae9ed
 
6ae9ed
@@ -4728,6 +4743,7 @@ networkGetNetworkAddress(const char *netname, char **netaddr)
6ae9ed
     case VIR_NETWORK_FORWARD_NONE:
6ae9ed
     case VIR_NETWORK_FORWARD_NAT:
6ae9ed
     case VIR_NETWORK_FORWARD_ROUTE:
6ae9ed
+    case VIR_NETWORK_FORWARD_OPEN:
6ae9ed
         ipdef = virNetworkDefGetIPByIndex(netdef, AF_UNSPEC, 0);
6ae9ed
         if (!ipdef) {
6ae9ed
             virReportError(VIR_ERR_INTERNAL_ERROR,
6ae9ed
@@ -4811,7 +4827,8 @@ networkGetActualType(virDomainNetDefPtr iface)
6ae9ed
 
6ae9ed
     if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
6ae9ed
         (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
6ae9ed
-        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
6ae9ed
+        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
6ae9ed
+        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
6ae9ed
         /* for these forward types, the actual net type really *is*
6ae9ed
          * NETWORK; we just keep the info from the portgroup in
6ae9ed
          * iface->data.network.actual
6ae9ed
diff --git a/tests/networkxml2confdata/open-network.conf b/tests/networkxml2confdata/open-network.conf
6ae9ed
new file mode 100644
6ae9ed
index 0000000..ff09984
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/networkxml2confdata/open-network.conf
6ae9ed
@@ -0,0 +1,11 @@
6ae9ed
+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
6ae9ed
+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
6ae9ed
+##    virsh net-edit open
6ae9ed
+## or other application using the libvirt API.
6ae9ed
+##
6ae9ed
+## dnsmasq conf file created by libvirt
6ae9ed
+strict-order
6ae9ed
+except-interface=lo
6ae9ed
+bind-dynamic
6ae9ed
+interface=virbr1
6ae9ed
+addn-hosts=/var/lib/libvirt/dnsmasq/open.addnhosts
6ae9ed
diff --git a/tests/networkxml2confdata/open-network.xml b/tests/networkxml2confdata/open-network.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..e0b3f03
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/networkxml2confdata/open-network.xml
6ae9ed
@@ -0,0 +1,9 @@
6ae9ed
+<network>
6ae9ed
+  <name>open</name>
6ae9ed
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
6ae9ed
+  <forward mode='open'/>
6ae9ed
+  <bridge name='virbr1' stp='on' delay='0'/>
6ae9ed
+  <mac address='12:34:56:78:9A:BC'/>
6ae9ed
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
6ae9ed
+  </ip>
6ae9ed
+</network>
6ae9ed
diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
6ae9ed
index 11e08c0..77acc53 100644
6ae9ed
--- a/tests/networkxml2conftest.c
6ae9ed
+++ b/tests/networkxml2conftest.c
6ae9ed
@@ -117,6 +117,7 @@ mymain(void)
6ae9ed
     DO_TEST("nat-network-dns-srv-record-minimal", restricted);
6ae9ed
     DO_TEST("nat-network-name-with-quotes", restricted);
6ae9ed
     DO_TEST("routed-network", full);
6ae9ed
+    DO_TEST("open-network", full);
6ae9ed
     DO_TEST("nat-network", dhcpv6);
6ae9ed
     DO_TEST("nat-network-dns-txt-record", full);
6ae9ed
     DO_TEST("nat-network-dns-srv-record", full);
6ae9ed
diff --git a/tests/networkxml2xmlin/open-network-with-forward-dev.xml b/tests/networkxml2xmlin/open-network-with-forward-dev.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..33e8bb5
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/networkxml2xmlin/open-network-with-forward-dev.xml
6ae9ed
@@ -0,0 +1,9 @@
6ae9ed
+<network>
6ae9ed
+  <name>open</name>
6ae9ed
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
6ae9ed
+  <bridge name="virbr1"/>
6ae9ed
+  <mac address='12:34:56:78:9A:BC'/>
6ae9ed
+  <forward mode="open" dev="eth0"/>
6ae9ed
+  <ip address="192.168.122.1" netmask="255.255.255.0">
6ae9ed
+  </ip>
6ae9ed
+</network>
6ae9ed
diff --git a/tests/networkxml2xmlin/open-network.xml b/tests/networkxml2xmlin/open-network.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..2e4b9b2
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/networkxml2xmlin/open-network.xml
6ae9ed
@@ -0,0 +1,9 @@
6ae9ed
+<network>
6ae9ed
+  <name>open</name>
6ae9ed
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
6ae9ed
+  <bridge name="virbr1"/>
6ae9ed
+  <mac address='12:34:56:78:9A:BC'/>
6ae9ed
+  <forward mode="open"/>
6ae9ed
+  <ip address="192.168.122.1" netmask="255.255.255.0">
6ae9ed
+  </ip>
6ae9ed
+</network>
6ae9ed
diff --git a/tests/networkxml2xmlout/open-network.xml b/tests/networkxml2xmlout/open-network.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..29e9684
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/networkxml2xmlout/open-network.xml
6ae9ed
@@ -0,0 +1,9 @@
6ae9ed
+<network>
6ae9ed
+  <name>open</name>
6ae9ed
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
6ae9ed
+  <forward mode='open'/>
6ae9ed
+  <bridge name='virbr1' stp='on' delay='0'/>
6ae9ed
+  <mac address='12:34:56:78:9a:bc'/>
6ae9ed
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
6ae9ed
+  </ip>
6ae9ed
+</network>
6ae9ed
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
6ae9ed
index d65f6aa..9114c1e 100644
6ae9ed
--- a/tests/networkxml2xmltest.c
6ae9ed
+++ b/tests/networkxml2xmltest.c
6ae9ed
@@ -127,6 +127,8 @@ mymain(void)
6ae9ed
     DO_TEST("empty-allow-ipv6");
6ae9ed
     DO_TEST("isolated-network");
6ae9ed
     DO_TEST("routed-network");
6ae9ed
+    DO_TEST("open-network");
6ae9ed
+    DO_TEST_PARSE_ERROR("open-network-with-forward-dev");
6ae9ed
     DO_TEST("nat-network");
6ae9ed
     DO_TEST("netboot-network");
6ae9ed
     DO_TEST("netboot-proxy-network");
6ae9ed
-- 
6ae9ed
2.10.0
6ae9ed