]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Convert nwfilter ebiptablesAllTeardown to virFirewall
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 14 Mar 2014 11:53:06 +0000 (11:53 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 25 Apr 2014 14:44:09 +0000 (15:44 +0100)
Convert the nwfilter ebiptablesAllTeardown method to use the
virFirewall object APIs instead of creating shell scripts
using virBuffer APIs. This provides a performance improvement
through allowing direct use of firewalld dbus APIs and will
facilitate automated testing.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
src/Makefile.am
src/nwfilter/nwfilter_ebiptables_driver.c
tests/Makefile.am
tests/nwfilterebiptablestest.c [new file with mode: 0644]

index 0f295ed36eb18de7bf73f3805b4ab7c77eaa2a37..dd0abe74ce3b76452d44caa0d42f0ad0493f8828 100644 (file)
@@ -1538,6 +1538,9 @@ endif WITH_NODE_DEVICES
 
 
 if WITH_NWFILTER
+noinst_LTLIBRARIES += libvirt_driver_nwfilter_impl.la
+libvirt_driver_nwfilter_la_SOURCES =
+libvirt_driver_nwfilter_la_LIBADD = libvirt_driver_nwfilter_impl.la
 if WITH_DRIVER_MODULES
 mod_LTLIBRARIES += libvirt_driver_nwfilter.la
 else ! WITH_DRIVER_MODULES
@@ -1545,20 +1548,23 @@ noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
 # Stateful, so linked to daemon instead
 #libvirt_la_BUILT_LIBADD += libvirt_driver_nwfilter.la
 endif ! WITH_DRIVER_MODULES
-libvirt_driver_nwfilter_la_CFLAGS = \
+libvirt_driver_nwfilter_impl_la_CFLAGS = \
                $(LIBPCAP_CFLAGS) \
                $(LIBNL_CFLAGS) \
                $(DBUS_CFLAGS) \
                -I$(top_srcdir)/src/access \
                -I$(top_srcdir)/src/conf \
                $(AM_CFLAGS)
-libvirt_driver_nwfilter_la_LDFLAGS = $(AM_LDFLAGS)
-libvirt_driver_nwfilter_la_LIBADD = $(LIBPCAP_LIBS) $(LIBNL_LIBS) $(DBUS_LIBS)
+libvirt_driver_nwfilter_impl_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_nwfilter_impl_la_LIBADD = \
+               $(LIBPCAP_LIBS) \
+               $(LIBNL_LIBS) \
+               $(DBUS_LIBS)
 if WITH_DRIVER_MODULES
-libvirt_driver_nwfilter_la_LIBADD += ../gnulib/lib/libgnu.la
-libvirt_driver_nwfilter_la_LDFLAGS += -module -avoid-version
+libvirt_driver_nwfilter_impl_la_LIBADD += ../gnulib/lib/libgnu.la
+libvirt_driver_nwfilter_impl_la_LDFLAGS += -module -avoid-version
 endif WITH_DRIVER_MODULES
-libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
+libvirt_driver_nwfilter_impl_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
 endif WITH_NWFILTER
 
 
index 07589be4c10254199a22152ad5cb367b1edb9519..7b944dfd504983c806a2d9bfb5deea37e26c121a 100644 (file)
@@ -45,6 +45,7 @@
 #include "configmake.h"
 #include "intprops.h"
 #include "virstring.h"
+#include "virfirewall.h"
 
 #define VIR_FROM_THIS VIR_FROM_NWFILTER
 
@@ -180,22 +181,15 @@ static const char ebiptables_script_set_ifs[] =
     snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname)
 
 #define PHYSDEV_IN  "--physdev-in"
-#define PHYSDEV_OUT "--physdev-is-bridged --physdev-out"
-/*
- * Previous versions of libvirt only used --physdev-out.
- * To be able to upgrade with running VMs we need to be able to
- * remove rules generated by those older versions of libvirt.
- */
-#define PHYSDEV_OUT_OLD  "--physdev-out"
 
 static const char *m_state_out_str   = "-m state --state NEW,ESTABLISHED";
 static const char *m_state_in_str    = "-m state --state ESTABLISHED";
 static const char *m_state_out_str_new = "-m conntrack --ctstate NEW,ESTABLISHED";
 static const char *m_state_in_str_new  = "-m conntrack --ctstate ESTABLISHED";
 
