[libvirt] [PATCH v2] bridge driver: extract platform specifics

Roman Bogorodskiy bogorodskiy at gmail.com
Wed Jul 24 12:22:54 UTC 2013


* Move platform specific things (e.g. firewalling and route
  collision checks) into bridge_driver_platform
* Create two platform specific implementations:
    - bridge_driver_linux: Linux implementation using iptables,
      it's actually the code moved from bridge_driver.c
    - bridge_driver_nop: dumb implementation that does nothing
---
 src/network/bridge_driver_platform.h |   79 ++++
 src/network/bridge_driver.c          |  708 +--------------------------------
 src/network/bridge_driver_linux.c    |  709 ++++++++++++++++++++++++++++++++++
 src/network/bridge_driver_nop.c      |   78 ++++
 src/network/bridge_driver_platform.c |   32 ++
 po/POTFILES.in                       |    1 +
 src/Makefile.am                      |    5 +-
 7 files changed, 903 insertions(+), 709 deletions(-)
 create mode 100644 src/network/bridge_driver_platform.h
 create mode 100644 src/network/bridge_driver_linux.c
 create mode 100644 src/network/bridge_driver_nop.c
 create mode 100644 src/network/bridge_driver_platform.c

diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h
new file mode 100644
index 0000000..289ab79
--- /dev/null
+++ b/src/network/bridge_driver_platform.h
@@ -0,0 +1,79 @@
+/*
+ * bridge_driver.h: platform specific routines for bridge driver
+ *
+ * Copyright (C) 2006-2013 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_BRIDGE_DRIVER_PLATFORM_H__
+# define __VIR_BRIDGE_DRIVER_PLATFORM_H__
+
+# include "internal.h"
+# include "virlog.h"
+# include "virthread.h"
+# include "virdnsmasq.h"
+# include "network_conf.h"
+
+/* Main driver state */
+struct _virNetworkDriverState {
+    virMutex lock;
+
+    virNetworkObjList networks;
+
+    char *networkConfigDir;
+    char *networkAutostartDir;
+    char *stateDir;
+    char *pidDir;
+    char *dnsmasqStateDir;
+    char *radvdStateDir;
+    dnsmasqCapsPtr dnsmasqCaps;
+};
+
+typedef struct _virNetworkDriverState virNetworkDriverState;
+typedef virNetworkDriverState *virNetworkDriverStatePtr;
+
+int networkCheckRouteCollision(virNetworkObjPtr network);
+
+int networkAddMasqueradingFirewallRules(virNetworkObjPtr network,
+                                        virNetworkIpDefPtr ipdef);
+
+void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network,
+                                            virNetworkIpDefPtr ipdef);
+
+int networkAddRoutingFirewallRules(virNetworkObjPtr network,
+                                   virNetworkIpDefPtr ipdef);
+
+void networkRemoveRoutingFirewallRules(virNetworkObjPtr network,
+                                       virNetworkIpDefPtr ipdef);
+
+int networkAddGeneralFirewallRules(virNetworkObjPtr network);
+
+void networkRemoveGeneralFirewallRules(virNetworkObjPtr network);
+
+int networkAddIpSpecificFirewallRules(virNetworkObjPtr network,
+                                      virNetworkIpDefPtr ipdef);
+
+void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network,
+                                          virNetworkIpDefPtr ipdef);
+
+int networkAddFirewallRules(virNetworkObjPtr network);
+
+void networkRemoveFirewallRules(virNetworkObjPtr network);
+
+#endif /* __VIR_BRIDGE_DRIVER_PLATFORM_H__ */
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 0bb57ea..a1b0dd5 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -45,6 +45,7 @@
 #include "virerror.h"
 #include "datatypes.h"
 #include "bridge_driver.h"
+#include "bridge_driver_platform.h"
 #include "network_conf.h"
 #include "device_conf.h"
 #include "driver.h"
@@ -69,24 +70,6 @@
 
 #define VIR_FROM_THIS VIR_FROM_NETWORK
 
-/* Main driver state */
-struct _virNetworkDriverState {
-    virMutex lock;
-
-    virNetworkObjList networks;
-
-    char *networkConfigDir;
-    char *networkAutostartDir;
-    char *stateDir;
-    char *pidDir;
-    char *dnsmasqStateDir;
-    char *radvdStateDir;
-    dnsmasqCapsPtr dnsmasqCaps;
-};
-
-typedef struct _virNetworkDriverState virNetworkDriverState;
-typedef virNetworkDriverState *virNetworkDriverStatePtr;
-
 static void networkDriverLock(virNetworkDriverStatePtr driver)
 {
     virMutexLock(&driver->lock);
@@ -1507,597 +1490,6 @@ networkRefreshDaemons(virNetworkDriverStatePtr driver)
     }
 }
 
