summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac12
-rw-r--r--daemon/Makefile.am4
-rw-r--r--daemon/libvirtd.c7
-rw-r--r--po/POTFILES.in3
-rwxr-xr-xpython/generator.py2
-rw-r--r--src/Makefile.am21
-rw-r--r--src/conf/nwfilter_conf.c37
-rw-r--r--src/libvirt_private.syms36
-rw-r--r--src/libvirt_public.syms1
-rw-r--r--src/nwfilter/nwfilter_driver.c416
-rw-r--r--src/nwfilter/nwfilter_driver.h36
-rw-r--r--src/nwfilter/nwfilter_ebiptables_driver.c1414
-rw-r--r--src/nwfilter/nwfilter_ebiptables_driver.h41
-rw-r--r--src/nwfilter/nwfilter_gentech_driver.c683
-rw-r--r--src/nwfilter/nwfilter_gentech_driver.h54
15 files changed, 2765 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index 52b16eeb4d..2148ae039a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -294,6 +294,9 @@ if test x"$with_rhel5_api" = x"yes"; then
AC_DEFINE([WITH_RHEL5_API], [1], [whether building for the RHEL-5 API])
fi
+AC_PATH_PROG([BASH_PATH], [bash], /bin/bash, [/bin:$PATH])
+AC_DEFINE_UNQUOTED([BASH_PATH], "$BASH_PATH", [path to bash binary])
+
AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
@@ -1268,6 +1271,15 @@ if test "$with_secrets" = "yes" ; then
fi
AM_CONDITIONAL([WITH_SECRETS], [test "$with_secrets" = "yes"])
+with_nwfilter=yes
+if test "$with_libvirtd" = "no"; then
+ with_nwfilter=no
+fi
+if test "$with_nwfilter" = "yes" ; then
+ AC_DEFINE([WITH_NWFILTER], 1, [whether local network filter management driver is available])
+fi
+AM_CONDITIONAL([WITH_NWFILTER], [test "$with_nwfilter" = "yes"])
+
AC_ARG_WITH([storage-fs],
AC_HELP_STRING([--with-storage-fs], [with FileSystem backend for the storage driver @<:@default=check@:>@]),[],[with_storage_fs=check])
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index a071609aa3..e117b97a38 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -116,6 +116,10 @@ endif
if WITH_SECRETS
libvirtd_LDADD += ../src/libvirt_driver_secret.la
endif
+
+if WITH_NWFILTER
+ libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la
+endif
endif
libvirtd_LDADD += ../src/libvirt.la
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 0d89c534c6..bd45016bff 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -96,6 +96,9 @@
# ifdef WITH_SECRETS
# include "secret/secret_driver.h"
# endif
+# ifdef WITH_NWFILTER
+# include "nwfilter/nwfilter_driver.h"
+# endif
#endif
@@ -876,6 +879,7 @@ static struct qemud_server *qemudInitialize(void) {
virDriverLoadModule("lxc");
virDriverLoadModule("uml");
virDriverLoadModule("one");
+ virDriverLoadModule("nwfilter");
#else
# ifdef WITH_NETWORK
networkRegister();
@@ -892,6 +896,9 @@ static struct qemud_server *qemudInitialize(void) {
# ifdef WITH_SECRETS
secretRegister();
# endif
+# ifdef WITH_NWFILTER
+ nwfilterRegister();
+# endif
# ifdef WITH_QEMU
qemuRegister();
# endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e14360efa3..d24cc1b0ff 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -28,6 +28,9 @@ src/node_device/node_device_driver.c
src/node_device/node_device_linux_sysfs.c
src/node_device/node_device_udev.c
src/nodeinfo.c
+src/nwfilter/nwfilter_driver.c
+src/nwfilter/nwfilter_ebiptables_driver.c
+src/nwfilter/nwfilter_gentech_driver.c
src/opennebula/one_conf.c
src/opennebula/one_driver.c
src/openvz/openvz_conf.c
diff --git a/python/generator.py b/python/generator.py
index acc8c90cf7..a24e122165 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -175,6 +175,7 @@ skipped_types = {
'virConnectDomainEventIOErrorCallback': "No function types in python",
'virConnectDomainEventGraphicsCallback': "No function types in python",
'virEventAddHandleFunc': "No function types in python",
+ 'virNWFilterPtr': "No function types in python",
}
#######################################################################
@@ -273,6 +274,7 @@ skip_impl = (
'virConnectListStorageVols',
'virConnectListDefinedStorageVols',
'virConnectListDefinedInterfaces',
+ 'virConnectListNWFilters',
'virConnGetLastError',
'virGetLastError',
'virDomainGetInfo',
diff --git a/src/Makefile.am b/src/Makefile.am
index b873d82d87..2409a57354 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -284,6 +284,11 @@ STORAGE_DRIVER_DISK_SOURCES = \
STORAGE_HELPER_DISK_SOURCES = \
storage/parthelper.c
+# Network filters
+NWFILTER_DRIVER_SOURCES = \
+ nwfilter/nwfilter_driver.h nwfilter/nwfilter_driver.c \
+ nwfilter/nwfilter_gentech_driver.c \
+ nwfilter/nwfilter_ebiptables_driver.c
# Security framework and drivers for various models
SECURITY_DRIVER_SOURCES = \
@@ -727,6 +732,22 @@ endif
endif
+if WITH_NWFILTER
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_nwfilter.la
+else
+libvirt_la_LIBADD += libvirt_driver_nwfilter.la
+noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
+endif
+libvirt_driver_nwfilter_la_CFLAGS = \
+ -I@top_srcdir@/src/conf
+if WITH_DRIVER_MODULES
+libvirt_driver_nwfilter_la_LDFLAGS = -module -avoid-version ../gnulib/lib/libgnu.la
+endif
+libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
+endif
+
+
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
noinst_LTLIBRARIES += libvirt_driver_security.la
libvirt_la_LIBADD += libvirt_driver_security.la
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index e5d285dc13..a75522c240 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -39,6 +39,7 @@
#include "nwfilter_params.h"
#include "nwfilter_conf.h"
#include "domain_conf.h"
+#include "nwfilter/nwfilter_gentech_driver.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
@@ -1605,10 +1606,42 @@ struct cbStruct {
};
static void
-virNWFilterDomainFWUpdateCB(void *payload ATTRIBUTE_UNUSED,
+virNWFilterDomainFWUpdateCB(void *payload,
const char *name ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
+ void *data)
{
+ virDomainObjPtr obj = payload;
+ virDomainDefPtr vm = obj->def;
+ struct cbStruct *cb = data;
+ int i;
+
+ virDomainObjLock(obj);
+
+ if (virDomainObjIsActive(obj)) {
+ for (i = 0; i < vm->nnets; i++) {
+ virDomainNetDefPtr net = vm->nets[i];
+ if ((net->filter) && (net->ifname)) {
+ switch (cb->step) {
+ case STEP_APPLY_NEW:
+ cb->err = virNWFilterUpdateInstantiateFilter(cb->conn,
+ net);
+ break;
+
+ case STEP_TEAR_NEW:
+ cb->err = virNWFilterRollbackUpdateFilter(cb->conn, net);
+ break;
+
+ case STEP_TEAR_OLD:
+ cb->err = virNWFilterTearOldFilter(cb->conn, net);
+ break;
+ }
+ if (cb->err)
+ break;
+ }
+ }
+ }
+
+ virDomainObjUnlock(obj);
}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4fe5427045..1bcab9fad1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -449,6 +449,42 @@ virNodeDeviceGetWWNs;
virNodeDeviceGetParentHost;
+# nwfilter_conf.h
+virNWFilterPoolLoadAllConfigs;
+virNWFilterPoolObjAssignDef;
+virNWFilterPoolObjSaveDef;
+virNWFilterPoolObjFindByName;
+virNWFilterPoolObjFindByUUID;
+virNWFilterPoolObjLock;
+virNWFilterPoolObjUnlock;
+virNWFilterPoolObjRemove;
+virNWFilterDefFree;
+virNWFilterDefParseString;
+virNWFilterPoolObjDeleteDef;
+virNWFilterPoolObjListFree;
+virNWFilterDefFormat;
+virNWFilterChainSuffixTypeToString;
+virNWFilterRuleActionTypeToString;
+virNWFilterJumpTargetTypeToString;
+virNWFilterRegisterCallbackDriver;
+virNWFilterTestUnassignDef;
+virNWFilterConfLayerInit;
+virNWFilterConfLayerShutdown;
+
+
+#nwfilter_params.h
+virNWFilterHashTableCreate;
+virNWFilterHashTableFree;
+virNWFilterHashTablePut;
+virNWFilterHashTablePutAll;
+virNWFilterHashTableRemoveEntry;
+
+
+# nwfilter_gentech_driver.h
+virNWFilterInstantiateFilter;
+virNWFilterTeardownFilter;
+
+
# pci.h
pciGetDevice;
pciFreeDevice;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index ad7577cd30..2f812a1585 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -380,4 +380,5 @@ LIBVIRT_0.7.8 {
virNWFilterUndefine;
} LIBVIRT_0.7.7;
+
# .... define new API here using predicted next version number ....
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
new file mode 100644
index 0000000000..4bb30ce136
--- /dev/null
+++ b/src/nwfilter/nwfilter_driver.c
@@ -0,0 +1,416 @@
+/*
+ * nwfilter_driver.c: core driver for network filter APIs
+ * (based on storage_driver.c)
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ * Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include "internal.h"
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "memory.h"
+#include "domain_conf.h"
+#include "nwfilter_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#define nwfilterLog(msg...) fprintf(stderr, msg)
+
+
+static virNWFilterDriverStatePtr driverState;
+
+static int nwfilterDriverShutdown(void);
+
+static void nwfilterDriverLock(virNWFilterDriverStatePtr driver)
+{
+ virMutexLock(&driver->lock);
+}
+static void nwfilterDriverUnlock(virNWFilterDriverStatePtr driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+
+/**
+ * virNWFilterStartup:
+ *
+ * Initialization function for the QEmu daemon
+ */
+static int
+nwfilterDriverStartup(int privileged) {
+ char *base = NULL;
+
+ if (virNWFilterConfLayerInit() < 0)
+ return -1;
+
+ if (VIR_ALLOC(driverState) < 0)
+ goto alloc_err_exit;
+
+ if (virMutexInit(&driverState->lock) < 0)
+ goto alloc_err_exit;
+
+ nwfilterDriverLock(driverState);
+
+ if (privileged) {
+ if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
+ goto out_of_memory;
+ } else {
+ uid_t uid = geteuid();
+ char *userdir = virGetUserDirectory(uid);
+
+ if (!userdir)
+ goto error;
+
+ if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
+ nwfilterLog("out of memory in virAsprintf");
+ VIR_FREE(userdir);
+ goto out_of_memory;
+ }
+ VIR_FREE(userdir);
+ }
+
+ if (virAsprintf(&driverState->configDir,
+ "%s/nwfilter", base) == -1)
+ goto out_of_memory;
+
+ VIR_FREE(base);
+
+ if (virNWFilterPoolLoadAllConfigs(NULL,
+ &driverState->pools,
+ driverState->configDir) < 0)
+ goto error;
+
+ nwfilterDriverUnlock(driverState);
+
+ return 0;
+
+out_of_memory:
+ nwfilterLog("virNWFilterStartup: out of memory");
+
+error:
+ VIR_FREE(base);
+ nwfilterDriverUnlock(driverState);
+ nwfilterDriverShutdown();
+
+alloc_err_exit:
+ virNWFilterConfLayerShutdown();
+
+ return -1;
+}
+
+/**
+ * virNWFilterReload:
+ *
+ * Function to restart the nwfilter driver, it will recheck the configuration
+ * files and update its state
+ */
+static int
+nwfilterDriverReload(void) {
+ if (!driverState) {
+ return -1;
+ }
+
+ nwfilterDriverLock(driverState);
+ virNWFilterPoolLoadAllConfigs(NULL,
+ &driverState->pools,
+ driverState->configDir);
+ nwfilterDriverUnlock(driverState);
+
+ return 0;
+}
+
+/**
+ * virNWFilterActive:
+ *
+ * Checks if the nwfilter driver is active, i.e. has an active pool
+ *
+ * Returns 1 if active, 0 otherwise
+ */
+static int
+nwfilterDriverActive(void) {
+ if (!driverState->pools.count)
+ return 0;
+ return 1;
+}
+
+/**
+ * virNWFilterShutdown:
+ *
+ * Shutdown the nwfilter driver, it will stop all active nwfilter pools
+ */
+static int
+nwfilterDriverShutdown(void) {
+ if (!driverState)
+ return -1;
+
+ nwfilterDriverLock(driverState);
+
+ /* free inactive pools */
+ virNWFilterPoolObjListFree(&driverState->pools);
+
+ VIR_FREE(driverState->configDir);
+ nwfilterDriverUnlock(driverState);
+ virMutexDestroy(&driverState->lock);
+ VIR_FREE(driverState);
+
+ return 0;
+}
+
+
+static virNWFilterPtr
+nwfilterLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, uuid);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ "%s", _("no pool with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virNWFilterPtr
+nwfilterLookupByName(virConnectPtr conn,
+ const char *name) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByName(&driver->pools, name);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("no pool with matching name '%s'"), name);
+ goto cleanup;
+ }
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virDrvOpenStatus
+nwfilterOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED) {
+ if (!driverState)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->nwfilterPrivateData = driverState;
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+
+static int
+nwfilterClose(virConnectPtr conn) {
+ conn->nwfilterPrivateData = NULL;
+ return 0;
+}
+
+
+static int
+nwfilterNumNWFilters(virConnectPtr conn) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ return driver->pools.count;
+}
+
+
+static int
+nwfilterListNWFilters(virConnectPtr conn,
+ char **const names,
+ int nnames) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ int got = 0, i;
+
+ nwfilterDriverLock(driver);
+ for (i = 0 ; i < driver->pools.count && got < nnames ; i++) {
+ virNWFilterPoolObjLock(driver->pools.objs[i]);
+ if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) {
+ virNWFilterPoolObjUnlock(driver->pools.objs[i]);
+ virReportOOMError();
+ goto cleanup;
+ }
+ got++;
+ virNWFilterPoolObjUnlock(driver->pools.objs[i]);
+ }
+ nwfilterDriverUnlock(driver);
+ return got;
+
+ cleanup:
+ nwfilterDriverUnlock(driver);
+ for (i = 0 ; i < got ; i++)
+ VIR_FREE(names[i]);
+ memset(names, 0, nnames * sizeof(*names));
+ return -1;
+}
+
+
+static virNWFilterPtr
+nwfilterDefine(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterDefPtr def;
+ virNWFilterPoolObjPtr pool = NULL;
+ virNWFilterPtr ret = NULL;
+
+ nwfilterDriverLock(driver);
+ if (!(def = virNWFilterDefParseString(conn, xml)))
+ goto cleanup;
+
+ if (!(pool = virNWFilterPoolObjAssignDef(conn, &driver->pools, def)))
+ goto cleanup;
+
+ if (virNWFilterPoolObjSaveDef(conn, driver, pool, def) < 0) {
+ virNWFilterPoolObjRemove(&driver->pools, pool);
+ def = NULL;
+ goto cleanup;
+ }
+ def = NULL;
+
+ ret = virGetNWFilter(conn, pool->def->name, pool->def->uuid);
+
+cleanup:
+ virNWFilterDefFree(def);
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ nwfilterDriverUnlock(driver);
+ return ret;
+}
+
+
+static int
+nwfilterUndefine(virNWFilterPtr obj) {
+ virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ int ret = -1;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
+ if (!pool) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("no nwfilter pool with matching uuid"));
+ goto cleanup;
+ }
+
+ if (virNWFilterTestUnassignDef(obj->conn, pool)) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s",
+ _("nwfilter is in use"));
+ goto cleanup;
+ }
+
+ if (virNWFilterPoolObjDeleteDef(obj->conn, pool) < 0)
+ goto cleanup;
+
+ VIR_FREE(pool->configFile);
+
+ virNWFilterPoolObjRemove(&driver->pools, pool);
+ pool = NULL;
+ ret = 0;
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ nwfilterDriverUnlock(driver);
+ return ret;
+}
+
+
+static char *
+nwfilterDumpXML(virNWFilterPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virNWFilterDriverStatePtr driver = obj->conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr pool;
+ char *ret = NULL;
+
+ nwfilterDriverLock(driver);
+ pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
+ nwfilterDriverUnlock(driver);
+
+ if (!pool) {
+ virNWFilterReportError(obj->conn, VIR_ERR_INVALID_NWFILTER,
+ "%s", _("no nwfilter pool with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virNWFilterDefFormat(obj->conn, pool->def);
+
+cleanup:
+ if (pool)
+ virNWFilterPoolObjUnlock(pool);
+ return ret;
+}
+
+
+static virNWFilterDriver nwfilterDriver = {
+ .name = "nwfilter",
+ .open = nwfilterOpen,
+ .close = nwfilterClose,
+ .numOfNWFilters = nwfilterNumNWFilters,
+ .listNWFilters = nwfilterListNWFilters,
+ .nwfilterLookupByName = nwfilterLookupByName,
+ .nwfilterLookupByUUID = nwfilterLookupByUUID,
+ .defineXML = nwfilterDefine,
+ .undefine = nwfilterUndefine,
+ .getXMLDesc = nwfilterDumpXML,
+};
+
+
+static virStateDriver stateDriver = {
+ .name = "NWFilter",
+ .initialize = nwfilterDriverStartup,
+ .cleanup = nwfilterDriverShutdown,
+ .reload = nwfilterDriverReload,
+ .active = nwfilterDriverActive,
+};
+
+int nwfilterRegister(void) {
+ virRegisterNWFilterDriver(&nwfilterDriver);
+ virRegisterStateDriver(&stateDriver);
+ return 0;
+}
diff --git a/src/nwfilter/nwfilter_driver.h b/src/nwfilter/nwfilter_driver.h
new file mode 100644
index 0000000000..b7d8668f45
--- /dev/null
+++ b/src/nwfilter/nwfilter_driver.h
@@ -0,0 +1,36 @@
+/*
+ * nwfilter_driver.h: core driver for nwfilter APIs
+ * (based on storage driver)
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ * Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#ifndef __VIR_NWFILTER_DRIVER_H__
+#define __VIR_NWFILTER_DRIVER_H__
+
+#include "nwfilter_params.h"
+#include "nwfilter_conf.h"
+
+int nwfilterRegister(void);
+
+#endif /* __VIR_NWFILTER_DRIVER_H__ */
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
new file mode 100644
index 0000000000..7af269caaf
--- /dev/null
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -0,0 +1,1414 @@
+/*
+ * nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include "internal.h"
+
+#include "buf.h"
+#include "memory.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "domain_conf.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+
+#define EBTABLES_DEFAULT_TABLE "nat"
+#define EBTABLES_CHAIN_INCOMING "PREROUTING"
+#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
+
+#define CHAINPREFIX_HOST_IN 'I'
+#define CHAINPREFIX_HOST_OUT 'O'
+#define CHAINPREFIX_HOST_IN_TEMP 'J'
+#define CHAINPREFIX_HOST_OUT_TEMP 'P'
+
+
+#define CMD_SEPARATOR "\n"
+#define CMD_DEF_PRE "cmd=\""
+#define CMD_DEF_POST "\""
+#define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST
+#define CMD_EXEC "res=`${cmd}`" CMD_SEPARATOR
+#define CMD_STOPONERR(X) \
+ X ? "if [ $? -ne 0 ]; then" \
+ " echo \"Failure to execute command '${cmd}'.\";" \
+ " exit 1;" \
+ "fi" CMD_SEPARATOR \
+ : ""
+
+
+#define EBTABLES_CMD EBTABLES_PATH
+#define BASH_CMD BASH_PATH
+
+#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
+ snprintf(buf, sizeof(buf), "libvirt-%c-%s", prefix, ifname)
+#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
+ snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)
+
+
+static const char *supported_protocols[] = {
+ "ipv4",
+ "arp",
+ NULL,
+};
+
+
+static int
+printVar(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item,
+ int *done)
+{
+ *done = 0;
+
+ if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+ char *val = (char *)virHashLookup(vars->hashTable, item->var);
+ if (!val) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("cannot find value for '%s'"),
+ item->var);
+ return 1;
+ }
+
+ if (!virStrcpy(buf, val, bufsize)) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer to small to print MAC address "
+ "'%s' into"),
+ item->var);
+ return 1;
+ }
+
+ *done = 1;
+ }
+ return 0;
+}
+
+
+static int
+printDataType(virConnectPtr conn,
+ virNWFilterHashTablePtr vars,
+ char *buf, int bufsize,
+ nwItemDescPtr item)
+{
+ int done;
+ if (printVar(conn, vars, buf, bufsize, item, &done))
+ return 1;
+
+ if (done)
+ return 0;
+
+ switch (item->datatype) {
+ case DATATYPE_IPADDR:
+ if (snprintf(buf, bufsize, "%d.%d.%d.%d",
+ item->u.ipaddr.addr.ipv4Addr[0],
+ item->u.ipaddr.addr.ipv4Addr[1],
+ item->u.ipaddr.addr.ipv4Addr[2],
+ item->u.ipaddr.addr.ipv4Addr[3]) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for IP address"));
+ return 1;
+ }
+ break;
+
+ case DATATYPE_MACADDR:
+ if (bufsize < VIR_MAC_STRING_BUFLEN) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for MAC address"));
+ return 1;
+ }
+
+ virFormatMacAddr(item->u.macaddr.addr, buf);
+ break;
+
+ case DATATYPE_UINT16:
+ if (snprintf(buf, bufsize, "%d",
+ item->u.u16) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for uint16 type"));
+ return 1;
+ }
+ break;
+
+ case DATATYPE_IPMASK:
+ case DATATYPE_UINT8:
+ if (snprintf(buf, bufsize, "%d",
+ item->u.u8) >= bufsize) {
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Buffer too small for uint8 type"));
+ return 1;
+ }
+ break;
+
+ default:
+ virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+ _("Unhandled datatype %x"), item->datatype);
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+
+static void
+ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
+{
+ if (!inst)
+ return;
+
+ VIR_FREE(inst->commandTemplate);
+ VIR_FREE(inst);
+}
+
+
+static int
+ebiptablesAddRuleInst(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ char *commandTemplate,
+ enum virNWFilterChainSuffixType neededChain,
+ char chainprefix,
+ unsigned int priority)
+{
+ ebiptablesRuleInstPtr inst;
+
+ if (VIR_ALLOC(inst) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ inst->commandTemplate = commandTemplate;
+ inst->neededProtocolChain = neededChain;
+ inst->chainprefix = chainprefix;
+ inst->priority = priority;
+
+ return virNWFilterRuleInstAddData(conn, res, inst);
+}
+
+
+static int
+ebtablesHandleEthHdr(virConnectPtr conn,
+ virBufferPtr buf,
+ virNWFilterHashTablePtr vars,
+ ethHdrDataDefPtr ethHdr)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -s %s %s",
+ ENTRY_GET_NEG_SIGN(&ethHdr->dataSrcMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataSrcMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ " -d %s %s",
+ ENTRY_GET_NEG_SIGN(&ethHdr->dataDstMACAddr),
+ macaddr);
+
+ if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACMask)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &ethHdr->dataDstMACMask))
+ goto err_exit;
+
+ virBufferVSprintf(buf,
+ "/%s",
+ macaddr);
+ }
+ }
+
+ return 0;
+
+ err_exit:
+ virBufferFreeAndReset(buf);
+
+ return 1;
+}
+
+/*
+ * ebtablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @chainPrefix : The prefix to put in front of the name of the chain
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+ebtablesCreateRuleInstance(virConnectPtr conn,
+ char chainPrefix,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ char macaddr[VIR_MAC_STRING_BUFLEN],
+ ipaddr[INET_ADDRSTRLEN],
+ number[20];
+ char chain[MAX_CHAINNAME_LENGTH];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (nwfilter->chainsuffix == VIR_NWFILTER_CHAINSUFFIX_ROOT)
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+ else
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ virNWFilterChainSuffixTypeToString(nwfilter->chainsuffix));
+
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.ethHdrFilter.ethHdr))
+ goto err_exit;
+
+ if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ethHdrFilter.dataProtocolID))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " -p %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
+ number);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.arpHdrFilter.ethHdr))
+ goto err_exit;
+
+ virBufferAddLit(&buf, " -p arp");
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataHWType))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-htype %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataOpcode))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-opcode %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.arpHdrFilter.dataProtocolType))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ " --arp-ptype %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataARPSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-src %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.arpHdrFilter.dataARPDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-ip-dst %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr),
+ ipaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataARPSrcMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-src %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr),
+ macaddr);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
+ if (printDataType(conn,
+ vars,
+ macaddr, sizeof(macaddr),
+ &rule->p.arpHdrFilter.dataARPDstMACAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --arp-mac-dst %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr),
+ macaddr);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ if (ebtablesHandleEthHdr(conn,
+ &buf,
+ vars,
+ &rule->p.ipHdrFilter.ethHdr))
+ goto err_exit;
+
+ virBufferAddLit(&buf,
+ " -p ipv4");
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr)) {
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataSrcIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
+
+ if (printDataType(conn,
+ vars,
+ ipaddr, sizeof(ipaddr),
+ &rule->p.ipHdrFilter.ipHdr.dataDstIPAddr))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr),
+ ipaddr);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataDstIPMask))
+ goto err_exit;
+ virBufferVSprintf(&buf,
+ "/%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataProtocolID))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-protocol %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
+ number);
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataSrcPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-source-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataSrcPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
+
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataDstPortStart))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-destination-port %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
+ number);
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.portData.dataDstPortEnd))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ ":%s",
+ number);
+ }
+ }
+
+ if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDSCP)) {
+ if (printDataType(conn,
+ vars,
+ number, sizeof(number),
+ &rule->p.ipHdrFilter.ipHdr.dataDSCP))
+ goto err_exit;
+
+ virBufferVSprintf(&buf,
+ " --ip-tos %s %s",
+ ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP),
+ number);
+ }
+ break;
+
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+ virBufferVSprintf(&buf,
+ CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+ EBTABLES_DEFAULT_TABLE, chain);
+ break;
+ }
+
+ virBufferVSprintf(&buf,
+ " -j %s" CMD_DEF_POST CMD_SEPARATOR
+ CMD_EXEC,
+ virNWFilterJumpTargetTypeToString(rule->action));
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+
+ return ebiptablesAddRuleInst(conn,
+ res,
+ virBufferContentAndReset(&buf),
+ nwfilter->chainsuffix,
+ chainPrefix,
+ rule->priority);
+
+err_exit:
+ virBufferFreeAndReset(&buf);
+
+ return -1;
+}
+
+
+/*
+ * ebiptablesCreateRuleInstance:
+ * @conn : Pointer to a virConnect object
+ * @nwfilter : The filter
+ * @rule: The rule of the filter to convert
+ * @ifname : The name of the interface to apply the rule to
+ * @vars : A map containing the variables to resolve
+ * @res : The data structure to store the result(s) into
+ *
+ * Convert a single rule into its representation for later instantiation
+ *
+ * Returns 0 in case of success with the result stored in the data structure
+ * pointed to by res, != 0 otherwise with the error message stored in the
+ * virConnect object.
+ */
+static int
+ebiptablesCreateRuleInstance(virConnectPtr conn,
+ enum virDomainNetType nettype ATTRIBUTE_UNUSED,
+ virNWFilterDefPtr nwfilter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ virNWFilterRuleInstPtr res)
+{
+ int rc = 0;
+
+ switch (rule->prtclType) {
+ case VIR_NWFILTER_RULE_PROTOCOL_IP:
+ case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+ case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_IN_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ if (rc)
+ return rc;
+ }
+
+ if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
+ rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
+ rc = ebtablesCreateRuleInstance(conn,
+ CHAINPREFIX_HOST_OUT_TEMP,
+ nwfilter,
+ rule,
+ ifname,
+ vars,
+ res);
+ }
+ break;
+ }
+
+ return rc;
+}
+
+
+static int
+ebiptablesFreeRuleInstance(void *_inst)
+{
+ ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
+ return 0;
+}
+
+
+static int
+ebiptablesDisplayRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
+ void *_inst)
+{
+ ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
+ printf("Command Template: %s\nNeeded protocol: %s\n\n",
+ inst->commandTemplate,
+ virNWFilterChainSuffixTypeToString(inst->neededProtocolChain));
+ return 0;
+}
+
+
+/**
+ * ebiptablesWriteToTempFile:
+ * @conn: pointer to virConnect object
+ * @string : the string to write into the file
+ *
+ * Returns the tempory filename where the string was written into,
+ * NULL in case of error with the error reported.
+ *
+ * Write the string into a temporary file and return the name of
+ * the temporary file. The string is assumed to contain executable
+ * commands. A line '#!/bin/bash' will automatically be written
+ * as the first line in the file. The permissions of the file are
+ * set so that the file can be run as an executable script.
+ */
+static char *
+ebiptablesWriteToTempFile(virConnectPtr conn,
+ const char *string) {
+ char filename[] = "/tmp/virtdXXXXXX";
+ int len;
+ char *filnam;
+ const char header[] = "#!" BASH_CMD "\n";
+ size_t written;
+
+ int fd = mkstemp(filename);
+
+ if (fd < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot create temporary file"));
+ return NULL;
+ }
+
+ if (fchmod(fd, S_IXUSR| S_IRUSR | S_IWUSR) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot change permissions on temp. file"));
+ goto err_exit;
+ }
+
+ len = strlen(header);
+ written = safewrite(fd, header, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ len = strlen(string);
+ written = safewrite(fd, string, len);
+ if (written != len) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("cannot write string to file"));
+ goto err_exit;
+ }
+
+ filnam = strdup(filename);
+ if (!filnam) {
+ virReportOOMError();
+ goto err_exit;
+ }
+
+ close(fd);
+ return filnam;
+
+err_exit:
+ close(fd);
+ unlink(filename);
+ return NULL;
+}
+
+
+/**
+ * ebiptablesExecCLI:
+ * @conn : pointer to virConnect object
+ * @buf : pointer to virBuffer containing the string with the commands to
+ * execute.
+ * @status: Pointer to an integer for returning the status of the
+ * commands executed via the script the was run.
+ *
+ * Returns 0 in case of success, != 0 in case of an error. The returned
+ * value is NOT the result of running the commands inside the bash
+ * script.
+ *
+ * Execute a sequence of commands (held in the given buffer) as a bash
+ * script and return the status of the execution.
+ */
+static int
+ebiptablesExecCLI(virConnectPtr conn,
+ virBufferPtr buf,
+ int *status)
+{
+ char *cmds;
+ char *filename;
+ int rc;
+ const char *argv[] = {NULL, NULL};
+
+ if (virBufferError(buf)) {
+ virReportOOMError();
+ virBufferFreeAndReset(buf);
+ return 1;
+ }
+
+ *status = 0;
+
+ cmds = virBufferContentAndReset(buf);
+
+ VIR_DEBUG("%s", cmds);
+
+ if (!cmds)
+ return 0;
+
+ filename = ebiptablesWriteToTempFile(conn, cmds);
+ VIR_FREE(cmds);
+
+ if (!filename)
+ return 1;
+
+ argv[0] = filename;
+ rc = virRun(argv, status);
+
+ *status >>= 8;
+
+ VIR_DEBUG("rc = %d, status = %d\n",rc, *status);
+
+ unlink(filename);
+
+ VIR_FREE(filename);
+
+ return rc;
+}
+
+
+static int
+ebtablesCreateTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE, chain,
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+ebtablesLinkTmpRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int stopOnError)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char iodev = (incoming) ? 'i' : 'o';
+
+ PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -%c %s -j %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int 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);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE, chain,
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesRemoveTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesRemoveRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+_ebtablesUnlinkRootChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming, const char *ifname,
+ int isTempChain)
+{
+ char chain[MAX_CHAINNAME_LENGTH];
+ char iodev = (incoming) ? 'i' : 'o';
+ 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);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -%c %s -j %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ (incoming) ? EBTABLES_CHAIN_INCOMING
+ : EBTABLES_CHAIN_OUTGOING,
+ iodev, ifname, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesUnlinkRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 0);
+}
+
+
+static int
+ebtablesUnlinkTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming, const char *ifname)
+{
+ return _ebtablesUnlinkRootChain(conn, buf, incoming, ifname, 1);
+}
+
+
+static int
+ebtablesCreateTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int stopOnError)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+
+ PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ CMD_DEF(EBTABLES_CMD " -t %s -N %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s"
+ CMD_DEF(EBTABLES_CMD " -t %s -A %s -p %s -j %s") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ CMD_STOPONERR(stopOnError),
+
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ CMD_STOPONERR(stopOnError));
+
+ return 0;
+}
+
+
+static int
+_ebtablesRemoveSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol,
+ int isTempChain)
+{
+ char rootchain[MAX_CHAINNAME_LENGTH], 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(rootchain, chainPrefix, ifname);
+ PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -D %s -p %s -j %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -F %s" CMD_SEPARATOR
+ EBTABLES_CMD " -t %s -X %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ rootchain,
+ protocol, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain,
+
+ EBTABLES_DEFAULT_TABLE, chain);
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 0);
+}
+
+
+static int
+ebtablesRemoveSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveSubChain(conn, buf, 1, ifname, supported_protocols[i]);
+ ebtablesRemoveSubChain(conn, buf, 0, ifname, supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRemoveTmpSubChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ return _ebtablesRemoveSubChain(conn, buf,
+ incoming, ifname, protocol, 1);
+}
+
+
+static int
+ebtablesRemoveTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRemoveTmpSubChain(conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRemoveTmpSubChain(conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChain(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname,
+ const char *protocol)
+{
+ char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
+ char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
+ : CHAINPREFIX_HOST_OUT_TEMP;
+ char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
+ : CHAINPREFIX_HOST_OUT;
+
+ if (protocol) {
+ PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
+ PRINT_CHAIN( chain, chainPrefix, ifname, protocol);
+ } else {
+ PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
+ PRINT_ROOT_CHAIN( chain, chainPrefix, ifname);
+ }
+
+ virBufferVSprintf(buf,
+ EBTABLES_CMD " -t %s -E %s %s" CMD_SEPARATOR,
+ EBTABLES_DEFAULT_TABLE,
+ tmpchain,
+ chain);
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpSubChains(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *ifname)
+{
+ int i;
+ for (i = 0; supported_protocols[i]; i++) {
+ ebtablesRenameTmpSubChain (conn, buf, 1, ifname,
+ supported_protocols[i]);
+ ebtablesRenameTmpSubChain (conn, buf, 0, ifname,
+ supported_protocols[i]);
+ }
+
+ return 0;
+}
+
+
+static int
+ebtablesRenameTmpRootChain(virConnectPtr conn,
+ virBufferPtr buf,
+ int incoming,
+ const char *ifname)
+{
+ return ebtablesRenameTmpSubChain(conn, buf, incoming, ifname, NULL);
+}
+
+
+static void
+ebiptablesInstCommand(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ const char *templ, char cmd, int pos,
+ int stopOnError)
+{
+ char position[10] = { 0 };
+ if (pos >= 0)
+ snprintf(position, sizeof(position), "%d", pos);
+ virBufferVSprintf(buf, templ, cmd, position);
+ virBufferVSprintf(buf, CMD_SEPARATOR "%s",
+ CMD_STOPONERR(stopOnError));
+}
+
+
+static int
+ebiptablesRuleOrderSort(const void *a, const void *b)
+{
+ const ebiptablesRuleInstPtr *insta = a;
+ const ebiptablesRuleInstPtr *instb = b;
+ return ((*insta)->priority - (*instb)->priority);
+}
+
+
+static int
+ebiptablesApplyNewRules(virConnectPtr conn,
+ const char *ifname,
+ int nruleInstances,
+ void **_inst)
+{
+ int i;
+ int cli_status;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+ int chains_in = 0, chains_out = 0;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (inst)
+ qsort(inst, nruleInstances, sizeof(inst[0]),
+ ebiptablesRuleOrderSort);
+
+ for (i = 0; i < nruleInstances; i++) {
+ if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
+ chains_in |= (1 << inst[i]->neededProtocolChain);
+ else
+ chains_out |= (1 << inst[i]->neededProtocolChain);
+ }
+
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ if (chains_in != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesCreateTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "ipv4", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "ipv4", 1);
+
+ // keep arp as last
+ if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 1, ifname, "arp", 1);
+ if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
+ ebtablesCreateTmpSubChain(conn, &buf, 0, ifname, "arp", 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'A', -1, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_tmpebchains;
+
+ // FIXME: establishment of iptables user define table tree goes here
+
+ // END IPTABLES stuff
+
+ if (chains_in != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 1, ifname, 1);
+ if (chains_out != 0)
+ ebtablesLinkTmpRootChain(conn, &buf, 0, ifname, 1);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status) || cli_status != 0)
+ goto tear_down_ebsubchains_and_unlink;
+
+ return 0;
+
+tear_down_ebsubchains_and_unlink:
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+
+tear_down_tmpebchains:
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("Some rules could not be created."));
+
+ return 1;
+}
+
+
+static int
+ebiptablesTearNewRules(virConnectPtr conn,
+ const char *ifname)
+{
+ int cli_status;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ ebtablesUnlinkTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkTmpRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveTmpSubChains(conn, &buf, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+}
+
+
+static int
+ebiptablesTearOldRules(virConnectPtr conn,
+ const char *ifname)
+{
+ int cli_status;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRenameTmpSubChains(conn, &buf, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 1, ifname);
+ ebtablesRenameTmpRootChain(conn, &buf, 0, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+}
+
+
+/**
+ * ebiptablesRemoveRules:
+ * @conn : pointer to virConnect object
+ * @ifname : the name of the interface to which the rules apply
+ * @nRuleInstance : the number of given rules
+ * @_inst : array of rule instantiation data
+ *
+ * Remove all rules one after the other
+ *
+ * Return 0 on success, 1 if execution of one or more cleanup
+ * commands failed.
+ */
+static int
+ebiptablesRemoveRules(virConnectPtr conn,
+ const char *ifname ATTRIBUTE_UNUSED,
+ int nruleInstances,
+ void **_inst)
+{
+ int rc = 0;
+ int cli_status;
+ int i;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
+
+ for (i = 0; i < nruleInstances; i++)
+ ebiptablesInstCommand(conn, &buf,
+ inst[i]->commandTemplate,
+ 'D', -1,
+ 0);
+
+ if (ebiptablesExecCLI(conn, &buf, &cli_status))
+ goto err_exit;
+
+ if (cli_status) {
+ virNWFilterReportError(conn, VIR_ERR_BUILD_FIREWALL,
+ "%s",
+ _("error while executing CLI commands"));
+ rc = 1;
+ }
+
+err_exit:
+ return rc;
+}
+
+
+/**
+ * ebiptablesAllTeardown:
+ * @ifname : the name of the interface to which the rules apply
+ *
+ * Unconditionally remove all possible user defined tables and rules
+ * that were created for the given interface (ifname).
+ *
+ * Always returns 0.
+ */
+static int
+ebiptablesAllTeardown(const char *ifname)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int cli_status;
+ virConnectPtr conn = NULL;
+
+ ebtablesUnlinkRootChain(conn, &buf, 1, ifname);
+ ebtablesUnlinkRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveRootChain(conn, &buf, 1, ifname);
+ ebtablesRemoveRootChain(conn, &buf, 0, ifname);
+
+ ebtablesRemoveSubChains(conn, &buf, ifname);
+
+ ebiptablesExecCLI(conn, &buf, &cli_status);
+
+ return 0;
+}
+
+
+virNWFilterTechDriver ebiptables_driver = {
+ .name = EBIPTABLES_DRIVER_ID,
+
+ .createRuleInstance = ebiptablesCreateRuleInstance,
+ .applyNewRules = ebiptablesApplyNewRules,
+ .tearNewRules = ebiptablesTearNewRules,
+ .tearOldRules = ebiptablesTearOldRules,
+ .allTeardown = ebiptablesAllTeardown,
+ .removeRules = ebiptablesRemoveRules,
+ .freeRuleInstance = ebiptablesFreeRuleInstance,
+ .displayRuleInstance = ebiptablesDisplayRuleInstance,
+};
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.h b/src/nwfilter/nwfilter_ebiptables_driver.h
new file mode 100644
index 0000000000..1635b1af79
--- /dev/null
+++ b/src/nwfilter/nwfilter_ebiptables_driver.h
@@ -0,0 +1,41 @@
+/*
+ * nwfilter_ebiptables_driver.h: ebtables/iptables driver support
+ *
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+#ifndef VIR_NWFILTER_EBTABLES_DRIVER_H__
+#define VIR_NWFILTER_EBTABLES_DRIVER_H__
+
+#define MAX_CHAINNAME_LENGTH 32 /* see linux/netfilter_bridge/ebtables.h */
+
+typedef struct _ebiptablesRuleInst ebiptablesRuleInst;
+typedef ebiptablesRuleInst *ebiptablesRuleInstPtr;
+struct _ebiptablesRuleInst {
+ char *commandTemplate;
+ enum virNWFilterChainSuffixType neededProtocolChain;
+ char chainprefix; // I for incoming, O for outgoing
+ unsigned int priority;
+};
+
+extern virNWFilterTechDriver ebiptables_driver;
+
+#define EBIPTABLES_DRIVER_ID "ebiptables"
+
+#endif
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
new file mode 100644
index 0000000000..e590952ae4
--- /dev/null
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -0,0 +1,683 @@
+/*
+ * nwfilter_gentech_driver.c: generic technology driver
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+
+#include "internal.h"
+
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "virterror_internal.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+
+#define NWFILTER_STD_VAR_MAC "MAC"
+
+
+static virNWFilterTechDriverPtr filter_tech_drivers[] = {
+ &ebiptables_driver,
+ NULL
+};
+
+
+virNWFilterTechDriverPtr
+virNWFilterTechDriverForName(const char *name) {
+ int i = 0;
+ while (filter_tech_drivers[i]) {
+ if (STREQ(filter_tech_drivers[i]->name, name))
+ return filter_tech_drivers[i];
+ i++;
+ }
+ return NULL;
+}
+
+
+/**
+ * virNWFilterRuleInstAddData:
+ * @conn : pointer to virConnect object
+ * @res : pointer to virNWFilterRuleInst object collecting the instantiation
+ * data of a single firewall rule.
+ * @data : the opaque data that the driver wants to add
+ *
+ * Add instantiation data to a firewall rule. An instantiated firewall
+ * rule may hold multiple data structure representing its instantiation
+ * data. This may for example be the case if a rule has been defined
+ * for bidirectional traffic and data needs to be added to the incoming
+ * and outgoing chains.
+ *
+ * Returns 0 in case of success, 1 in case of an error with the error
+ * message attached to the virConnect object.
+ */
+int
+virNWFilterRuleInstAddData(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virNWFilterRuleInstPtr res,
+ void *data)
+{
+ if (VIR_REALLOC_N(res->data, res->ndata+1) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+ res->data[res->ndata++] = data;
+ return 0;
+}
+
+
+static void
+virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
+{
+ int i;
+ if (!inst)
+ return;
+
+ for (i = 0; i < inst->ndata; i++)
+ inst->techdriver->freeRuleInstance(inst->data[i]);
+
+ VIR_FREE(inst->data);
+ VIR_FREE(inst);
+}
+
+
+/**
+ * virNWFilterVarHashmapAddStdValues:
+ * @conn: Poijter to virConnect object
+ * @tables: pointer to hash tabel to add values to
+ * @macaddr: The string of the MAC address to add to the hash table,
+ * may be NULL
+ *
+ * Returns 0 in case of success, 1 in case an error happened with
+ * error having been reported.
+ *
+ * Adds a couple of standard keys (MAC, IP) to the hash table.
+ */
+static int
+virNWFilterVarHashmapAddStdValues(virConnectPtr conn,
+ virNWFilterHashTablePtr table,
+ char *macaddr)
+{
+ if (macaddr) {
+ if (virHashAddEntry(table->hashTable,
+ NWFILTER_STD_VAR_MAC,
+ macaddr) < 0) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Could not add variable 'MAC' to hashmap"));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * virNWFilterCreateVarHashmap:
+ * @conn: pointer to virConnect object
+ * @macaddr: pointer to string containing formatted MAC address of interface
+ *
+ * Create a hashmap used for evaluating the firewall rules. Initializes
+ * it with the standard variable 'MAC'.
+ *
+ * Returns pointer to hashmap, NULL if an error occcurred and error message
+ * is attached to the virConnect object.
+ */
+virNWFilterHashTablePtr
+virNWFilterCreateVarHashmap(virConnectPtr conn,
+ char *macaddr) {
+ virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
+ if (!table) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virNWFilterVarHashmapAddStdValues(conn, table, macaddr)) {
+ virNWFilterHashTableFree(table);
+ return NULL;
+ }
+ return table;
+}
+
+
+/**
+ * virNWFilterRuleInstantiate:
+ * @conn: pointer to virConnect object
+ * @techdriver: the driver to use for instantiation
+ * @filter: The filter the rule is part of
+ * @rule : The rule that is to be instantiated
+ * @ifname: The name of the interface
+ * @vars: map containing variable names and value used for instantiation
+ *
+ * Returns virNWFilterRuleInst object on success, NULL on error with
+ * error reported.
+ *
+ * Instantiate a single rule. Return a pointer to virNWFilterRuleInst
+ * object that will hold an array of driver-specific data resulting
+ * from the instantiation. Returns NULL on error with error reported.
+ */
+static virNWFilterRuleInstPtr
+virNWFilterRuleInstantiate(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ virNWFilterRuleDefPtr rule,
+ const char *ifname,
+ virNWFilterHashTablePtr vars)
+{
+ int rc;
+ int i;
+ virNWFilterRuleInstPtr ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ret->techdriver = techdriver;
+
+ rc = techdriver->createRuleInstance(conn, nettype, filter,
+ rule, ifname, vars, ret);
+
+ if (rc) {
+ for (i = 0; i < ret->ndata; i++)
+ techdriver->freeRuleInstance(ret->data[i]);
+ VIR_FREE(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * virNWFilterCreateVarsFrom:
+ * @conn: pointer to virConnect object
+ * @vars1: pointer to hash table
+ * @vars2: pointer to hash table
+ *
+ * Returns pointer to new hashtable or NULL in case of error with
+ * error already reported.
+ *
+ * Creates a new hash table with contents of var1 and var2 added where
+ * contents of var2 will overwrite those of var1.
+ */
+static virNWFilterHashTablePtr
+virNWFilterCreateVarsFrom(virConnectPtr conn,
+ virNWFilterHashTablePtr vars1,
+ virNWFilterHashTablePtr vars2)
+{
+ virNWFilterHashTablePtr res = virNWFilterHashTableCreate(0);
+ if (!res) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (virNWFilterHashTablePutAll(conn, vars1, res))
+ goto err_exit;
+
+ if (virNWFilterHashTablePutAll(conn, vars2, res))
+ goto err_exit;
+
+ return res;
+
+err_exit:
+ virNWFilterHashTableFree(res);
+ return NULL;
+}
+
+
+/**
+ * _virNWFilterPoolInstantiateRec:
+ * @conn: pointer to virConnect object
+ * @techdriver: The driver to use for instantiation
+ * @filter: The filter to instantiate
+ * @ifname: The name of the interface to apply the rules to
+ * @vars: A map holding variable names and values used for instantiating
+ * the filter and its subfilters.
+ * @nEntries: number of virNWFilterInst objects collected
+ * @insts: pointer to array for virNWFilterIns object pointers
+ * @useNewFilter: instruct whether to use a newDef pointer rather than a
+ * def ptr which is useful during a filter update
+ * @foundNewFilter: pointer to int indivating whether a newDef pointer was
+ * ever used; variable expected to be initialized to 0 by caller
+ *
+ * Returns 0 on success, a value otherwise.
+ *
+ * Recursively instantiate a filter by instantiating the given filter along
+ * with all its subfilters in a depth-first traversal of the tree of
+ * referenced filters. The name of the interface to which the rules belong
+ * must be provided. Apply the values of variables as needed. Terminate with
+ * error when a referenced filter is missing or a variable could not be
+ * resolved -- among other reasons.
+ */
+static int
+_virNWFilterInstantiateRec(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ int *nEntries,
+ virNWFilterRuleInstPtr **insts,
+ enum instCase useNewFilter, int *foundNewFilter)
+{
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterPoolObjPtr obj;
+ int rc = 0;
+ int i;
+ virNWFilterRuleInstPtr inst;
+ virNWFilterDefPtr next_filter;
+
+ for (i = 0; i < filter->nentries; i++) {
+ virNWFilterRuleDefPtr rule = filter->filterEntries[i]->rule;
+ virNWFilterIncludeDefPtr inc = filter->filterEntries[i]->include;
+ if (rule) {
+ inst = virNWFilterRuleInstantiate(conn,
+ techdriver,
+ nettype,
+ filter,
+ rule,
+ ifname,
+ vars);
+ if (!inst) {
+ rc = 1;
+ break;
+ }
+
+ if (VIR_REALLOC_N(*insts, (*nEntries)+1) < 0) {
+ virReportOOMError();
+ rc = 1;
+ break;
+ }
+
+ (*insts)[(*nEntries)++] = inst;
+
+ } else if (inc) {
+ VIR_DEBUG("Instantiating filter %s\n", inc->filterref);
+ obj = virNWFilterPoolObjFindByName(&driver->pools,
+ inc->filterref);
+ if (obj) {
+
+ if (obj->wantRemoved) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Filter '%s' is in use."),
+ inc->filterref);
+ rc = 1;
+ virNWFilterPoolObjUnlock(obj);
+ break;
+ }
+
+ // create a temporary hashmap for depth-first tree traversal
+ virNWFilterHashTablePtr tmpvars =
+ virNWFilterCreateVarsFrom(conn,
+ inc->params,
+ vars);
+ if (!tmpvars) {
+ virReportOOMError();
+ rc = 1;
+ virNWFilterPoolObjUnlock(obj);
+ break;
+ }
+
+ next_filter = obj->def;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ if (obj->newDef) {
+ next_filter = obj->newDef;
+ *foundNewFilter = 1;
+ }
+ break;
+ case INSTANTIATE_ALWAYS:
+ break;
+ }
+
+ rc = _virNWFilterInstantiateRec(conn,
+ techdriver,
+ nettype,
+ next_filter,
+ ifname,
+ tmpvars,
+ nEntries, insts,
+ useNewFilter,
+ foundNewFilter);
+
+ virNWFilterHashTableFree(tmpvars);
+
+ virNWFilterPoolObjUnlock(obj);
+ if (rc)
+ break;
+ } else {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("referenced filter '%s' is missing"),
+ inc->filterref);
+ rc = 1;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+
+static int
+virNWFilterRuleInstancesToArray(int nEntries,
+ virNWFilterRuleInstPtr *insts,
+ void ***ptrs,
+ int *nptrs)
+{
+ int i,j;
+
+ *nptrs = 0;
+
+ for (j = 0; j < nEntries; j++)
+ (*nptrs) += insts[j]->ndata;
+
+ if ((*nptrs) == 0)
+ return 0;
+
+ if (VIR_ALLOC_N((*ptrs), (*nptrs)) < 0) {
+ virReportOOMError();
+ return 1;
+ }
+
+ (*nptrs) = 0;
+
+ for (j = 0; j < nEntries; j++)
+ for (i = 0; i < insts[j]->ndata; i++)
+ (*ptrs)[(*nptrs)++] = insts[j]->data[i];
+
+ return 0;
+}
+
+
+/**
+ * virNWFilterInstantiate:
+ * @conn: pointer to virConnect object
+ * @techdriver: The driver to use for instantiation
+ * @filter: The filter to instantiate
+ * @ifname: The name of the interface to apply the rules to
+ * @vars: A map holding variable names and values used for instantiating
+ * the filter and its subfilters.
+ *
+ * Returns 0 on success, a value otherwise.
+ *
+ * Instantiate a filter by instantiating the filter itself along with
+ * all its subfilters in a depth-first traversal of the tree of referenced
+ * filters. The name of the interface to which the rules belong must be
+ * provided. Apply the values of variables as needed.
+ */
+static int
+virNWFilterInstantiate(virConnectPtr conn,
+ virNWFilterTechDriverPtr techdriver,
+ enum virDomainNetType nettype,
+ virNWFilterDefPtr filter,
+ const char *ifname,
+ virNWFilterHashTablePtr vars,
+ enum instCase useNewFilter, int *foundNewFilter,
+ bool teardownOld)
+{
+ int rc;
+ int j, nptrs;
+ int nEntries = 0;
+ virNWFilterRuleInstPtr *insts = NULL;
+ void **ptrs = NULL;
+ int instantiate = 1;
+
+ rc = _virNWFilterInstantiateRec(conn,
+ techdriver,
+ nettype,
+ filter,
+ ifname,
+ vars,
+ &nEntries, &insts,
+ useNewFilter, foundNewFilter);
+
+ if (rc)
+ goto err_exit;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ instantiate = *foundNewFilter;
+ break;
+ case INSTANTIATE_ALWAYS:
+ instantiate = 1;
+ break;
+ }
+
+ if (instantiate) {
+
+ rc = virNWFilterRuleInstancesToArray(nEntries, insts,
+ &ptrs, &nptrs);
+ if (rc)
+ goto err_exit;
+
+ rc = techdriver->applyNewRules(conn, ifname, nptrs, ptrs);
+
+ if (teardownOld && rc == 0)
+ techdriver->tearOldRules(conn, ifname);
+
+ VIR_FREE(ptrs);
+ }
+
+err_exit:
+
+ for (j = 0; j < nEntries; j++)
+ virNWFilterRuleInstFree(insts[j]);
+
+ VIR_FREE(insts);
+
+ return rc;
+}
+
+
+static int
+_virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net,
+ bool teardownOld,
+ enum instCase useNewFilter)
+{
+ int rc;
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
+ virNWFilterTechDriverPtr techdriver;
+ virNWFilterPoolObjPtr obj;
+ virNWFilterHashTablePtr vars, vars1;
+ virNWFilterDefPtr filter;
+ char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
+ int foundNewFilter = 0;
+ char *str_macaddr = NULL;
+
+ techdriver = virNWFilterTechDriverForName(drvname);
+
+ if (!techdriver) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+ return 1;
+ }
+
+ VIR_DEBUG("filter name: %s\n", net->filter);
+
+ obj = virNWFilterPoolObjFindByName(&driver->pools, net->filter);
+ if (!obj) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Could not find filter '%s'"),
+ net->filter);
+ return 1;
+ }
+
+ if (obj->wantRemoved) {
+ virNWFilterReportError(conn, VIR_ERR_NO_NWFILTER,
+ _("Filter '%s' is in use."),
+ net->filter);
+ rc = 1;
+ goto err_exit;
+ }
+
+ virFormatMacAddr(net->mac, vmmacaddr);
+ str_macaddr = strdup(vmmacaddr);
+ if (!str_macaddr) {
+ virReportOOMError();
+ rc = 1;
+ goto err_exit;
+ }
+
+ vars1 = virNWFilterCreateVarHashmap(conn,
+ str_macaddr);
+ if (!vars1) {
+ rc = 1;
+ goto err_exit;
+ }
+
+ str_macaddr = NULL;
+
+ vars = virNWFilterCreateVarsFrom(conn,
+ vars1,
+ net->filterparams);
+ if (!vars) {
+ rc = 1;
+ goto err_exit_vars1;
+ }
+
+ filter = obj->def;
+
+ switch (useNewFilter) {
+ case INSTANTIATE_FOLLOW_NEWFILTER:
+ if (obj->newDef) {
+ filter = obj->newDef;
+ foundNewFilter = 1;
+ }
+ break;
+
+ case INSTANTIATE_ALWAYS:
+ break;
+ }
+
+ rc = virNWFilterInstantiate(conn,
+ techdriver,
+ net->type,
+ filter,
+ net->ifname,
+ vars,
+ useNewFilter, &foundNewFilter,
+ teardownOld);
+
+ virNWFilterHashTableFree(vars);
+
+err_exit_vars1:
+ virNWFilterHashTableFree(vars1);
+
+err_exit:
+
+ virNWFilterPoolObjUnlock(obj);
+
+ VIR_FREE(str_macaddr);
+
+ return rc;
+}
+
+
+int
+virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ 1,
+ INSTANTIATE_ALWAYS);
+}
+
+
+int
+virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ return _virNWFilterInstantiateFilter(conn, net,
+ 0,
+ INSTANTIATE_FOLLOW_NEWFILTER);
+}
+
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net)
+{
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterTechDriverPtr techdriver;
+ techdriver = virNWFilterTechDriverForName(drvname);
+ if (!techdriver) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+ return 1;
+ }
+
+ return techdriver->tearNewRules(conn, net->ifname);
+}
+
+
+int
+virNWFilterTearOldFilter(virConnectPtr conn,
+ virDomainNetDefPtr net)
+{
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterTechDriverPtr techdriver;
+ techdriver = virNWFilterTechDriverForName(drvname);
+ if (!techdriver) {
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+ return 1;
+ }
+
+ return techdriver->tearOldRules(conn, net->ifname);
+}
+
+
+int
+virNWFilterTeardownFilter(const virDomainNetDefPtr net)
+{
+ const char *drvname = EBIPTABLES_DRIVER_ID;
+ virNWFilterTechDriverPtr techdriver;
+ techdriver = virNWFilterTechDriverForName(drvname);
+
+ if (!techdriver) {
+#if 0
+ virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Could not get access to ACL tech "
+ "driver '%s'"),
+ drvname);
+#endif
+ return 1;
+ }
+
+ techdriver->allTeardown(net->ifname);
+
+ return 0;
+}
diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h
new file mode 100644
index 0000000000..a77d95a5c8
--- /dev/null
+++ b/src/nwfilter/nwfilter_gentech_driver.h
@@ -0,0 +1,54 @@
+/*
+ * nwfilter_gentech_driver.h: generic technology driver include file
+ *
+ * Copyright (C) 2010 IBM Corp.
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+#ifndef __NWFILTER_GENTECH_DRIVER_H
+#define __NWFILTER_GENTECH_DRIVER_H
+
+virNWFilterTechDriverPtr virNWFilterTechDriverForName(const char *name);
+
+int virNWFilterRuleInstAddData(virConnectPtr conn,
+ virNWFilterRuleInstPtr res,
+ void *data);
+
+
+enum instCase {
+ INSTANTIATE_ALWAYS,
+ INSTANTIATE_FOLLOW_NEWFILTER,
+};
+
+
+int virNWFilterInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+
+int virNWFilterTearOldFilter(virConnectPtr conn,
+ const virDomainNetDefPtr net);
+
+int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
+
+virNWFilterHashTablePtr virNWFilterCreateVarHashmap(virConnectPtr conn,
+ char *macaddr);
+
+#endif