-static const char *m_physdev_in_str  = "-m physdev " PHYSDEV_IN;
-static const char *m_physdev_out_str = "-m physdev " PHYSDEV_OUT;
-static const char *m_physdev_out_old_str = "-m physdev " PHYSDEV_OUT_OLD;
+static const char *m_physdev_in_str  = "-m physdev --physdev-in";
+static const char *m_physdev_out_str = "-m physdev --physdev-is-bridged --physdev-out";
+static const char *m_physdev_out_old_str = "-m physdev --physdev-out";
 
 #define MATCH_STATE_OUT    m_state_out_str
 #define MATCH_STATE_IN     m_state_in_str
@@ -203,6 +197,10 @@ static const char *m_physdev_out_old_str = "-m physdev " PHYSDEV_OUT_OLD;
 #define MATCH_PHYSDEV_OUT  m_physdev_out_str
 #define MATCH_PHYSDEV_OUT_OLD  m_physdev_out_old_str
 
+#define MATCH_PHYSDEV_IN_FW   "-m", "physdev", "--physdev-in"
+#define MATCH_PHYSDEV_OUT_FW  "-m", "physdev", "--physdev-is-bridged", "--physdev-out"
+#define MATCH_PHYSDEV_OUT_OLD_FW  "-m", "physdev", "--physdev-out"
+
 #define COMMENT_VARNAME "comment"
 
 static int ebtablesRemoveBasicRules(const char *ifname);
@@ -249,6 +247,12 @@ static const struct ushort_map l3_protocols[] = {
 };
 
 
