]> xenbits.xensource.com Git - libvirt.git/commitdiff
Core driver implementation with ebtables support
authorStefan Berger <stefanb@us.ibm.com>
Thu, 25 Mar 2010 17:46:09 +0000 (13:46 -0400)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 26 Mar 2010 18:01:16 +0000 (18:01 +0000)
This patch implements the core driver and provides
- management functionality for managing the filter XMLs
- compiling the internal filter representation into ebtables rules
- applying ebtables rules on a network (tap,macvtap) interface
- tearing down ebtables rules that were applied on behalf of an
interface
- updating of filters while VMs are running and causing the firewalls to
be rebuilt
- other bits and pieces

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
15 files changed:
configure.ac
daemon/Makefile.am
daemon/libvirtd.c
po/POTFILES.in
python/generator.py
src/Makefile.am
src/conf/nwfilter_conf.c
src/libvirt_private.syms
src/libvirt_public.syms
src/nwfilter/nwfilter_driver.c [new file with mode: 0644]
src/nwfilter/nwfilter_driver.h [new file with mode: 0644]
src/nwfilter/nwfilter_ebiptables_driver.c [new file with mode: 0644]
src/nwfilter/nwfilter_ebiptables_driver.h [new file with mode: 0644]
src/nwfilter/nwfilter_gentech_driver.c [new file with mode: 0644]
src/nwfilter/nwfilter_gentech_driver.h [new file with mode: 0644]

index 52b16eeb4d1bf5ed22e3a0cf893214c4368a776d..2148ae039ac8b930406ffd82ffbbd3057dad0a8a 100644 (file)
@@ -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])
index a071609aa31153ef954ecb2c1a61df01fd23fe5f..e117b97a386b2b2f5ebcd9fdc6ebcc4a9051c5b6 100644 (file)
@@ -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
index 0d89c534c6c4248cd2456b231343d05935faf20f..bd45016bff72dbd5347b6a2d4601101932cba229 100644 (file)
@@ -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
index e14360efa3a425557dd200b3005f0da7cf6d0bd9..d24cc1b0ffa983b0122a409a22c48eb7d4b141ae 100644 (file)
@@ -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
index acc8c90cf7f2f53640d094e6211b9c7fc0744cfb..a24e122165fd286366ee3ad3ceae175006108247 100755 (executable)
@@ -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',
index b873d82d87267b305234defbb07cee40192fda55..2409a57354a5795384d37b66b54fa16a8b8bf546 100644 (file)
@@ -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
index e5d285dc13a33e95ee3180b29aa6a543fac93740..a75522c2408ef3ad62fe750309ae400751bb1414 100644 (file)
@@ -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);
 }
 
 
index 4fe542704561fc59004a51fa883f985db53e4a0d..1bcab9fad1a1346ecc30317b4e023f223031c4af 100644 (file)
@@ -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;
index ad7577cd3028f4ef120ffda8f34f990eaa2b72dc..2f812a15850cf9ac09868b34146cf518cbd7a7d8 100644 (file)
@@ -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 (file)
index 0000000..4bb30ce
--- /dev/null
@@ -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 (file)
index 0000000..b7d8668
--- /dev/null
@@ -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 (file)
index 0000000..7af269c
--- /dev/null
@@ -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 (file)
index 0000000..1635b1a
--- /dev/null
@@ -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 (file)
index 0000000..e590952
--- /dev/null
@@ -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 (file)
index 0000000..a77d95a
--- /dev/null
@@ -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