-static int
-networkAddMasqueradingFirewallRules(virNetworkObjPtr network,
-                                    virNetworkIpDefPtr ipdef)
-{
-    int prefix = virNetworkIpDefPrefix(ipdef);
-    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
-
-    if (prefix < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Invalid prefix or netmask for '%s'"),
-                       network->def->bridge);
-        goto masqerr1;
-    }
-
-    /* allow forwarding packets from the bridge interface */
-    if (iptablesAddForwardAllowOut(&ipdef->address,
-                                   prefix,
-                                   network->def->bridge,
-                                   forwardIf) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow forwarding from '%s'"),
-                       network->def->bridge);
-        goto masqerr1;
-    }
-
-    /* allow forwarding packets to the bridge interface if they are
-     * part of an existing connection
-     */
-    if (iptablesAddForwardAllowRelatedIn(&ipdef->address,
-                                         prefix,
-                                         network->def->bridge,
-                                         forwardIf) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow forwarding to '%s'"),
-                       network->def->bridge);
-        goto masqerr2;
-    }
-
-    /*
-     * Enable masquerading.
-     *
-     * We need to end up with 3 rules in the table in this order
-     *
-     *  1. protocol=tcp with sport mapping restriction
-     *  2. protocol=udp with sport mapping restriction
-     *  3. generic any protocol
-     *
-     * The sport mappings are required, because default IPtables
-     * MASQUERADE maintain port numbers unchanged where possible.
-     *
-     * NFS can be configured to only "trust" port numbers < 1023.
-     *
-     * Guests using NAT thus need to be prevented from having port
-     * numbers < 1023, otherwise they can bypass the NFS "security"
-     * check on the source port number.
-     *
-     * Since we use '--insert' to add rules to the header of the
-     * chain, we actually need to add them in the reverse of the
-     * order just mentioned !
-     */
-
-    /* First the generic masquerade rule for other protocols */
-    if (iptablesAddForwardMasquerade(&ipdef->address,
-                                     prefix,
-                                     forwardIf,
-                                     &network->def->forward.addr,
-                                     &network->def->forward.port,
-                                     NULL) < 0) {
-        if (forwardIf)
-            virReportError(VIR_ERR_SYSTEM_ERROR,
-                           _("failed to add iptables rule to enable masquerading to %s"),
-                           forwardIf);
-        else
-            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
-                           _("failed to add iptables rule to enable masquerading"));
-        goto masqerr3;
-    }
-
-    /* UDP with a source port restriction */
-    if (iptablesAddForwardMasquerade(&ipdef->address,
-                                     prefix,
-                                     forwardIf,
-                                     &network->def->forward.addr,
-                                     &network->def->forward.port,
-                                     "udp") < 0) {
-        if (forwardIf)
-            virReportError(VIR_ERR_SYSTEM_ERROR,
-                           _("failed to add iptables rule to enable UDP masquerading to %s"),
-                           forwardIf);
-        else
-            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
-                           _("failed to add iptables rule to enable UDP masquerading"));
-        goto masqerr4;
-    }
-
-    /* TCP with a source port restriction */
-    if (iptablesAddForwardMasquerade(&ipdef->address,
-                                     prefix,
-                                     forwardIf,
-                                     &network->def->forward.addr,
-                                     &network->def->forward.port,
-                                     "tcp") < 0) {
-        if (forwardIf)
-            virReportError(VIR_ERR_SYSTEM_ERROR,
-                           _("failed to add iptables rule to enable TCP masquerading to %s"),
-                           forwardIf);
-        else
-            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
-                           _("failed to add iptables rule to enable TCP masquerading"));
-        goto masqerr5;
-    }
-
-    return 0;
-
- masqerr5:
-    iptablesRemoveForwardMasquerade(&ipdef->address,
-                                    prefix,
-                                    forwardIf,
-                                    &network->def->forward.addr,
-                                    &network->def->forward.port,
-                                    "udp");
- masqerr4:
-    iptablesRemoveForwardMasquerade(&ipdef->address,
-                                    prefix,
-                                    forwardIf,
-                                    &network->def->forward.addr,
-                                    &network->def->forward.port,
-                                    NULL);
- masqerr3:
-    iptablesRemoveForwardAllowRelatedIn(&ipdef->address,
-                                        prefix,
-                                        network->def->bridge,
-                                        forwardIf);
- masqerr2:
-    iptablesRemoveForwardAllowOut(&ipdef->address,
-                                  prefix,
-                                  network->def->bridge,
-                                  forwardIf);
- masqerr1:
-    return -1;
-}
-
-static void
-networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network,
-                                       virNetworkIpDefPtr ipdef)
-{
-    int prefix = virNetworkIpDefPrefix(ipdef);
-    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
-
-    if (prefix >= 0) {
-        iptablesRemoveForwardMasquerade(&ipdef->address,
-                                        prefix,
-                                        forwardIf,
-                                        &network->def->forward.addr,
-                                        &network->def->forward.port,
-                                        "tcp");
-        iptablesRemoveForwardMasquerade(&ipdef->address,
-                                        prefix,
-                                        forwardIf,
-                                        &network->def->forward.addr,
-                                        &network->def->forward.port,
-                                        "udp");
-        iptablesRemoveForwardMasquerade(&ipdef->address,
-                                        prefix,
-                                        forwardIf,
-                                        &network->def->forward.addr,
-                                        &network->def->forward.port,
-                                        NULL);
-
-        iptablesRemoveForwardAllowRelatedIn(&ipdef->address,
-                                            prefix,
-                                            network->def->bridge,
-                                            forwardIf);
-        iptablesRemoveForwardAllowOut(&ipdef->address,
-                                      prefix,
-                                      network->def->bridge,
-                                      forwardIf);
-    }
-}
-
-static int
-networkAddRoutingFirewallRules(virNetworkObjPtr network,
-                               virNetworkIpDefPtr ipdef)
-{
-    int prefix = virNetworkIpDefPrefix(ipdef);
-    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
-
-    if (prefix < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Invalid prefix or netmask for '%s'"),
-                       network->def->bridge);
-        goto routeerr1;
-    }
-
-    /* allow routing packets from the bridge interface */
-    if (iptablesAddForwardAllowOut(&ipdef->address,
-                                   prefix,
-                                   network->def->bridge,
-                                   forwardIf) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow routing from '%s'"),
-                       network->def->bridge);
-        goto routeerr1;
-    }
-
-    /* allow routing packets to the bridge interface */
-    if (iptablesAddForwardAllowIn(&ipdef->address,
-                                  prefix,
-                                  network->def->bridge,
-                                  forwardIf) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow routing to '%s'"),
-                       network->def->bridge);
-        goto routeerr2;
-    }
-
-    return 0;
-
-routeerr2:
-    iptablesRemoveForwardAllowOut(&ipdef->address,
-                                  prefix,
-                                  network->def->bridge,
-                                  forwardIf);
-routeerr1:
-    return -1;
-}
-
-static void
-networkRemoveRoutingFirewallRules(virNetworkObjPtr network,
-                                  virNetworkIpDefPtr ipdef)
-{
-    int prefix = virNetworkIpDefPrefix(ipdef);
-    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
-
-    if (prefix >= 0) {
-        iptablesRemoveForwardAllowIn(&ipdef->address,
-                                     prefix,
-                                     network->def->bridge,
-                                     forwardIf);
-
-        iptablesRemoveForwardAllowOut(&ipdef->address,
-                                      prefix,
-                                      network->def->bridge,
-                                      forwardIf);
-    }
-}
-
-/* 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 virtual systems.
- * If any IPv6 addresses are defined, then add the rules for regular operation.
- */
-static int
-networkAddGeneralIp6tablesRules(virNetworkObjPtr network)
-{
-
-    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
-        !network->def->ipv6nogw) {
-        return 0;
-    }
-
-    /* Catch all rules to block forwarding to/from bridges */
-
-    if (iptablesAddForwardRejectOut(AF_INET6, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to block outbound traffic from '%s'"),
-                       network->def->bridge);
-        goto err1;
-    }
-
-    if (iptablesAddForwardRejectIn(AF_INET6, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to block inbound traffic to '%s'"),
-                       network->def->bridge);
-        goto err2;
-    }
-
-    /* Allow traffic between guests on the same bridge */
-    if (iptablesAddForwardAllowCross(AF_INET6, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to allow cross bridge traffic on '%s'"),
-                       network->def->bridge);
-        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(AF_INET6, network->def->bridge, 53) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to allow DNS requests from '%s'"),
-                       network->def->bridge);
-        goto err4;
-    }
-
-    if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 53) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to allow DNS requests from '%s'"),
-                       network->def->bridge);
-        goto err5;
-    }
-
-    if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 547) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add ip6tables rule to allow DHCP6 requests from '%s'"),
-                       network->def->bridge);
-        goto err6;
-    }
-
-    return 0;
-
-    /* unwind in reverse order from the point of failure */
-err6:
-    iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53);
-err5:
-    iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53);
-err4:
-    iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge);
-err3:
-    iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge);
-err2:
-    iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge);
-err1:
-    return -1;
-}
-
-static void
-networkRemoveGeneralIp6tablesRules(virNetworkObjPtr network)
-{
-    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
-        !network->def->ipv6nogw) {
-        return;
-    }
-    if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
-        iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 547);
-        iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53);
-        iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53);
-    }
-
-    /* the following rules are there if no IPv6 address has been defined
-     * but network->def->ipv6nogw == true
-     */
-    iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge);
-    iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge);
-    iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge);
-}
-
-static int
-networkAddGeneralFirewallRules(virNetworkObjPtr network)
-{
-    size_t i;
-    virNetworkIpDefPtr ipv4def;
-
-    /* First look for first IPv4 address that has dhcp or tftpboot defined. */
-    /* We support dhcp config on 1 IPv4 interface only. */
-    for (i = 0;
-         (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
-         i++) {
-        if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
-            break;
-    }
-
-    /* allow DHCP requests through to dnsmasq */
-
-    if (iptablesAddTcpInput(AF_INET, network->def->bridge, 67) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow DHCP requests from '%s'"),
-                       network->def->bridge);
-        goto err1;
-    }
-
-    if (iptablesAddUdpInput(AF_INET, network->def->bridge, 67) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow DHCP requests from '%s'"),
-                       network->def->bridge);
-        goto err2;
-    }
-
-    /* If we are doing local DHCP service on this network, attempt to
-     * add a rule that will fixup the checksum of DHCP response
-     * packets back to the guests (but report failure without
-     * aborting, since not all iptables implementations support it).
-     */
-
-    if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) &&
-        (iptablesAddOutputFixUdpChecksum(network->def->bridge, 68) < 0)) {
-        VIR_WARN("Could not add rule to fixup DHCP response checksums "
-                 "on network '%s'.", network->def->name);
-        VIR_WARN("May need to update iptables package & kernel to support CHECKSUM rule.");
-    }
-
-    /* allow DNS requests through to dnsmasq */
-    if (iptablesAddTcpInput(AF_INET, network->def->bridge, 53) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow DNS requests from '%s'"),
-                       network->def->bridge);
-        goto err3;
-    }
-
-    if (iptablesAddUdpInput(AF_INET, network->def->bridge, 53) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow DNS requests from '%s'"),
-                       network->def->bridge);
-        goto err4;
-    }
-
-    /* allow TFTP requests through to dnsmasq if necessary */
-    if (ipv4def && ipv4def->tftproot &&
-        iptablesAddUdpInput(AF_INET, network->def->bridge, 69) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow TFTP requests from '%s'"),
-                       network->def->bridge);
-        goto err5;
-    }
-
-    /* Catch all rules to block forwarding to/from bridges */
-
-    if (iptablesAddForwardRejectOut(AF_INET, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to block outbound traffic from '%s'"),
-                       network->def->bridge);
-        goto err6;
-    }
-
-    if (iptablesAddForwardRejectIn(AF_INET, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to block inbound traffic to '%s'"),
-                       network->def->bridge);
-        goto err7;
-    }
-
-    /* Allow traffic between guests on the same bridge */
-    if (iptablesAddForwardAllowCross(AF_INET, network->def->bridge) < 0) {
-        virReportError(VIR_ERR_SYSTEM_ERROR,
-                       _("failed to add iptables rule to allow cross bridge traffic on '%s'"),
-                       network->def->bridge);
-        goto err8;
-    }
-
-    /* add IPv6 general rules, if needed */
-    if (networkAddGeneralIp6tablesRules(network) < 0) {
-        goto err9;
-    }
-
-    return 0;
-
-    /* unwind in reverse order from the point of failure */
-err9:
-    iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
-err8:
-    iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
-err7:
-    iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
-err6:
-    if (ipv4def && ipv4def->tftproot) {
-        iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
-    }
-err5:
-    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
-err4:
-    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
-err3:
-    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
-err2:
-    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
-err1:
-    return -1;
-}
-
-static void
-networkRemoveGeneralFirewallRules(virNetworkObjPtr network)
-{
-    size_t i;
-    virNetworkIpDefPtr ipv4def;
-
-    networkRemoveGeneralIp6tablesRules(network);
-
-    for (i = 0;
-         (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
-         i++) {
-        if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
-            break;
-    }
-
-    iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
-    iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
-    iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
-    if (ipv4def && ipv4def->tftproot) {
-        iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
-    }
-    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
-    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
-    if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
-        iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68);
-    }
-    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
-    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
-}
-
-static int
-networkAddIpSpecificFirewallRules(virNetworkObjPtr network,
-                                  virNetworkIpDefPtr ipdef)
-{
-    /* NB: in the case of IPv6, routing rules are added when the
-     * forward mode is NAT. This is because IPv6 has no NAT.
-     */
-
-    if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
-        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
-            return networkAddMasqueradingFirewallRules(network, ipdef);
-        else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
-            return networkAddRoutingFirewallRules(network, ipdef);
-    } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
-        return networkAddRoutingFirewallRules(network, ipdef);
-    }
-    return 0;
-}
-
-static void
-networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network,
-                                     virNetworkIpDefPtr ipdef)
-{
-    if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
-        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
-            networkRemoveMasqueradingFirewallRules(network, ipdef);
-        else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
-            networkRemoveRoutingFirewallRules(network, ipdef);
-    } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
-        networkRemoveRoutingFirewallRules(network, ipdef);
-    }
-}
-
-/* Add all rules for all ip addresses (and general rules) on a network */
-static int
-networkAddFirewallRules(virNetworkObjPtr network)
-{
-    size_t i, j;
-    virNetworkIpDefPtr ipdef;
-    virErrorPtr orig_error;
-
-    /* Add "once per network" rules */
-    if (networkAddGeneralFirewallRules(network) < 0)
-        return -1;
-
-    for (i = 0;
-         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
-         i++) {
-        /* Add address-specific iptables rules */
-        if (networkAddIpSpecificFirewallRules(network, ipdef) < 0) {
-            goto err;
-        }
-    }
-    return 0;
-
-err:
-    /* store the previous error message before attempting removal of rules */
-    orig_error = virSaveLastError();
-
-    /* The final failed call to networkAddIpSpecificFirewallRules will
-     * have removed any rules it created, but we need to remove those
-     * added for previous IP addresses.
-     */
-    for (j = 0; j < i; j++) {
-        if ((ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, j)))
-            networkRemoveIpSpecificFirewallRules(network, ipdef);
-    }
-    networkRemoveGeneralFirewallRules(network);
-
-    /* return the original error */
-    virSetError(orig_error);
-    virFreeError(orig_error);
-    return -1;
-}
-
-/* Remove all rules for all ip addresses (and general rules) on a network */
-static void
-networkRemoveFirewallRules(virNetworkObjPtr network)
-{
-    size_t i;
-    virNetworkIpDefPtr ipdef;
-
-    for (i = 0;
-         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
-         i++) {
-        networkRemoveIpSpecificFirewallRules(network, ipdef);
-    }
-    networkRemoveGeneralFirewallRules(network);
-}
-
 static void
 networkReloadFirewallRules(virNetworkDriverStatePtr driver)
 {
@@ -2206,104 +1598,6 @@ cleanup:
     return ret;
 }
 