+static char chainprefixes_host[3] = {
+    CHAINPREFIX_HOST_IN,
+    CHAINPREFIX_HOST_OUT,
+    0
+};
+
 static int
 printVar(virNWFilterVarCombIterPtr vars,
          char *buf, int bufsize,
@@ -660,6 +664,36 @@ _iptablesRemoveRootChain(virBufferPtr buf,
 }
 
 
+static void
+_iptablesRemoveRootChainFW(virFirewallPtr fw,
+                           virFirewallLayer layer,
+                           char prefix,
+                           bool incoming, const char *ifname,
+                           int isTempChain)
+{
+    char chain[MAX_CHAINNAME_LENGTH];
+    char chainPrefix[2] = {
+        prefix,
+    };
+
+    if (isTempChain)
+        chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN_TEMP
+                                  : CHAINPREFIX_HOST_OUT_TEMP;
+    else
+        chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN
+                                  : CHAINPREFIX_HOST_OUT;
+
+    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+    virFirewallAddRuleFull(fw, layer,
+                           true, NULL, NULL,
+                           "-F", chain, NULL);
+    virFirewallAddRuleFull(fw, layer,
+                           true, NULL, NULL,
+                           "-X", chain, NULL);
+}
+
+
 static void
 iptablesRemoveRootChain(virBufferPtr buf,
                         char prefix,
@@ -670,6 +704,17 @@ iptablesRemoveRootChain(virBufferPtr buf,
 }
 
 
+static void
+iptablesRemoveRootChainFW(virFirewallPtr fw,
+                          virFirewallLayer layer,
+                          char prefix,
+                          bool incoming,
+                          const char *ifname)
+{
+    _iptablesRemoveRootChainFW(fw, layer, prefix, incoming, ifname, false);
+}
+
+
 static void
 iptablesRemoveTmpRootChain(virBufferPtr buf,
                            char prefix,
@@ -701,6 +746,17 @@ iptablesRemoveRootChains(virBufferPtr buf,
 }
 
 
+static void
+iptablesRemoveRootChainsFW(virFirewallPtr fw,
+                           virFirewallLayer layer,
+                           const char *ifname)
+{
+    iptablesRemoveRootChainFW(fw, layer, 'F', false, ifname);
+    iptablesRemoveRootChainFW(fw, layer, 'F', true, ifname);
+    iptablesRemoveRootChainFW(fw, layer, 'H', true, ifname);
+}
+
+
 static void
 iptablesLinkTmpRootChain(virBufferPtr buf,
                          const char *basechain,
@@ -762,14 +818,15 @@ iptablesSetupVirtInPost(virBufferPtr buf,
 
 
 static void
-iptablesClearVirtInPost(virBufferPtr buf,
-                        const char *ifname)
+iptablesClearVirtInPostFW(virFirewallPtr fw,
+                          virFirewallLayer layer,
+                          const char *ifname)
 {
-    const char *match = MATCH_PHYSDEV_IN;
-    virBufferAsprintf(buf,
-                      "$IPT -D " VIRT_IN_POST_CHAIN
-                      " %s %s -j ACCEPT" CMD_SEPARATOR,
-                      match, ifname);
+    virFirewallAddRuleFull(fw, layer,
+                           true, NULL, NULL,
+                           "-D", VIRT_IN_POST_CHAIN,
+                           MATCH_PHYSDEV_IN_FW,
+                           ifname, "-j", "ACCEPT", NULL);
 }
 
 static void
@@ -816,6 +873,57 @@ _iptablesUnlinkRootChain(virBufferPtr buf,
 }
 
 
+static void
+_iptablesUnlinkRootChainFW(virFirewallPtr fw,
+                           virFirewallLayer layer,
+                           const char *basechain,
+                           char prefix,
+                           bool incoming, const char *ifname,
+                           int isTempChain)
+{
+    char chain[MAX_CHAINNAME_LENGTH];
+    char chainPrefix[2] = {
+        prefix,
+    };
+    if (isTempChain)
+        chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN_TEMP
+                                  : CHAINPREFIX_HOST_OUT_TEMP;
+    else
+        chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN
+                                  : CHAINPREFIX_HOST_OUT;
+
+    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+    if (incoming)
+        virFirewallAddRuleFull(fw, layer,
+                               true, NULL, NULL,
+                               "-D", basechain,
+                               MATCH_PHYSDEV_IN_FW, ifname,
+                               "-g", chain,
+                               NULL);
+    else
+        virFirewallAddRuleFull(fw, layer,
+                               true, NULL, NULL,
+                               "-D", basechain,
+                               MATCH_PHYSDEV_OUT_FW, ifname,
+                               "-g", chain,
+                               NULL);
+
+    /*
+     * Previous versions of libvirt may have created a rule
+     * with the --physdev-is-bridged missing. Remove this one
+     * as well.
+     */
+    if (!incoming)
+        virFirewallAddRuleFull(fw, layer,
+                               true, NULL, NULL,
+                               "-D", basechain,
+                               MATCH_PHYSDEV_OUT_OLD_FW, ifname,
+                               "-g", chain,
+                               NULL);
+}
+
+
 static void
 iptablesUnlinkRootChain(virBufferPtr buf,
                         const char *basechain,
@@ -826,6 +934,17 @@ iptablesUnlinkRootChain(virBufferPtr buf,
                              basechain, prefix, incoming, ifname, false);
 }
 
+static void
+iptablesUnlinkRootChainFW(virFirewallPtr fw,
+                          virFirewallLayer layer,
+                          const char *basechain,
+                          char prefix,
+                          bool incoming, const char *ifname)
+{
+    _iptablesUnlinkRootChainFW(fw, layer,
+                               basechain, prefix, incoming, ifname, false);
+}
+
 
 static void
 iptablesUnlinkTmpRootChain(virBufferPtr buf,
@@ -848,6 +967,17 @@ iptablesUnlinkRootChains(virBufferPtr buf,
 }
 
 
+static void
+iptablesUnlinkRootChainsFW(virFirewallPtr fw,
+                           virFirewallLayer layer,
+                           const char *ifname)
+{
+    iptablesUnlinkRootChainFW(fw, layer, VIRT_OUT_CHAIN, 'F', false, ifname);
+    iptablesUnlinkRootChainFW(fw, layer, VIRT_IN_CHAIN,  'F', true, ifname);
+    iptablesUnlinkRootChainFW(fw, layer, HOST_IN_CHAIN,  'H', true, ifname);
+}
+
+
 static void
 iptablesUnlinkTmpRootChains(virBufferPtr buf,
                             const char *ifname)
@@ -2801,6 +2931,31 @@ _ebtablesRemoveRootChain(virBufferPtr buf,
 }
 
 
+static void
+_ebtablesRemoveRootChainFW(virFirewallPtr fw,
+                           bool incoming, const char *ifname,
+                           int isTempChain)
+{
+    char chain[MAX_CHAINNAME_LENGTH];
+    char chainPrefix;
+    if (isTempChain)
+        chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
+                               : CHAINPREFIX_HOST_OUT_TEMP;
+    else
+        chainPrefix = incoming ? CHAINPREFIX_HOST_IN
+                               : CHAINPREFIX_HOST_OUT;
+
+    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+    virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                           true, NULL, NULL,
+                           "-t", "nat", "-F", chain, NULL);
+    virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                           true, NULL, NULL,
+                           "-t", "nat", "-X", chain, NULL);
+}
+
+
 static void
 ebtablesRemoveRootChain(virBufferPtr buf,
                         bool incoming, const char *ifname)
@@ -2809,6 +2964,14 @@ ebtablesRemoveRootChain(virBufferPtr buf,
 }
 
 
+static void
+ebtablesRemoveRootChainFW(virFirewallPtr fw,
+                          bool incoming, const char *ifname)
+{
+    _ebtablesRemoveRootChainFW(fw, incoming, ifname, false);
+}
+
+
 static void
 ebtablesRemoveTmpRootChain(virBufferPtr buf,
                            bool incoming, const char *ifname)
@@ -2844,6 +3007,33 @@ _ebtablesUnlinkRootChain(virBufferPtr buf,
 }
 
 
+static void
+_ebtablesUnlinkRootChainFW(virFirewallPtr fw,
+                           bool incoming, const char *ifname,
+                           int isTempChain)
+{
+    char chain[MAX_CHAINNAME_LENGTH];
+    char chainPrefix;
+
+    if (isTempChain) {
+        chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
+                               : CHAINPREFIX_HOST_OUT_TEMP;
+    } else {
+        chainPrefix = incoming ? CHAINPREFIX_HOST_IN
+                               : CHAINPREFIX_HOST_OUT;
+    }
+
+    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+    virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                           true, NULL, NULL,
+                           "-t", "nat", "-D",
+                           incoming ? EBTABLES_CHAIN_INCOMING : EBTABLES_CHAIN_OUTGOING,
+                           incoming ? "-i" : "-o",
+                           ifname, "-j", chain, NULL);
+}
+
+
 static void
 ebtablesUnlinkRootChain(virBufferPtr buf,
                         bool incoming, const char *ifname)
@@ -2852,6 +3042,14 @@ ebtablesUnlinkRootChain(virBufferPtr buf,
 }
 
 
+static void
+ebtablesUnlinkRootChainFW(virFirewallPtr fw,
+                          bool incoming, const char *ifname)
+{
+    _ebtablesUnlinkRootChainFW(fw, incoming, ifname, false);
+}
+
+
 static void
 ebtablesUnlinkTmpRootChain(virBufferPtr buf,
                            bool incoming, const char *ifname)
@@ -2972,6 +3170,60 @@ _ebtablesRemoveSubChains(virBufferPtr buf,
     virBufferAddLit(buf, "rm_chains $chains\n");
 }
 
+
+static int
+ebtablesRemoveSubChainsQuery(virFirewallPtr fw,
+                             const char *const *lines,
+                             void *opaque)
+{
+    size_t i, j;
+    const char *chainprefixes = opaque;
+
+    for (i = 0; lines[i] != NULL; i++) {
+        VIR_DEBUG("Considering '%s'", lines[i]);
+        char *tmp = strstr(lines[i], "-j ");
+        if (!tmp)
+            continue;
+        tmp = tmp + 3;
+        for (j = 0; chainprefixes[j]; j++) {
+            if (tmp[0] == chainprefixes[j] &&
+                tmp[1] == '-') {
+                VIR_DEBUG("Processing chain '%s'", tmp);
+                virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                                       false, ebtablesRemoveSubChainsQuery,
+                                       (void *)chainprefixes,
+                                        "-t", "nat", "-L", tmp, NULL);
+                virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                                       true, NULL, NULL,
+                                       "-t", "nat", "-F", tmp, NULL);
+                virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                                       true, NULL, NULL,
+                                       "-t", "nat", "-X", tmp, NULL);
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+static void
+_ebtablesRemoveSubChainsFW(virFirewallPtr fw,
+                           const char *ifname,
+                           const char *chainprefixes)
+{
+    char rootchain[MAX_CHAINNAME_LENGTH];
+    size_t i;
+
+    for (i = 0; chainprefixes[i] != 0; i++) {
+        PRINT_ROOT_CHAIN(rootchain, chainprefixes[i], ifname);
+        virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
+                               false, ebtablesRemoveSubChainsQuery,
+                               (void *)chainprefixes,
+                               "-t", "nat", "-L", rootchain, NULL);
+    }
+}
+
 static void
 ebtablesRemoveSubChains(virBufferPtr buf,
                         const char *ifname)
@@ -2985,6 +3237,13 @@ ebtablesRemoveSubChains(virBufferPtr buf,
     _ebtablesRemoveSubChains(buf, ifname, chains);
 }
 
+static void
+ebtablesRemoveSubChainsFW(virFirewallPtr fw,
+                          const char *ifname)
+{
+    _ebtablesRemoveSubChainsFW(fw, ifname, chainprefixes_host);
+}
+
 static void
 ebtablesRemoveTmpSubChains(virBufferPtr buf,
                            const char *ifname)
@@ -4052,43 +4311,37 @@ ebiptablesTearOldRules(const char *ifname)
  * Unconditionally remove all possible user defined tables and rules
  * that were created for the given interface (ifname).
  *
- * Always returns 0.
+ * Returns 0 on success, -1 on OOM
  */
 static int
 ebiptablesAllTeardown(const char *ifname)
 {
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    if (iptables_cmd_path) {
-        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
-
-        iptablesUnlinkRootChains(&buf, ifname);
-        iptablesClearVirtInPost(&buf, ifname);
-        iptablesRemoveRootChains(&buf, ifname);
-    }
+    virFirewallPtr fw = virFirewallNew();
+    int ret = -1;
 
-    if (ip6tables_cmd_path) {
-        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
+    virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
 
-        iptablesUnlinkRootChains(&buf, ifname);
-        iptablesClearVirtInPost(&buf, ifname);
-        iptablesRemoveRootChains(&buf, ifname);
-    }
+    iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
+    iptablesClearVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
+    iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
 
-    if (ebtables_cmd_path) {
-        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
+    iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
+    iptablesClearVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
+    iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
 
-        ebtablesUnlinkRootChain(&buf, true, ifname);
-        ebtablesUnlinkRootChain(&buf, false, ifname);
+    ebtablesUnlinkRootChainFW(fw, true, ifname);
+    ebtablesUnlinkRootChainFW(fw, false, ifname);
 
-        ebtablesRemoveSubChains(&buf, ifname);
+    ebtablesRemoveSubChainsFW(fw, ifname);
 
-        ebtablesRemoveRootChain(&buf, true, ifname);
-        ebtablesRemoveRootChain(&buf, false, ifname);
-    }
-    ebiptablesExecCLI(&buf, true, NULL);
+    ebtablesRemoveRootChainFW(fw, true, ifname);
+    ebtablesRemoveRootChainFW(fw, false, ifname);
 
-    return 0;
+    virMutexLock(&execCLIMutex);
+    ret = virFirewallApply(fw);
+    virMutexUnlock(&execCLIMutex);
+    virFirewallFree(fw);
+    return ret;
 }
 
 
index bda3632742ffde2714f9934c3ae94f1216b8340d..3917b9d52d0473d1782e2ba46d650358832e5afb 100644 (file)
@@ -272,6 +272,10 @@ endif WITH_STORAGE_SHEEPDOG
 
 test_programs += nwfilterxml2xmltest
 
+if WITH_NWFILTER
+test_programs += nwfilterebiptablestest
+endif WITH_NWFILTER
+
 if WITH_STORAGE
 test_programs += storagevolxml2argvtest
 endif WITH_STORAGE
@@ -696,6 +700,13 @@ nwfilterxml2xmltest_SOURCES = \
        testutils.c testutils.h
 nwfilterxml2xmltest_LDADD = $(LDADDS)
 
+if WITH_NWFILTER
+nwfilterebiptablestest_SOURCES = \
+       nwfilterebiptablestest.c \
+       testutils.c testutils.h
+nwfilterebiptablestest_LDADD = ../src/libvirt_driver_nwfilter_impl.la $(LDADDS)
+endif WITH_NWFILTER
+
 secretxml2xmltest_SOURCES = \
        secretxml2xmltest.c \
        testutils.c testutils.h
diff --git a/tests/nwfilterebiptablestest.c b/tests/nwfilterebiptablestest.c
new file mode 100644 (file)
index 0000000..da17d6a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * nwfilterebiptablestest.c: Test {eb,ip,ip6}tables rule generation
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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/>.
+ *
+ */
+
+#include <config.h>
+
+#include "testutils.h"
+#include "nwfilter/nwfilter_ebiptables_driver.h"
+#include "virbuffer.h"
+
+#define __VIR_FIREWALL_PRIV_H_ALLOW__
+#include "virfirewallpriv.h"
+
+#define __VIR_COMMAND_PRIV_H_ALLOW__
+#include "vircommandpriv.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+static int
+testNWFilterEBIPTablesAllTeardown(const void *opaque ATTRIBUTE_UNUSED)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    const char *expected =
+        "iptables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FO-vnet0\n"
+        "iptables -D libvirt-out -m physdev --physdev-out vnet0 -g FO-vnet0\n"
+        "iptables -D libvirt-in -m physdev --physdev-in vnet0 -g FI-vnet0\n"
+        "iptables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HI-vnet0\n"
+        "iptables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n"
+        "iptables -F FO-vnet0\n"
+        "iptables -X FO-vnet0\n"
+        "iptables -F FI-vnet0\n"
+        "iptables -X FI-vnet0\n"
+        "iptables -F HI-vnet0\n"
+        "iptables -X HI-vnet0\n"
+        "ip6tables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FO-vnet0\n"
+        "ip6tables -D libvirt-out -m physdev --physdev-out vnet0 -g FO-vnet0\n"
+        "ip6tables -D libvirt-in -m physdev --physdev-in vnet0 -g FI-vnet0\n"
+        "ip6tables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HI-vnet0\n"
+        "ip6tables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n"
+        "ip6tables -F FO-vnet0\n"
+        "ip6tables -X FO-vnet0\n"
+        "ip6tables -F FI-vnet0\n"
+        "ip6tables -X FI-vnet0\n"
+        "ip6tables -F HI-vnet0\n"
+        "ip6tables -X HI-vnet0\n"
+        "ebtables -t nat -D PREROUTING -i vnet0 -j libvirt-I-vnet0\n"
+        "ebtables -t nat -D POSTROUTING -o vnet0 -j libvirt-O-vnet0\n"
+        "ebtables -t nat -L libvirt-I-vnet0\n"
+        "ebtables -t nat -L libvirt-O-vnet0\n"
+        "ebtables -t nat -F libvirt-I-vnet0\n"
+        "ebtables -t nat -X libvirt-I-vnet0\n"
+        "ebtables -t nat -F libvirt-O-vnet0\n"
+        "ebtables -t nat -X libvirt-O-vnet0\n";
+    char *actual = NULL;
+    int ret = -1;
+
+    virCommandSetDryRun(&buf, NULL, NULL);
+
+    if (ebiptables_driver.allTeardown("vnet0") < 0)
+        goto cleanup;
+
+    if (virBufferError(&buf))
+        goto cleanup;
+
+    actual = virBufferContentAndReset(&buf);
+    virtTestClearCommandPath(actual);
+
+    if (STRNEQ_NULLABLE(actual, expected)) {
+        virtTestDifference(stderr, actual, expected);
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    virCommandSetDryRun(NULL, NULL, NULL);
+    virBufferFreeAndReset(&buf);
+    VIR_FREE(actual);
+    return ret;
+}
+
+
+static int
+mymain(void)
+{
+    int ret = 0;
+
+    if (virFirewallSetBackend(VIR_FIREWALL_BACKEND_DIRECT) < 0) {
+        ret = -1;
+        goto cleanup;
+    }
+
+    if (virtTestRun("ebiptablesAllTeardown",
+                    testNWFilterEBIPTablesAllTeardown,
+                    NULL) < 0)
+        ret = -1;
+
+ cleanup:
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)