提交 8d559864 编写于 作者: D Daniel P. Berrange

Convert nwfilter ebiptablesAllTeardown to virFirewall

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: NDaniel P. Berrange <berrange@redhat.com>
上级 3bf346a1
......@@ -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
......
......@@ -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;
}
......
......@@ -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
......
/*
* 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)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册