-#define PROC_NET_ROUTE "/proc/net/route"
-
-/* XXX: This function can be a lot more exhaustive, there are certainly
- *      other scenarios where we can ruin host network connectivity.
- * XXX: Using a proper library is preferred over parsing /proc
- */
-static int
-networkCheckRouteCollision(virNetworkObjPtr network)
-{
-    int ret = 0, len;
-    char *cur, *buf = NULL;
-    /* allow for up to 100000 routes (each line is 128 bytes) */
-    enum {MAX_ROUTE_SIZE = 128*100000};
-
-    /* Read whole routing table into memory */
-    if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
-        goto out;
-
-    /* Dropping the last character shouldn't hurt */
-    if (len > 0)
-        buf[len-1] = '\0';
-
-    VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf);
-
-    if (!STRPREFIX(buf, "Iface"))
-        goto out;
-
-    /* First line is just headings, skip it */
-    cur = strchr(buf, '\n');
-    if (cur)
-        cur++;
-
-    while (cur) {
-        char iface[17], dest[128], mask[128];
-        unsigned int addr_val, mask_val;
-        virNetworkIpDefPtr ipdef;
-        int num;
-        size_t i;
-
-        /* NUL-terminate the line, so sscanf doesn't go beyond a newline.  */
-        char *nl = strchr(cur, '\n');
-        if (nl) {
-            *nl++ = '\0';
-        }
-
-        num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s",
-                     iface, dest, mask);
-        cur = nl;
-
-        if (num != 3) {
-            VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE);
-            continue;
-        }
-
-        if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) {
-            VIR_DEBUG("Failed to convert network address %s to uint", dest);
-            continue;
-        }
-
-        if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) {
-            VIR_DEBUG("Failed to convert network mask %s to uint", mask);
-            continue;
-        }
-
-        addr_val &= mask_val;
-
-        for (i = 0;
-             (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
-             i++) {
-
-            unsigned int net_dest;
-            virSocketAddr netmask;
-
-            if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
-                VIR_WARN("Failed to get netmask of '%s'",
-                         network->def->bridge);
-                continue;
-            }
-
-            net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
-                        netmask.data.inet4.sin_addr.s_addr);
-
-            if ((net_dest == addr_val) &&
-                (netmask.data.inet4.sin_addr.s_addr == mask_val)) {
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Network is already in use by interface %s"),
-                               iface);
-                ret = -1;
-                goto out;
-            }
-        }
-    }
-
-out:
-    VIR_FREE(buf);
-    return ret;
-}
-
 /* add an IP address to a bridge */
 static int
 networkAddAddrToBridge(virNetworkObjPtr network,
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
new file mode 100644
index 0000000..80430a8
--- /dev/null
+++ b/src/network/bridge_driver_linux.c
@@ -0,0 +1,709 @@
+/*
+ * bridge_driver_linux.c: Linux implementation of bridge driver
+ *
+ * Copyright (C) 2006-2013 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "viralloc.h"
+#include "virfile.h"
+#include "viriptables.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define PROC_NET_ROUTE "/proc/net/route"
+
+/* XXX: This function can be a lot more exhaustive, there are certainly
+ *      other scenarios where we can ruin host network connectivity.
+ * XXX: Using a proper library is preferred over parsing /proc
+ */
+int networkCheckRouteCollision(virNetworkObjPtr network)
+{
+    int ret = 0, len;
+    char *cur, *buf = NULL;
+    /* allow for up to 100000 routes (each line is 128 bytes) */
+    enum {MAX_ROUTE_SIZE = 128*100000};
+
+    /* Read whole routing table into memory */
+    if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
+        goto out;
+
+    /* Dropping the last character shouldn't hurt */
+    if (len > 0)
+        buf[len-1] = '\0';
+
+    VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf);
+
+    if (!STRPREFIX(buf, "Iface"))
+        goto out;
+
+    /* First line is just headings, skip it */
+    cur = strchr(buf, '\n');
+    if (cur)
+        cur++;
+
+    while (cur) {
+        char iface[17], dest[128], mask[128];
+        unsigned int addr_val, mask_val;
+        virNetworkIpDefPtr ipdef;
+        int num;
+        size_t i;
+
+        /* NUL-terminate the line, so sscanf doesn't go beyond a newline.  */
+        char *nl = strchr(cur, '\n');
+        if (nl) {
+            *nl++ = '\0';
+        }
+
+        num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s",
+                     iface, dest, mask);
+        cur = nl;
+
+        if (num != 3) {
+            VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE);
+            continue;
+        }
+
+        if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) {
+            VIR_DEBUG("Failed to convert network address %s to uint", dest);
+            continue;
+        }
+
+        if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) {
+            VIR_DEBUG("Failed to convert network mask %s to uint", mask);
+            continue;
+        }
+
+        addr_val &= mask_val;
+
+        for (i = 0;
+             (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
+             i++) {
+
+            unsigned int net_dest;
+            virSocketAddr netmask;
+
+            if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
+                VIR_WARN("Failed to get netmask of '%s'",
+                         network->def->bridge);
+                continue;
+            }
+
+            net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
+                        netmask.data.inet4.sin_addr.s_addr);
+
+            if ((net_dest == addr_val) &&
+                (netmask.data.inet4.sin_addr.s_addr == mask_val)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Network is already in use by interface %s"),
+                               iface);
+                ret = -1;
+                goto out;
+            }
+        }
+    }
+
+out:
+    VIR_FREE(buf);
+    return ret;
+}
+
+int networkAddMasqueradingFirewallRules(virNetworkObjPtr network,
+                                        virNetworkIpDefPtr ipdef)
+{
+    int prefix = virNetworkIpDefPrefix(ipdef);
+    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
+
+    if (prefix < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Invalid prefix or netmask for '%s'"),
+                       network->def->bridge);
+        goto masqerr1;
+    }
+
+    /* allow forwarding packets from the bridge interface */
+    if (iptablesAddForwardAllowOut(&ipdef->address,
+                                   prefix,
+                                   network->def->bridge,
+                                   forwardIf) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow forwarding from '%s'"),
+                       network->def->bridge);
+        goto masqerr1;
+    }
+
+    /* allow forwarding packets to the bridge interface if they are
+     * part of an existing connection
+     */
+    if (iptablesAddForwardAllowRelatedIn(&ipdef->address,
+                                         prefix,
+                                         network->def->bridge,
+                                         forwardIf) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow forwarding to '%s'"),
+                       network->def->bridge);
+        goto masqerr2;
+    }
+
+    /*
+     * Enable masquerading.
+     *
+     * We need to end up with 3 rules in the table in this order
+     *
+     *  1. protocol=tcp with sport mapping restriction
+     *  2. protocol=udp with sport mapping restriction
+     *  3. generic any protocol
+     *
+     * The sport mappings are required, because default IPtables
+     * MASQUERADE maintain port numbers unchanged where possible.
+     *
+     * NFS can be configured to only "trust" port numbers < 1023.
+     *
+     * Guests using NAT thus need to be prevented from having port
+     * numbers < 1023, otherwise they can bypass the NFS "security"
+     * check on the source port number.
+     *
+     * Since we use '--insert' to add rules to the header of the
+     * chain, we actually need to add them in the reverse of the
+     * order just mentioned !
+     */
+
+    /* First the generic masquerade rule for other protocols */
+    if (iptablesAddForwardMasquerade(&ipdef->address,
+                                     prefix,
+                                     forwardIf,
+                                     &network->def->forward.addr,
+                                     &network->def->forward.port,
+                                     NULL) < 0) {
+        if (forwardIf)
+            virReportError(VIR_ERR_SYSTEM_ERROR,
+                           _("failed to add iptables rule to enable masquerading to %s"),
+                           forwardIf);
+        else
+            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
+                           _("failed to add iptables rule to enable masquerading"));
+        goto masqerr3;
+    }
+
+    /* UDP with a source port restriction */
+    if (iptablesAddForwardMasquerade(&ipdef->address,
+                                     prefix,
+                                     forwardIf,
+                                     &network->def->forward.addr,
+                                     &network->def->forward.port,
+                                     "udp") < 0) {
+        if (forwardIf)
+            virReportError(VIR_ERR_SYSTEM_ERROR,
+                           _("failed to add iptables rule to enable UDP masquerading to %s"),
+                           forwardIf);
+        else
+            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
+                           _("failed to add iptables rule to enable UDP masquerading"));
+        goto masqerr4;
+    }
+
+    /* TCP with a source port restriction */
+    if (iptablesAddForwardMasquerade(&ipdef->address,
+                                     prefix,
+                                     forwardIf,
+                                     &network->def->forward.addr,
+                                     &network->def->forward.port,
+                                     "tcp") < 0) {
+        if (forwardIf)
+            virReportError(VIR_ERR_SYSTEM_ERROR,
+                           _("failed to add iptables rule to enable TCP masquerading to %s"),
+                           forwardIf);
+        else
+            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
+                           _("failed to add iptables rule to enable TCP masquerading"));
+        goto masqerr5;
+    }
+
+    return 0;
+
+ masqerr5:
+    iptablesRemoveForwardMasquerade(&ipdef->address,
+                                    prefix,
+                                    forwardIf,
+                                    &network->def->forward.addr,
+                                    &network->def->forward.port,
+                                    "udp");
+ masqerr4:
+    iptablesRemoveForwardMasquerade(&ipdef->address,
+                                    prefix,
+                                    forwardIf,
+                                    &network->def->forward.addr,
+                                    &network->def->forward.port,
+                                    NULL);
+ masqerr3:
+    iptablesRemoveForwardAllowRelatedIn(&ipdef->address,
+                                        prefix,
+                                        network->def->bridge,
+                                        forwardIf);
+ masqerr2:
+    iptablesRemoveForwardAllowOut(&ipdef->address,
+                                  prefix,
+                                  network->def->bridge,
+                                  forwardIf);
+ masqerr1:
+    return -1;
+}
+
+void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network,
+                                            virNetworkIpDefPtr ipdef)
+{
+    int prefix = virNetworkIpDefPrefix(ipdef);
+    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
+
+    if (prefix >= 0) {
+        iptablesRemoveForwardMasquerade(&ipdef->address,
+                                        prefix,
+                                        forwardIf,
+                                        &network->def->forward.addr,
+                                        &network->def->forward.port,
+                                        "tcp");
+        iptablesRemoveForwardMasquerade(&ipdef->address,
+                                        prefix,
+                                        forwardIf,
+                                        &network->def->forward.addr,
+                                        &network->def->forward.port,
+                                        "udp");
+        iptablesRemoveForwardMasquerade(&ipdef->address,
+                                        prefix,
+                                        forwardIf,
+                                        &network->def->forward.addr,
+                                        &network->def->forward.port,
+                                        NULL);
+
+        iptablesRemoveForwardAllowRelatedIn(&ipdef->address,
+                                            prefix,
+                                            network->def->bridge,
+                                            forwardIf);
+        iptablesRemoveForwardAllowOut(&ipdef->address,
+                                      prefix,
+                                      network->def->bridge,
+                                      forwardIf);
+    }
+}
+
+int networkAddRoutingFirewallRules(virNetworkObjPtr network,
+                                   virNetworkIpDefPtr ipdef)
+{
+    int prefix = virNetworkIpDefPrefix(ipdef);
+    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
+
+    if (prefix < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Invalid prefix or netmask for '%s'"),
+                       network->def->bridge);
+        goto routeerr1;
+    }
+
+    /* allow routing packets from the bridge interface */
+    if (iptablesAddForwardAllowOut(&ipdef->address,
+                                   prefix,
+                                   network->def->bridge,
+                                   forwardIf) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow routing from '%s'"),
+                       network->def->bridge);
+        goto routeerr1;
+    }
+
+    /* allow routing packets to the bridge interface */
+    if (iptablesAddForwardAllowIn(&ipdef->address,
+                                  prefix,
+                                  network->def->bridge,
+                                  forwardIf) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow routing to '%s'"),
+                       network->def->bridge);
+        goto routeerr2;
+    }
+
+    return 0;
+
+routeerr2:
+    iptablesRemoveForwardAllowOut(&ipdef->address,
+                                  prefix,
+                                  network->def->bridge,
+                                  forwardIf);
+routeerr1:
+    return -1;
+}
+
+void networkRemoveRoutingFirewallRules(virNetworkObjPtr network,
+                                       virNetworkIpDefPtr ipdef)
+{
+    int prefix = virNetworkIpDefPrefix(ipdef);
+    const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
+
+    if (prefix >= 0) {
+        iptablesRemoveForwardAllowIn(&ipdef->address,
+                                     prefix,
+                                     network->def->bridge,
+                                     forwardIf);
+
+        iptablesRemoveForwardAllowOut(&ipdef->address,
+                                      prefix,
+                                      network->def->bridge,
+                                      forwardIf);
+    }
+}
+
+/* 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 virtual systems.
+ * If any IPv6 addresses are defined, then add the rules for regular operation.
+ */
+static int
+networkAddGeneralIp6tablesRules(virNetworkObjPtr network)
+{
+
+    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
+        !network->def->ipv6nogw) {
+        return 0;
+    }
+
+    /* Catch all rules to block forwarding to/from bridges */
+
+    if (iptablesAddForwardRejectOut(AF_INET6, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to block outbound traffic from '%s'"),
+                       network->def->bridge);
+        goto err1;
+    }
+
+    if (iptablesAddForwardRejectIn(AF_INET6, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to block inbound traffic to '%s'"),
+                       network->def->bridge);
+        goto err2;
+    }
+
+    /* Allow traffic between guests on the same bridge */
+    if (iptablesAddForwardAllowCross(AF_INET6, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to allow cross bridge traffic on '%s'"),
+                       network->def->bridge);
+        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(AF_INET6, network->def->bridge, 53) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to allow DNS requests from '%s'"),
+                       network->def->bridge);
+        goto err4;
+    }
+
+    if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 53) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to allow DNS requests from '%s'"),
+                       network->def->bridge);
+        goto err5;
+    }
+
+    if (iptablesAddUdpInput(AF_INET6, network->def->bridge, 547) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add ip6tables rule to allow DHCP6 requests from '%s'"),
+                       network->def->bridge);
+        goto err6;
+    }
+
+    return 0;
+
+    /* unwind in reverse order from the point of failure */
+err6:
+    iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53);
+err5:
+    iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53);
+err4:
+    iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge);
+err3:
+    iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge);
+err2:
+    iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge);
+err1:
+    return -1;
+}
+
+static void
+networkRemoveGeneralIp6tablesRules(virNetworkObjPtr network)
+{
+    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
+        !network->def->ipv6nogw) {
+        return;
+    }
+    if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
+        iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 547);
+        iptablesRemoveUdpInput(AF_INET6, network->def->bridge, 53);
+        iptablesRemoveTcpInput(AF_INET6, network->def->bridge, 53);
+    }
+
+    /* the following rules are there if no IPv6 address has been defined
+     * but network->def->ipv6nogw == true
+     */
+    iptablesRemoveForwardAllowCross(AF_INET6, network->def->bridge);
+    iptablesRemoveForwardRejectIn(AF_INET6, network->def->bridge);
+    iptablesRemoveForwardRejectOut(AF_INET6, network->def->bridge);
+}
+
+int networkAddGeneralFirewallRules(virNetworkObjPtr network)
+{
+    size_t i;
+    virNetworkIpDefPtr ipv4def;
+
+    /* First look for first IPv4 address that has dhcp or tftpboot defined. */
+    /* We support dhcp config on 1 IPv4 interface only. */
+    for (i = 0;
+         (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
+         i++) {
+        if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
+            break;
+    }
+
+    /* allow DHCP requests through to dnsmasq */
+
+    if (iptablesAddTcpInput(AF_INET, network->def->bridge, 67) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow DHCP requests from '%s'"),
+                       network->def->bridge);
+        goto err1;
+    }
+
+    if (iptablesAddUdpInput(AF_INET, network->def->bridge, 67) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow DHCP requests from '%s'"),
+                       network->def->bridge);
+        goto err2;
+    }
+
+    /* If we are doing local DHCP service on this network, attempt to
+     * add a rule that will fixup the checksum of DHCP response
+     * packets back to the guests (but report failure without
+     * aborting, since not all iptables implementations support it).
+     */
+
+    if (ipv4def && (ipv4def->nranges || ipv4def->nhosts) &&
+        (iptablesAddOutputFixUdpChecksum(network->def->bridge, 68) < 0)) {
+        VIR_WARN("Could not add rule to fixup DHCP response checksums "
+                 "on network '%s'.", network->def->name);
+        VIR_WARN("May need to update iptables package & kernel to support CHECKSUM rule.");
+    }
+
+    /* allow DNS requests through to dnsmasq */
+    if (iptablesAddTcpInput(AF_INET, network->def->bridge, 53) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow DNS requests from '%s'"),
+                       network->def->bridge);
+        goto err3;
+    }
+
+    if (iptablesAddUdpInput(AF_INET, network->def->bridge, 53) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow DNS requests from '%s'"),
+                       network->def->bridge);
+        goto err4;
+    }
+
+    /* allow TFTP requests through to dnsmasq if necessary */
+    if (ipv4def && ipv4def->tftproot &&
+        iptablesAddUdpInput(AF_INET, network->def->bridge, 69) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow TFTP requests from '%s'"),
+                       network->def->bridge);
+        goto err5;
+    }
+
+    /* Catch all rules to block forwarding to/from bridges */
+
+    if (iptablesAddForwardRejectOut(AF_INET, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to block outbound traffic from '%s'"),
+                       network->def->bridge);
+        goto err6;
+    }
+
+    if (iptablesAddForwardRejectIn(AF_INET, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to block inbound traffic to '%s'"),
+                       network->def->bridge);
+        goto err7;
+    }
+
+    /* Allow traffic between guests on the same bridge */
+    if (iptablesAddForwardAllowCross(AF_INET, network->def->bridge) < 0) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("failed to add iptables rule to allow cross bridge traffic on '%s'"),
+                       network->def->bridge);
+        goto err8;
+    }
+
+    /* add IPv6 general rules, if needed */
+    if (networkAddGeneralIp6tablesRules(network) < 0) {
+        goto err9;
+    }
+
+    return 0;
+
+    /* unwind in reverse order from the point of failure */
+err9:
+    iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
+err8:
+    iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
+err7:
+    iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
+err6:
+    if (ipv4def && ipv4def->tftproot) {
+        iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
+    }
+err5:
+    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
+err4:
+    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
+err3:
+    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
+err2:
+    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
+err1:
+    return -1;
+}
+
+void networkRemoveGeneralFirewallRules(virNetworkObjPtr network)
+{
+    size_t i;
+    virNetworkIpDefPtr ipv4def;
+
+    networkRemoveGeneralIp6tablesRules(network);
+
+    for (i = 0;
+         (ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
+         i++) {
+        if (ipv4def->nranges || ipv4def->nhosts || ipv4def->tftproot)
+            break;
+    }
+
+    iptablesRemoveForwardAllowCross(AF_INET, network->def->bridge);
+    iptablesRemoveForwardRejectIn(AF_INET, network->def->bridge);
+    iptablesRemoveForwardRejectOut(AF_INET, network->def->bridge);
+    if (ipv4def && ipv4def->tftproot) {
+        iptablesRemoveUdpInput(AF_INET, network->def->bridge, 69);
+    }
+    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 53);
+    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 53);
+    if (ipv4def && (ipv4def->nranges || ipv4def->nhosts)) {
+        iptablesRemoveOutputFixUdpChecksum(network->def->bridge, 68);
+    }
+    iptablesRemoveUdpInput(AF_INET, network->def->bridge, 67);
+    iptablesRemoveTcpInput(AF_INET, network->def->bridge, 67);
+}
+
+int networkAddIpSpecificFirewallRules(virNetworkObjPtr network,
+                                      virNetworkIpDefPtr ipdef)
+{
+    /* NB: in the case of IPv6, routing rules are added when the
+     * forward mode is NAT. This is because IPv6 has no NAT.
+     */
+
+    if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
+        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
+            return networkAddMasqueradingFirewallRules(network, ipdef);
+        else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+            return networkAddRoutingFirewallRules(network, ipdef);
+    } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+        return networkAddRoutingFirewallRules(network, ipdef);
+    }
+    return 0;
+}
+
+void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network,
+                                          virNetworkIpDefPtr ipdef)
+{
+    if (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) {
+        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
+            networkRemoveMasqueradingFirewallRules(network, ipdef);
+        else if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+            networkRemoveRoutingFirewallRules(network, ipdef);
+    } else if (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+        networkRemoveRoutingFirewallRules(network, ipdef);
+    }
+}
+
+/* Add all rules for all ip addresses (and general rules) on a network */
+int networkAddFirewallRules(virNetworkObjPtr network)
+{
+    size_t i, j;
+    virNetworkIpDefPtr ipdef;
+    virErrorPtr orig_error;
+
+    /* Add "once per network" rules */
+    if (networkAddGeneralFirewallRules(network) < 0)
+        return -1;
+
+    for (i = 0;
+         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
+         i++) {
+        /* Add address-specific iptables rules */
+        if (networkAddIpSpecificFirewallRules(network, ipdef) < 0) {
+            goto err;
+        }
+    }
+    return 0;
+
+err:
+    /* store the previous error message before attempting removal of rules */
+    orig_error = virSaveLastError();
+
+    /* The final failed call to networkAddIpSpecificFirewallRules will
+     * have removed any rules it created, but we need to remove those
+     * added for previous IP addresses.
+     */
+    for (j = 0; j < i; j++) {
+        if ((ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, j)))
+            networkRemoveIpSpecificFirewallRules(network, ipdef);
+    }
+    networkRemoveGeneralFirewallRules(network);
+
+    /* return the original error */
+    virSetError(orig_error);
+    virFreeError(orig_error);
+    return -1;
+}
+
+/* Remove all rules for all ip addresses (and general rules) on a network */
+void networkRemoveFirewallRules(virNetworkObjPtr network)
+{
+    size_t i;
+    virNetworkIpDefPtr ipdef;
+
+    for (i = 0;
+         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
+         i++) {
+        networkRemoveIpSpecificFirewallRules(network, ipdef);
+    }
+    networkRemoveGeneralFirewallRules(network);
+}
diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c
new file mode 100644
index 0000000..f983402
--- /dev/null
+++ b/src/network/bridge_driver_nop.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006-2013 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+int networkCheckRouteCollision(virNetworkObjPtr network)
+{
+    return 0;
+}
+
+int networkAddMasqueradingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                        virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+void networkRemoveMasqueradingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                            virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+}
+
+int networkAddRoutingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                   virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+void networkRemoveRoutingFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                       virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+}
+
+int networkAddGeneralFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+void networkRemoveGeneralFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED)
+{
+}
+
+int networkAddIpSpecificFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                      virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+void networkRemoveIpSpecificFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED,
+                                          virNetworkIpDefPtr ipdef ATTRIBUTE_UNUSED)
+{
+}
+
+int networkAddFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+void networkRemoveFirewallRules(virNetworkObjPtr network ATTRIBUTE_UNUSED)
+{
+}
diff --git a/src/network/bridge_driver_platform.c b/src/network/bridge_driver_platform.c
new file mode 100644
index 0000000..1d2fc02
--- /dev/null
+++ b/src/network/bridge_driver_platform.c
@@ -0,0 +1,32 @@
+/*
+ * bridge_driver_platform.c: platform specific part of bridge driver
+ *
+ * Copyright (C) 2006-2013 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "bridge_driver_platform.h"
+
+#if defined(__linux__)
+# include "bridge_driver_linux.c"
+#else
+# include "bridge_driver_nop.c"
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1fd84af..24b32db 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -70,6 +70,7 @@ src/lxc/lxc_process.c
 src/libxl/libxl_driver.c
 src/libxl/libxl_conf.c
 src/network/bridge_driver.c
+src/network/bridge_driver_linux.c
 src/node_device/node_device_driver.c
 src/node_device/node_device_hal.c
 src/node_device/node_device_linux_sysfs.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 84372cb..80309fa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -725,8 +725,9 @@ PARALLELS_DRIVER_SOURCES =					\
 		parallels/parallels_storage.c		\
 		parallels/parallels_network.c
 
-NETWORK_DRIVER_SOURCES =					\
-		network/bridge_driver.h network/bridge_driver.c
+NETWORK_DRIVER_SOURCES =								\
+		network/bridge_driver.h network/bridge_driver.c 			\
+		network/bridge_driver_platform.h network/bridge_driver_platform.c
 
 INTERFACE_DRIVER_SOURCES =
 
-- 
1.7.9.5




More information about the libvir-list mailing list