[libvirt] [PATCH 12/13] Core driver implementation with ebtables support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>

---
 configure.ac                              |    3 
 daemon/libvirtd.c                         |    7 
 include/libvirt/virterror.h               |    5 
 python/generator.py                       |    2 
 src/conf/nwfilter_conf.c                  | 2503 ++++++++++++++++++++++++++++++
 src/conf/nwfilter_conf.h                  |  472 +++++
 src/datatypes.c                           |  142 +
 src/datatypes.h                           |   32 
 src/nwfilter/nwfilter_driver.c            |  429 +++++
 src/nwfilter/nwfilter_driver.h            |   35 
 src/nwfilter/nwfilter_ebiptables_driver.c | 1313 +++++++++++++++
 src/nwfilter/nwfilter_ebiptables_driver.h |   41 
 src/nwfilter/nwfilter_gentech_driver.c    |  656 +++++++
 src/nwfilter/nwfilter_gentech_driver.h    |   52 
 src/util/virterror.c                      |   27 
 15 files changed, 5719 insertions(+)

Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -0,0 +1,2503 @@
+/*
+ * nwfilter_conf.c: network filter XML processing
+ *                  (derived from storage_conf.c)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * 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@xxxxxxxxxx>
+ */
+#include <stdio.h>
+#include <config.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <regex.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "config.h"
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "nwfilter_conf.h"
+#include "domain_conf.h"
+
+#include "xml.h"
+#include "uuid.h"
+#include "buf.h"
+#include "util.h"
+#include "memory.h"
+
+#include "nwfilter/nwfilter_gentech_driver.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_NWFILTER
+
+#define virNWFilterError(conn, code, fmt...)                             \
+            virReportErrorHelper(conn, VIR_FROM_NWFILTER, code, __FILE__,\
+                                  __FUNCTION__, __LINE__, fmt)
+
+VIR_ENUM_IMPL(virNWFilterRuleAction, VIR_NWFILTER_RULE_ACTION_LAST,
+              "drop",
+              "accept");
+
+VIR_ENUM_IMPL(virNWFilterJumpTarget, VIR_NWFILTER_RULE_ACTION_LAST,
+              "DROP",
+              "ACCEPT");
+
+VIR_ENUM_IMPL(virNWFilterRuleDirection, VIR_NWFILTER_RULE_DIRECTION_LAST,
+              "in",
+              "out",
+              "inout");
+
+VIR_ENUM_IMPL(virNWFilterChainPolicy, VIR_NWFILTER_CHAIN_POLICY_LAST,
+              "ACCEPT",
+              "DROP");
+
+VIR_ENUM_IMPL(virNWFilterEbtablesTable, VIR_NWFILTER_EBTABLES_TABLE_LAST,
+              "filter",
+              "nat",
+              "broute");
+
+VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
+              "root",
+              "arp",
+              "ipv4");
+
+
+/*
+ * a map entry for a simple static int-to-string map
+ */
+struct int_map {
+    int32_t attr;
+    const char *val;
+};
+
+
+/*
+ * only one filter update allowed
+ */
+static virMutex updateMutex;
+
+static void
+virNWFilterLockFilterUpdates(void) {
+    virMutexLock(&updateMutex);
+}
+
+static void
+virNWFilterUnlockFilterUpdates(void) {
+    virMutexUnlock(&updateMutex);
+}
+
+
+/*
+ * regular expressions for parameter names and values
+ */
+static regex_t regex_nam;
+static regex_t regex_val;
+
+
+/*
+ * attribute names for the rules XML
+ */
+static const char srcmacaddr_str[]   = "srcmacaddr";
+static const char srcmacmask_str[]   = "srcmacmask";
+static const char dstmacaddr_str[]   = "dstmacaddr";
+static const char dstmacmask_str[]   = "dstmacmask";
+static const char srcipaddr_str[]    = "srcipaddr";
+static const char srcipmask_str[]    = "srcipmask";
+static const char dstipaddr_str[]    = "dstipaddr";
+static const char dstipmask_str[]    = "dstipmask";
+static const char srcportstart_str[] = "srcportstart";
+static const char srcportend_str[]   = "srcportend";
+static const char dstportstart_str[] = "dstportstart";
+static const char dstportend_str[]   = "dstportend";
+
+#define SRCMACADDR   srcmacaddr_str
+#define SRCMACMASK   srcmacmask_str
+#define DSTMACADDR   dstmacaddr_str
+#define DSTMACMASK   dstmacmask_str
+#define SRCIPADDR    srcipaddr_str
+#define SRCIPMASK    srcipmask_str
+#define DSTIPADDR    dstipaddr_str
+#define DSTIPMASK    dstipmask_str
+#define SRCPORTSTART srcportstart_str
+#define SRCPORTEND   srcportend_str
+#define DSTPORTSTART dstportstart_str
+#define DSTPORTEND   dstportend_str
+
+
+/**
+ * intMapGetByInt:
+ * @intmap: Pointer to int-to-string map
+ * @attr: The attribute to look up
+ * @res: Pointer to string pointer for result
+ *
+ * Returns 1 if value was found with result returned, 0 otherwise.
+ *
+ * lookup a map entry given the integer.
+ */
+static bool
+intMapGetByInt(const struct int_map *intmap, int32_t attr, const char **res)
+{
+    int i = 0;
+    bool found = 0;
+    while (intmap[i].val && !found) {
+        if (intmap[i].attr == attr) {
+            *res = intmap[i].val;
+            found = 1;
+        }
+        i++;
+    }
+    return found;
+}
+
+
+/**
+ * intMapGetByString:
+ * @intmap: Pointer to int-to-string map
+ * @str: Pointer to string for which to find the entry
+ * @casecmp : Whether to ignore case when doing string matching
+ * @result: Pointer to int for result
+ *
+ * Returns 0 if no entry was found, 1 otherwise.
+ *
+ * Do a lookup in the map trying to find an integer key using the string
+ * value. Returns 1 if entry was found with result returned, 0 otherwise.
+ */
+static bool
+intMapGetByString(const struct int_map *intmap, const char *str, int casecmp,
+                  int32_t *result)
+{
+    int i = 0;
+    bool found = 0;
+    while (intmap[i].val && !found) {
+        if ( (casecmp && STRCASEEQ(intmap[i].val, str)) ||
+                         STREQ    (intmap[i].val, str)    ) {
+            *result = intmap[i].attr;
+            found = 1;
+        }
+        i++;
+    }
+    return found;
+}
+
+
+void
+virNWFilterRuleDefFree(virNWFilterRuleDefPtr def) {
+    int i;
+    if (!def)
+        return;
+
+    for (i = 0; i < def->nvars; i++)
+        VIR_FREE(def->vars[i]);
+
+    VIR_FREE(def->vars);
+
+    VIR_FREE(def);
+}
+
+
+static void
+hashDealloc(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+    VIR_FREE(payload);
+}
+
+
+static void
+virNWFilterIncludeDefFree(virNWFilterIncludeDefPtr inc) {
+    if (!inc)
+        return;
+    virNWFilterHashTableFree(inc->params);
+    VIR_FREE(inc->filterref);
+    VIR_FREE(inc);
+}
+
+
+static void
+virNWFilterEntryFree(virNWFilterEntryPtr entry) {
+    if (!entry)
+        return;
+
+    virNWFilterRuleDefFree(entry->rule);
+    virNWFilterIncludeDefFree(entry->include);
+    VIR_FREE(entry);
+}
+
+
+void
+virNWFilterDefFree(virNWFilterDefPtr def) {
+    int i;
+    if (!def)
+        return;
+
+    VIR_FREE(def->name);
+
+    for (i = 0; i < def->nentries; i++)
+        virNWFilterEntryFree(def->filterEntries[i]);
+
+    VIR_FREE(def->filterEntries);
+
+    VIR_FREE(def);
+}
+
+
+void
+virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj) {
+    if (!obj)
+        return;
+
+    virNWFilterDefFree(obj->def);
+    virNWFilterDefFree(obj->newDef);
+
+    VIR_FREE(obj->configFile);
+
+    virMutexDestroy(&obj->lock);
+
+    VIR_FREE(obj);
+}
+
+
+void
+virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools)
+{
+    unsigned int i;
+    for (i = 0 ; i < pools->count ; i++)
+        virNWFilterPoolObjFree(pools->objs[i]);
+    VIR_FREE(pools->objs);
+    pools->count = 0;
+}
+
+
+static int
+virNWFilterRuleDefAddVar(virConnectPtr conn ATTRIBUTE_UNUSED,
+                         virNWFilterRuleDefPtr nwf,
+                         nwItemDesc *item,
+                         const char *var)
+{
+    int i = 0;
+
+    if (nwf->vars) {
+        for (i = 0; i < nwf->nvars; i++)
+            if (STREQ(nwf->vars[i], var)) {
+                item->var = nwf->vars[i];
+                return 0;
+            }
+    }
+
+    if (VIR_REALLOC_N(nwf->vars, nwf->nvars+1) < 0) {
+        virReportOOMError();
+        return 1;
+    }
+
+    nwf->vars[nwf->nvars] = strdup(var);
+
+    if (!nwf->vars[nwf->nvars]) {
+        virReportOOMError();
+        return 1;
+    }
+
+    item->var = nwf->vars[nwf->nvars++];
+
+    return 0;
+}
+
+
+void
+virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+                         virNWFilterPoolObjPtr pool)
+{
+    unsigned int i;
+
+    virNWFilterPoolObjUnlock(pool);
+
+    for (i = 0 ; i < pools->count ; i++) {
+        virNWFilterPoolObjLock(pools->objs[i]);
+        if (pools->objs[i] == pool) {
+            virNWFilterPoolObjUnlock(pools->objs[i]);
+            virNWFilterPoolObjFree(pools->objs[i]);
+
+            if (i < (pools->count - 1))
+                memmove(pools->objs + i, pools->objs + i + 1,
+                        sizeof(*(pools->objs)) * (pools->count - (i + 1)));
+
+            if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
+                ; /* Failure to reduce memory allocation isn't fatal */
+            }
+            pools->count--;
+
+            break;
+        }
+        virNWFilterPoolObjUnlock(pools->objs[i]);
+    }
+}
+
+
+
+typedef bool (*valueValidator)(enum attrDatatype datatype, void *valptr,
+                               virNWFilterRuleDefPtr nwf);
+typedef bool (*valueFormatter)(virBufferPtr buf,
+                               virNWFilterRuleDefPtr nwf);
+
+typedef struct _virXMLAttr2Struct virXMLAttr2Struct;
+struct _virXMLAttr2Struct
+{
+    const char *name;           // attribute name
+    enum attrDatatype datatype;
+    int dataIdx;		// offset of the hasXYZ boolean
+    valueValidator validator;   // beyond-standard checkers
+    valueFormatter formatter;   // beyond-standard formatter
+};
+
+
+
+static bool
+checkPriority(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+              virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+    unsigned char prio = *(unsigned char *)val;
+    if (prio > 7)
+        return 0;
+    return 1;
+}
+
+
+static bool
+checkVLAN(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+          virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+    uint16_t vid = *(uint16_t *)val;
+    if (vid >= 0x1000)
+        return 0;
+    return 1;
+}
+
+
+
+
+static const struct int_map macProtoMap[] = {
+    {
+      .attr = ETHERTYPE_ARP,
+      .val  = "arp",
+    }, {
+      .attr = ETHERTYPE_IP,
+      .val  = "ipv4",
+    }, {
+      .val  = NULL,
+    }
+};
+
+
+static bool
+checkMacProtocolID(enum attrDatatype datatype, void *value,
+                   virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+    int32_t res = -1;
+    const char *str;
+
+    if (datatype == DATATYPE_STRING) {
+        if (intMapGetByString(macProtoMap, (char *)value, 1, &res) == 0)
+            res = -1;
+    } else if (datatype == DATATYPE_UINT16) {
+        if (intMapGetByInt(macProtoMap,
+                           (int32_t)*(uint16_t *)value, &str) == 0)
+            res = -1;
+    }
+
+    if (res != -1) {
+        nwf->p.ethHdrFilter.dataProtocolID.u.u16 = res;
+        return 1;
+    }
+
+    return 0;
+}
+
+
+static bool
+macProtocolIDFormatter(virBufferPtr buf,
+                       virNWFilterRuleDefPtr nwf)
+{
+    const char *str = NULL;
+
+    if (intMapGetByInt(macProtoMap,
+                       nwf->p.ethHdrFilter.dataProtocolID.u.u16,
+                       &str)) {
+        virBufferVSprintf(buf, "%s", str);
+        return 1;
+    }
+    return 0;
+}
+
+
+/* generic function to check for a valid (ipv4,ipv6, mac) mask
+ * A mask is valid of there is a sequence of 1's followed by a sequence
+ * of 0s or only 1s or only 0s
+ */
+static bool
+checkValidMask(unsigned char *data, int len)
+{
+    uint32_t idx = 0;
+    uint8_t mask = 0x80;
+    int checkones = 1;
+
+    while ((idx >> 3) < len) {
+        if (checkones) {
+            if (!(data[idx>>3] & mask))
+                checkones = 0;
+        } else {
+            if ((data[idx>>3] & mask))
+                return 0;
+        }
+
+        idx++;
+        mask >>= 1;
+        if (!mask)
+            mask = 0x80;
+    }
+    return 1;
+}
+
+
+/* check for a valid IPv4 mask */
+static bool
+checkIPv4Mask(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *maskptr,
+              virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+    return checkValidMask(maskptr, 4);
+}
+
+
+static bool
+checkMACMask(enum attrDatatype datatype ATTRIBUTE_UNUSED,
+             void *macMask,
+             virNWFilterRuleDefPtr nwf ATTRIBUTE_UNUSED)
+{
+    return checkValidMask((unsigned char *)macMask, 6);
+}
+
+
+static int getMaskNumBits(const unsigned char *mask, int len) {
+     int i = 0;
+     while (i < (len << 3)) {
+         if (!(mask[i>>3] & (0x80 >> (i & 3))))
+             break;
+         i++;
+     }
+     return i;
+}
+
+/*
+ * supported arp opcode -- see 'ebtables -h arp' for the naming
+ */
+static const struct int_map arpOpcodeMap[] = {
+    {
+        .attr = 1,
+        .val = "Request",
+    } , {
+        .attr = 2,
+        .val = "Reply",
+    } , {
+        .attr = 3,
+        .val = "Request_Reverse",
+    } , {
+        .attr = 4,
+        .val = "Reply_Reverse",
+    } , {
+        .attr = 5,
+        .val = "DRARP_Request",
+    } , {
+        .attr = 6,
+        .val = "DRARP_Reply",
+    } , {
+        .attr = 7,
+        .val = "DRARP_Error",
+    } , {
+        .attr = 8,
+        .val = "InARP_Request",
+    } , {
+        .attr = 9,
+        .val = "ARP_NAK",
+    } , {
+        .val = NULL,
+    }
+};
+
+
+static bool
+arpOpcodeValidator(enum attrDatatype datatype,
+                   void *value,
+                   virNWFilterRuleDefPtr nwf)
+{
+    int32_t res = -1;
+    const char *str;
+
+    if (datatype == DATATYPE_STRING) {
+        if (intMapGetByString(arpOpcodeMap, (char *)value, 1, &res) == 0)
+            res = -1;
+    } else if (datatype == DATATYPE_UINT8) {
+        if (intMapGetByInt(arpOpcodeMap,
+                           (uint32_t)*(uint16_t *)value, &str) == 0)
+            res = -1;
+    }
+
+    if (res != -1) {
+        nwf->p.arpHdrFilter.dataOpcode.u.u16 = res;
+        return 1;
+    }
+    return 0;
+}
+
+
+static bool
+arpOpcodeFormatter(virBufferPtr buf,
+                   virNWFilterRuleDefPtr nwf)
+{
+    const char *str = NULL;
+
+    if (intMapGetByInt(arpOpcodeMap,
+                       nwf->p.arpHdrFilter.dataOpcode.u.u16,
+                       &str)) {
+        virBufferVSprintf(buf, "%s", str);
+        return 1;
+    }
+    return 0;
+}
+
+
+static const struct int_map ipProtoMap[] = {
+    {
+        .attr = IPPROTO_TCP,
+        .val  = "tcp",
+    } , {
+        .attr = IPPROTO_UDP,
+        .val  = "udp",
+    } , {
+        .attr = IPPROTO_ICMP,
+        .val  = "icmp",
+    } , {
+        .attr = IPPROTO_IGMP,
+        .val  = "igmp",
+#ifdef IPPROTO_SCTP
+    } , {
+        .attr = IPPROTO_SCTP,
+        .val  = "sctp",
+#endif
+    } , {
+        .val = NULL,
+    }
+};
+
+
+static bool checkIPProtocolID(enum attrDatatype datatype,
+                              void *value,
+                              virNWFilterRuleDefPtr nwf)
+{
+    int32_t res = -1;
+    const char *str;
+
+    if (datatype == DATATYPE_STRING) {
+        if (intMapGetByString(ipProtoMap, (char *)value, 1, &res) == 0)
+            res = -1;
+    } else if (datatype == DATATYPE_UINT8) {
+        // may just accept what user provides and not test...
+        if (intMapGetByInt(ipProtoMap,
+                           (uint32_t)*(uint16_t *)value, &str) == 0)
+            res = -1;
+    }
+
+    if (res != -1) {
+        nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16 = res;
+        return 1;
+    }
+    return 0;
+}
+
+
+static bool
+formatIPProtocolID(virBufferPtr buf,
+                   virNWFilterRuleDefPtr nwf)
+{
+    const char *str = NULL;
+
+    if (intMapGetByInt(ipProtoMap,
+                       nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16,
+                       &str)) {
+        virBufferVSprintf(buf, "%s", str);
+        return 1;
+    }
+    return 0;
+}
+
+
+static const virXMLAttr2Struct macAttributes[] = {
+    {
+        .name = SRCMACADDR,
+        .datatype = DATATYPE_MACADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataSrcMACAddr),
+    },
+    {
+        .name = SRCMACMASK,
+        .datatype = DATATYPE_MACMASK,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataSrcMACMask),
+    },
+    {
+        .name = DSTMACADDR,
+        .datatype = DATATYPE_MACADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataDstMACAddr),
+    },
+    {
+        .name = DSTMACMASK,
+        .datatype = DATATYPE_MACMASK,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataDstMACMask),
+    },
+    {
+        .name = "protocolid",
+        .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataProtocolID),
+        .validator= checkMacProtocolID,
+        .formatter= macProtocolIDFormatter,
+    },
+    {
+        .name = "priority",
+        .datatype = DATATYPE_UINT8,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataPriority),
+        .validator= checkPriority, // enforce only 3 valid bits
+    },
+    {
+        .name = "vlanid",
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataVLANID),
+        .validator= checkVLAN, // enforce only 12 valid bits
+    },
+    {
+        .name = NULL,
+    }
+};
+
+static const virXMLAttr2Struct arpAttributes[] = {
+    {
+        .name = "hwtype",
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataHWType),
+    }, {
+        .name = "protocoltype",
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataProtocolType),
+    }, {
+        .name = "opcode",
+        .datatype = DATATYPE_UINT8 | DATATYPE_STRING,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataOpcode),
+        .validator= arpOpcodeValidator,
+        .formatter= arpOpcodeFormatter,
+    }, {
+        .name = SRCMACADDR,
+        .datatype = DATATYPE_MACADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataSrcMACAddr),
+    }, {
+        .name = DSTMACADDR,
+        .datatype = DATATYPE_MACADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataDstMACAddr),
+    }, {
+        .name = SRCIPADDR,
+        .datatype = DATATYPE_IPADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataSrcIPAddr),
+    }, {
+        .name = DSTIPADDR,
+        .datatype = DATATYPE_IPADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataDstIPAddr),
+    },
+    {
+        .name = NULL,
+    }
+};
+
+static const virXMLAttr2Struct ipAttributes[] = {
+    {
+        .name = "version",
+        .datatype = DATATYPE_UINT8,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataIPVersion),
+    },
+    {
+        .name = SRCIPADDR,
+        .datatype = DATATYPE_IPADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcAddr),
+    },
+    {
+        .name = DSTIPADDR,
+        .datatype = DATATYPE_IPADDR,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstAddr),
+    },
+    {
+        .name = SRCIPMASK,
+        .datatype = DATATYPE_IPMASK,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcMask),
+    },
+    {
+        .name = DSTIPMASK,
+        .datatype = DATATYPE_IPMASK,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstMask),
+    },
+    {
+        .name = "protocol",
+        .datatype = DATATYPE_STRING,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataProtocolID),
+        .validator= checkIPProtocolID,
+        .formatter= formatIPProtocolID,
+    },
+    {
+        .name = SRCPORTSTART,
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortStart),
+    },
+    {
+        .name = SRCPORTEND,
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortEnd),
+    },
+    {
+        .name = DSTPORTSTART,
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortStart),
+    },
+    {
+        .name = DSTPORTEND,
+        .datatype = DATATYPE_UINT16,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortEnd),
+    },
+    {
+        .name = NULL,
+    }
+};
+
+
+typedef struct _virAttributes virAttributes;
+struct _virAttributes {
+    const char *id;
+    const virXMLAttr2Struct *att;
+    enum virNWFilterRuleProtocolType prtclType;
+};
+
+
+static const virAttributes virAttr[] = {
+    {
+        .id = "arp",
+        .att = arpAttributes,
+        .prtclType = VIR_NWFILTER_RULE_PROTOCOL_ARP,
+    }, {
+        .id = "mac",
+        .att = macAttributes,
+        .prtclType = VIR_NWFILTER_RULE_PROTOCOL_MAC,
+    }, {
+        .id = "ip",
+        .att = ipAttributes,
+        .prtclType = VIR_NWFILTER_RULE_PROTOCOL_IP,
+    }, {
+        .id = NULL,
+    }
+};
+
+
+static bool
+virNWMACAddressParser(const char *input,
+                      nwMACAddressPtr output)
+{
+    if (virParseMacAddr(input, &output->addr[0]) == 0)
+        return 1;
+    return 0;
+}
+
+
+static bool
+virNWIPv4AddressParser(const char *input,
+                       nwIPAddressPtr output)
+{
+    int i;
+    char *endptr;
+    const char *n = input;
+    long int d;
+
+    for (i = 0; i < 4; i++) {
+        d = strtol(n, &endptr, 10);
+        if (d < 0 || d > 255            ||
+            (endptr - n        > 3    ) ||
+            (i <= 2 && *endptr != '.' ) ||
+            (i == 3 && *endptr != '\0'))
+            return 0;
+        output->addr.ipv4Addr[i] = (unsigned char)d;
+        n = endptr + 1;
+    }
+    return 1;
+}
+
+
+static int
+virNWFilterRuleDetailsParse(virConnectPtr conn ATTRIBUTE_UNUSED,
+                            xmlNodePtr node,
+                            virNWFilterRuleDefPtr nwf,
+                            const virXMLAttr2Struct *att)
+{
+    int rc = 0;
+    int idx = 0;
+    char *prop;
+    int found = 0;
+    enum attrDatatype datatype, att_datatypes;
+    enum virNWFilterEntryItemFlags *flags ,match_flag = 0, flags_set = 0;
+    nwItemDesc *item;
+    int int_val;
+    void *data_ptr, *storage_ptr;
+    valueValidator validator;
+    char *match = virXMLPropString(node, "match");
+    nwIPAddress ipaddr;
+
+    if (match && STREQ(match, "no"))
+        match_flag = NWFILTER_ENTRY_ITEM_FLAG_IS_NEG;
+    VIR_FREE(match);
+    match = NULL;
+
+    while (att[idx].name != NULL && rc == 0) {
+        prop = virXMLPropString(node, att[idx].name);
+
+        item = (nwItemDesc *)((char *)nwf + att[idx].dataIdx);
+        flags = &item->flags;
+        flags_set = match_flag;
+
+        if (prop) {
+            found = 0;
+
+            validator = NULL;
+
+            if (STRPREFIX(prop, "$")) {
+                flags_set |= NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR;
+                storage_ptr = NULL;
+
+                if (virNWFilterRuleDefAddVar(conn,
+                                             nwf,
+                                             item,
+                                             &prop[1]))
+                    rc = -1;
+                found = 1;
+            }
+
+            datatype = 1;
+
+            att_datatypes = att[idx].datatype;
+
+            while (datatype <= DATATYPE_LAST && found == 0 && rc == 0) {
+                if ((att_datatypes & datatype)) {
+
+                    att_datatypes ^= datatype;
+
+                    validator = att[idx].validator;
+
+                    switch (datatype) {
+
+                        case DATATYPE_UINT8:
+                            storage_ptr = &item->u.u8;
+                            if (sscanf(prop, "%d", &int_val) == 1) {
+                                if (int_val >= 0 && int_val <= 0xff) {
+                                    if (!validator)
+                                        *(uint8_t *)storage_ptr = int_val;
+                                    found = 1;
+                                    data_ptr = &int_val;
+                                } else
+                                    rc = -1;
+                            } else
+                                rc = -1;
+                        break;
+
+                        case DATATYPE_UINT16:
+                            storage_ptr = &item->u.u16;
+                            if (sscanf(prop, "%d", &int_val) == 1) {
+                                if (int_val >= 0 && int_val <= 0xffff) {
+                                    if (!validator)
+                                        *(uint16_t *)storage_ptr = int_val;
+                                    found = 1;
+                                    data_ptr = &int_val;
+                                } else
+                                    rc = -1;
+                            } else
+                                rc = -1;
+                        break;
+
+                        case DATATYPE_IPADDR:
+                            // parse as dotted IPv4
+                            // search for existing parser in libvirt
+                            // later: also parse as IPv6
+                            storage_ptr = &item->u.ipaddr;
+                            if (!virNWIPv4AddressParser(prop,
+                                       (nwIPAddressPtr)storage_ptr)) {
+                                rc = -1;
+                            }
+                            found = 1;
+                        break;
+
+                        case DATATYPE_IPMASK:
+                            // parse as dotted IPv4
+                            // parse as CIDR mask
+                            // later: also parse as IPv6
+                            storage_ptr = &item->u.u8;
+                            if (!virNWIPv4AddressParser(prop, &ipaddr)) {
+                                if (sscanf(prop, "%d", &int_val) == 1) {
+                                    if (int_val >= 0 && int_val <= 32) {
+                                        if (!validator)
+                                            *(uint8_t *)storage_ptr =
+                                                   (uint8_t)int_val;
+                                        found = 1;
+                                        data_ptr = &int_val;
+                                    } else
+                                        rc = -1;
+                                } else
+                                    rc = -1;
+                            } else {
+                                if (checkIPv4Mask(datatype,
+                                                  ipaddr.addr.ipv4Addr, nwf))
+                                    *(uint8_t *)storage_ptr =
+                                       getMaskNumBits(ipaddr.addr.ipv4Addr,
+                                                 sizeof(ipaddr.addr.ipv4Addr));
+                                else
+                                    rc = -1;
+                                found = 1;
+                            }
+                        break;
+
+                        case DATATYPE_MACADDR:
+                            storage_ptr = &item->u.macaddr;
+                            if (!virNWMACAddressParser(prop,
+                                        (nwMACAddressPtr)storage_ptr)) {
+                                rc = -1;
+                            }
+                            found = 1;
+                        break;
+
+                        case DATATYPE_MACMASK:
+                            validator = checkMACMask;
+                            storage_ptr = &item->u.macaddr;
+                            if (!virNWMACAddressParser(prop,
+                                        (nwMACAddressPtr)storage_ptr)) {
+                                rc = -1;
+                            }
+                            data_ptr = storage_ptr;
+                            found = 1;
+                        break;
+
+                        case DATATYPE_STRING:
+                            if (!validator) {
+                                // not supported
+                                rc = -1;
+                                break;
+                            }
+                            data_ptr = prop;
+                            found = 1;
+                        break;
+
+                        case DATATYPE_LAST:
+                        default:
+                        break;
+                    }
+                }
+
+                if (rc != 0 && att_datatypes != 0) {
+                    rc = 0;
+                    found = 0;
+                }
+
+                datatype <<= 1;
+            } /* while */
+
+            if (found == 1 && rc == 0) {
+                *flags = NWFILTER_ENTRY_ITEM_FLAG_EXISTS | flags_set;
+                item->datatype = datatype >> 1;
+                if (validator) {
+                    if (!validator(datatype >> 1, data_ptr, nwf)) {
+                        rc = -1;
+                        *flags = 0;
+                    }
+                }
+            }
+
+            if (!found || rc) {
+                virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                       _("%s has illegal value %s"),
+                                       att[idx].name, prop);
+                rc = -1;
+            }
+            VIR_FREE(prop);
+        }
+        idx++;
+    }
+
+    return rc;
+}
+
+
+/**
+ * virNWFilterHashTablePut:
+ * @table: Pointer to a virNWFilterHashTable
+ * @name: name of the key to enter
+ * @val: The value associated with the key
+ * @freeName: Whether the name must be freed on table destruction
+ *
+ * Returns 0 on success, 1 on failure.
+ *
+ * Put an entry into the hashmap replacing and freeing an existing entry
+ * if one existed.
+ */
+int
+virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+                        const char *name,
+                        char *val,
+                        int copyName)
+{
+    if (!virHashLookup(table->hashTable, name)) {
+        if (copyName) {
+            name = strdup(name);
+            if (!name)
+                return 1;
+
+            if (VIR_REALLOC_N(table->names, table->nNames + 1) < 0) {
+                VIR_FREE(name);
+                return 1;
+            }
+            table->names[table->nNames++] = (char *)name;
+        }
+
+        if (virHashAddEntry(table->hashTable, name, val) != 0) {
+            if (copyName) {
+                VIR_FREE(name);
+                table->nNames--;
+            }
+            return 1;
+        }
+    } else {
+        if (virHashUpdateEntry(table->hashTable, name, val, hashDealloc) != 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+/**
+ * virNWFilterHashTableFree:
+ * @table: Pointer to virNWFilterHashTable
+ *
+ * Free a hashtable de-allocating memory for all its entries.
+ *
+ * All hash tables within the NWFilter driver must use this
+ * function to deallocate and free their content.
+ */
+void
+virNWFilterHashTableFree(virNWFilterHashTablePtr table)
+{
+    int i;
+    if (!table)
+        return;
+    virHashFree(table->hashTable, hashDealloc);
+
+    for (i = 0; i < table->nNames; i++)
+        VIR_FREE(table->names[i]);
+    VIR_FREE(table->names);
+    VIR_FREE(table);
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterHashTableCreate(int n) {
+    virNWFilterHashTablePtr ret;
+
+    if (VIR_ALLOC(ret) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+    ret->hashTable = virHashCreate(n);
+    if (!ret->hashTable) {
+        virReportOOMError();
+        VIR_FREE(ret);
+        return NULL;
+    }
+    return ret;
+}
+
+
+int
+virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr ht,
+                                const char *entry)
+{
+    int i;
+    int rc = virHashRemoveEntry(ht->hashTable, entry, hashDealloc);
+
+    if (rc == 0) {
+        for (i = 0; i < ht->nNames; i++) {
+            if (STREQ(ht->names[i], entry)) {
+                VIR_FREE(ht->names[i]);
+                ht->names[i] = ht->names[--ht->nNames];
+                ht->names[ht->nNames] = NULL;
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+
+struct addToTableStruct {
+    virNWFilterHashTablePtr target;
+    int errOccurred;
+    virConnectPtr conn;
+};
+
+
+static void
+addToTable(void *payload, const char *name, void *data)
+{
+    struct addToTableStruct *atts = (struct addToTableStruct *)data;
+    char *val;
+
+    if (atts->errOccurred)
+        return;
+
+    val = strdup((char *)payload);
+    if (!val) {
+        virReportOOMError();
+        atts->errOccurred = 1;
+        return;
+    }
+
+    if (virNWFilterHashTablePut(atts->target, name, val, 1) != 0) {
+        virNWFilterReportError(atts->conn, VIR_ERR_INTERNAL_ERROR,
+                               _("Could not put variable '%s' into hashmap"),
+                               name);
+        atts->errOccurred = 1;
+        VIR_FREE(val);
+    }
+}
+
+
+int
+virNWFilterHashTablePutAll(virConnectPtr conn,
+                           virNWFilterHashTablePtr src,
+                           virNWFilterHashTablePtr dest)
+{
+    struct addToTableStruct atts = {
+        .target = dest,
+        .errOccurred = 0,
+        .conn = conn,
+    };
+
+    virHashForEach(src->hashTable, addToTable, &atts);
+    if (atts.errOccurred)
+        goto err_exit;
+
+    return 0;
+
+err_exit:
+    return 1;
+}
+
+
+virNWFilterHashTablePtr
+virNWFilterParseParamAttributes(xmlNodePtr cur)
+{
+    char *nam, *val;
+
+    virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
+    if (!table) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    cur = cur->children;
+
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            if (xmlStrEqual(cur->name, BAD_CAST "parameter")) {
+                nam = virXMLPropString(cur, "name");
+                val = virXMLPropString(cur, "value");
+                if (nam != NULL && val != NULL) {
+                    if (regexec(&regex_nam, nam, 0, NULL, 0) != 0)
+                        goto skip_entry;
+                    if (regexec(&regex_val, val, 0, NULL, 0) != 0)
+                        goto skip_entry;
+                    if (virNWFilterHashTablePut(table, nam, val, 1)) {
+                        VIR_FREE(nam);
+                        VIR_FREE(val);
+                        virNWFilterHashTableFree(table);
+                        return NULL;
+                    }
+                    val = NULL;
+                }
+skip_entry:
+                VIR_FREE(nam);
+                VIR_FREE(val);
+            }
+        }
+        cur = cur->next;
+    }
+    return table;
+}
+
+
+struct formatterParam {
+    virBufferPtr buf;
+    const char *indent;
+};
+
+
+static void
+_formatParameterAttrs(void *payload, const char *name, void *data)
+{
+    struct formatterParam *fp = (struct formatterParam *)data;
+
+    virBufferVSprintf(fp->buf, "%s<parameter name='%s' value='%s'/>\n",
+                      fp->indent,
+                      name,
+                      (char *)payload);
+}
+
+
+char *
+virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+                                 const char *indent)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    struct formatterParam fp = {
+        .buf = &buf,
+        .indent = indent,
+    };
+
+    virHashForEach(table->hashTable, _formatParameterAttrs, &fp);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        virBufferFreeAndReset(&buf);
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+static virNWFilterIncludeDefPtr
+virNWFilterIncludeParse(virConnectPtr conn,
+                        xmlNodePtr cur)
+{
+    virNWFilterIncludeDefPtr ret;
+
+    if (VIR_ALLOC(ret) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    ret->filterref = virXMLPropString(cur, "filter");
+    if (!ret->filterref) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("rule node requires action attribute"));
+        goto err_exit;
+    }
+
+    ret->params = virNWFilterParseParamAttributes(cur);
+    if (!ret->params)
+        goto err_exit;
+
+cleanup:
+    return ret;
+
+err_exit:
+    virNWFilterIncludeDefFree(ret);
+    ret = NULL;
+    goto cleanup;
+}
+
+
+static void
+virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule)
+{
+#define COPY_NEG_SIGN(A, B) \
+    (A).flags = ((A).flags & ~NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) | \
+                ((B).flags &  NWFILTER_ENTRY_ITEM_FLAG_IS_NEG);
+
+    switch (rule->prtclType) {
+    case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+        COPY_NEG_SIGN(rule->p.ethHdrFilter.dataSrcMACMask,
+                      rule->p.ethHdrFilter.dataSrcMACAddr);
+        COPY_NEG_SIGN(rule->p.ethHdrFilter.dataDstMACMask,
+                      rule->p.ethHdrFilter.dataDstMACAddr);
+    break;
+
+    case VIR_NWFILTER_RULE_PROTOCOL_IP:
+        COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcMask,
+                      rule->p.ipHdrFilter.ipHdr.dataSrcAddr);
+        COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataDstMask,
+                      rule->p.ipHdrFilter.ipHdr.dataDstAddr);
+    break;
+
+    case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+    case VIR_NWFILTER_RULE_PROTOCOL_NONE:
+    break;
+    }
+
+#undef COPY_NEG_SIGN
+}
+
+
+static virNWFilterRuleDefPtr
+virNWFilterRuleParse(virConnectPtr conn,
+                     xmlNodePtr node)
+{
+    char *action;
+    char *direction;
+    char *prio;
+    int found;
+    int found_i;
+    unsigned int priority;
+
+    xmlNodePtr cur;
+    virNWFilterRuleDefPtr ret;
+
+    if (VIR_ALLOC(ret) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    action    = virXMLPropString(node, "action");
+    direction = virXMLPropString(node, "direction");
+    prio      = virXMLPropString(node, "priority");
+
+    if (!action) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("rule node requires action attribute"));
+        goto err_exit;
+    }
+
+    if ((ret->action = virNWFilterRuleActionTypeFromString(action)) < 0) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("unknown rule action attribute value"));
+        goto err_exit;
+    }
+
+    if (!direction) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("rule node requires direction attribute"));
+        goto err_exit;
+    }
+
+    if ((ret->tt = virNWFilterRuleDirectionTypeFromString(direction)) < 0) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s",
+                               _("unknown rule direction attribute value"));
+        goto err_exit;
+    }
+
+    ret->priority = MAX_RULE_PRIORITY / 2;
+
+    if (prio) {
+        if (sscanf(prio, "%d", (int *)&priority) == 1) {
+            if ((int)priority >= 0 && priority <= MAX_RULE_PRIORITY)
+                ret->priority = priority;
+        }
+    }
+
+    cur = node->children;
+
+    found = 0;
+
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE) {
+            int i = 0;
+            while (1) {
+                if (found)
+                    i = found_i;
+
+                if (xmlStrEqual(cur->name, BAD_CAST virAttr[i].id)) {
+
+                    found_i = i;
+                    found = 1;
+                    ret->prtclType = virAttr[i].prtclType;
+
+                    if (virNWFilterRuleDetailsParse(conn,
+                                                    cur,
+                                                    ret,
+                                                    virAttr[i].att) < 0) {
+                        /* we ignore malformed rules
+                           goto err_exit;
+                        */
+                    }
+                    break;
+                }
+                if (!found) {
+                    i++;
+                    if (!virAttr[i].id)
+                        break;
+                } else
+                   break;
+            }
+        }
+
+        cur = cur->next;
+    }
+
+    virNWFilterRuleDefFixup(ret);
+
+cleanup:
+    VIR_FREE(prio);
+    VIR_FREE(action);
+    VIR_FREE(direction);
+
+    return ret;
+
+err_exit:
+    virNWFilterRuleDefFree(ret);
+    ret = NULL;
+    goto cleanup;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParseXML(virConnectPtr conn,
+                       xmlXPathContextPtr ctxt) {
+    virNWFilterDefPtr ret;
+    xmlNodePtr curr = ctxt->node;
+    char *uuid = NULL;
+    char *chain = NULL;
+    virNWFilterEntryPtr entry;
+
+    if (VIR_ALLOC(ret) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    ret->name = virXPathString("string(./@name)", ctxt);
+    if (!ret->name) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                               "%s", _("filter has no name"));
+        goto cleanup;
+    }
+
+    ret->chainsuffix = VIR_NWFILTER_CHAINSUFFIX_ROOT;
+    chain = virXPathString("string(./@chain)", ctxt);
+    if (chain) {
+        if ((ret->chainsuffix =
+             virNWFilterChainSuffixTypeFromString(chain)) < 0) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                   _("unknown chain suffix '%s'"), chain);
+            goto cleanup;
+        }
+    }
+
+    uuid = virXPathString("string(./uuid)", ctxt);
+    if (uuid == NULL) {
+        if (virUUIDGenerate(ret->uuid) < 0) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  "%s", _("unable to generate uuid"));
+            goto cleanup;
+        }
+    } else {
+        if (virUUIDParse(uuid, ret->uuid) < 0) {
+            virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+                                  "%s", _("malformed uuid element"));
+            goto cleanup;
+        }
+        VIR_FREE(uuid);
+    }
+
+    curr = curr->children;
+
+    while (curr != NULL) {
+        if (curr->type == XML_ELEMENT_NODE) {
+            if (VIR_ALLOC(entry) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            /* ignore malformed rule and include elements */
+            if (xmlStrEqual(curr->name, BAD_CAST "rule"))
+                entry->rule = virNWFilterRuleParse(conn, curr);
+            else if (xmlStrEqual(curr->name, BAD_CAST "filterref"))
+                entry->include = virNWFilterIncludeParse(conn, curr);
+
+            if (entry->rule || entry->include) {
+                if (VIR_REALLOC_N(ret->filterEntries, ret->nentries+1) < 0) {
+                    VIR_FREE(entry);
+                    virReportOOMError();
+                    goto cleanup;
+                }
+                ret->filterEntries[ret->nentries++] = entry;
+            } else
+                VIR_FREE(entry);
+        }
+        curr = curr->next;
+    }
+
+    VIR_FREE(chain);
+
+    return ret;
+
+ cleanup:
+    VIR_FREE(chain);
+    VIR_FREE(uuid);
+    return NULL;
+}
+
+
+/* Called from SAX on parsing errors in the XML. */
+static void
+catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+    if (ctxt) {
+        virConnectPtr conn = ctxt->_private;
+
+        if (conn &&
+            conn->err.code == VIR_ERR_NONE &&
+            ctxt->lastError.level == XML_ERR_FATAL &&
+            ctxt->lastError.message != NULL) {
+            virNWFilterReportError(conn, VIR_ERR_XML_DETAIL,
+                                   _("at line %d: %s"),
+                                   ctxt->lastError.line,
+                                   ctxt->lastError.message);
+        }
+    }
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseNode(virConnectPtr conn,
+                        xmlDocPtr xml,
+                        xmlNodePtr root) {
+    xmlXPathContextPtr ctxt = NULL;
+    virNWFilterDefPtr def = NULL;
+
+    if (STRNEQ((const char *)root->name, "filter")) {
+        virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+                               "%s",
+                               _("unknown root element for nw filter pool"));
+        goto cleanup;
+    }
+
+    ctxt = xmlXPathNewContext(xml);
+    if (ctxt == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    ctxt->node = root;
+    def = virNWFilterDefParseXML(conn, ctxt);
+
+cleanup:
+    xmlXPathFreeContext(ctxt);
+    return def;
+}
+
+
+static virNWFilterDefPtr
+virNWFilterDefParse(virConnectPtr conn,
+                     const char *xmlStr,
+                     const char *filename) {
+    virNWFilterDefPtr ret = NULL;
+    xmlParserCtxtPtr pctxt;
+    xmlDocPtr xml = NULL;
+    xmlNodePtr node = NULL;
+
+    /* Set up a parser context so we can catch the details of XML errors. */
+    pctxt = xmlNewParserCtxt ();
+    if (!pctxt || !pctxt->sax)
+        goto cleanup;
+    pctxt->sax->error = catchXMLError;
+    pctxt->_private = conn;
+
+    if (conn) virResetError (&conn->err);
+    if (filename) {
+        xml = xmlCtxtReadFile (pctxt, filename, NULL,
+                               XML_PARSE_NOENT | XML_PARSE_NONET |
+                               XML_PARSE_NOWARNING);
+    } else {
+        xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr,
+                              "nwfilter.xml", NULL,
+                              XML_PARSE_NOENT | XML_PARSE_NONET |
+                              XML_PARSE_NOWARNING);
+    }
+
+    if (!xml) {
+        if (conn && conn->err.code == VIR_ERR_NONE)
+              virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+                                     "%s",_("failed to parse xml document"));
+        goto cleanup;
+    }
+
+    node = xmlDocGetRootElement(xml);
+    if (node == NULL) {
+        virNWFilterReportError(conn, VIR_ERR_XML_ERROR,
+                               "%s", _("missing root element"));
+        goto cleanup;
+    }
+
+    ret = virNWFilterDefParseNode(conn, xml, node);
+
+    xmlFreeParserCtxt (pctxt);
+    xmlFreeDoc(xml);
+
+    return ret;
+
+ cleanup:
+    xmlFreeParserCtxt (pctxt);
+    xmlFreeDoc(xml);
+    return NULL;
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseString(virConnectPtr conn,
+                             const char *xmlStr)
+{
+    return virNWFilterDefParse(conn, xmlStr, NULL);
+}
+
+
+virNWFilterDefPtr
+virNWFilterDefParseFile(virConnectPtr conn,
+                        const char *filename)
+{
+    return virNWFilterDefParse(conn, NULL, filename);
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+                            const unsigned char *uuid)
+{
+    unsigned int i;
+
+    for (i = 0 ; i < pools->count ; i++) {
+        virNWFilterPoolObjLock(pools->objs[i]);
+        if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
+            return pools->objs[i];
+        virNWFilterPoolObjUnlock(pools->objs[i]);
+    }
+
+    return NULL;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+                            const char *name)
+{
+    unsigned int i;
+
+    for (i = 0 ; i < pools->count ; i++) {
+        virNWFilterPoolObjLock(pools->objs[i]);
+        if (STREQ(pools->objs[i]->def->name, name))
+            return pools->objs[i];
+        virNWFilterPoolObjUnlock(pools->objs[i]);
+    }
+
+    return NULL;
+}
+
+
+int virNWFilterSaveXML(virConnectPtr conn,
+                       const char *configDir,
+                       virNWFilterDefPtr def,
+                       const char *xml)
+{
+    char *configFile = NULL;
+    int fd = -1, ret = -1;
+    size_t towrite;
+    int err;
+
+    if ((configFile = virNWFilterConfigFile(conn, configDir, def->name)) == NULL)
+        goto cleanup;
+
+    if ((err = virFileMakePath(configDir))) {
+        virReportSystemError(err,
+                             _("cannot create config directory '%s'"),
+                             configDir);
+        goto cleanup;
+    }
+
+    if ((fd = open(configFile,
+                   O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR )) < 0) {
+        virReportSystemError(errno,
+                             _("cannot create config file '%s'"),
+                             configFile);
+        goto cleanup;
+    }
+
+    towrite = strlen(xml);
+    if (safewrite(fd, xml, towrite) < 0) {
+        virReportSystemError(errno,
+                             _("cannot write config file '%s'"),
+                             configFile);
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        virReportSystemError(errno,
+                             _("cannot save config file '%s'"),
+                             configFile);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (fd != -1)
+        close(fd);
+
+    VIR_FREE(configFile);
+
+    return ret;
+}
+
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+                          const char *configDir,
+                          virNWFilterDefPtr def)
+{
+    int ret = -1;
+    char *xml;
+
+    if (!(xml = virNWFilterDefFormat(conn, def)))
+        goto cleanup;
+
+    if (virNWFilterSaveXML(conn, configDir, def, xml))
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    VIR_FREE(xml);
+    return ret;
+}
+
+
+static int
+_virNWFilterDefLoopDetect(virConnectPtr conn,
+                          virNWFilterPoolObjListPtr pools,
+                          virNWFilterDefPtr def,
+                          const char *filtername)
+{
+    int rc = 0;
+    int i;
+    virNWFilterEntryPtr entry;
+    virNWFilterPoolObjPtr obj;
+
+    if (!def)
+        return 0;
+
+    for (i = 0; i < def->nentries; i++) {
+        entry = def->filterEntries[i];
+        if (entry->include) {
+
+            if (STREQ(filtername, entry->include->filterref)) {
+                rc = 1;
+                break;
+            }
+
+            obj = virNWFilterPoolObjFindByName(pools,
+                                               entry->include->filterref);
+            if (obj) {
+                rc = _virNWFilterDefLoopDetect(conn,
+                                               pools,
+                                               obj->def, filtername);
+
+                virNWFilterPoolObjUnlock(obj);
+                if (rc)
+                   break;
+            }
+        }
+    }
+
+    return rc;
+}
+
+
+/*
+ * virNWFilterDefLoopDetect:
+ * @conn: pointer to virConnect object
+ * @pools : the pools to search
+ * @def : the filter definiton that may add a loop and is to be tested
+ *
+ * Detect a loop introduced through the filters being able to
+ * reference each other.
+ *
+ * Returns 0 in case no loop was detected, 1 otherwise.
+ */
+static int
+virNWFilterDefLoopDetect(virConnectPtr conn,
+                         virNWFilterPoolObjListPtr pools,
+                         virNWFilterDefPtr def)
+{
+    return _virNWFilterDefLoopDetect(conn, pools, def, def->name);
+}
+
+int nCallbackDriver;
+#define MAX_CALLBACK_DRIVER 10
+static virNWFilterCallbackDriverPtr callbackDrvArray[MAX_CALLBACK_DRIVER];
+
+void
+virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr cbd)
+{
+    if (nCallbackDriver < MAX_CALLBACK_DRIVER) {
+        callbackDrvArray[nCallbackDriver++] = cbd;
+    }
+}
+
+
+struct cbStruct {
+    virConnectPtr conn;
+    int doUpdate;
+    int err;
+};
+
+static void
+virNWFilterDomainFWUpdateCB(void *payload,
+                            const char *name 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)) {
+                if (cb->doUpdate)
+                    cb->err = virNWFilterUpdateInstantiateFilter(cb->conn,
+                                                                 net);
+                else
+                    cb->err = virNWFilterRollbackUpdateFilter(cb->conn, net);
+                if (cb->err)
+                    break;
+            }
+        }
+    }
+
+    virDomainObjUnlock(obj);
+}
+
+
+static int
+virNWFilterTriggerVMFilterRebuild(virConnectPtr conn)
+{
+    int i;
+    int err;
+    struct cbStruct cb = {
+        .conn = conn,
+        .err = 0,
+        .doUpdate = 1,
+    };
+
+    for (i = 0; i < nCallbackDriver; i++) {
+        callbackDrvArray[i]->vmFilterRebuild(conn,
+                                             virNWFilterDomainFWUpdateCB,
+                                             &cb);
+    }
+
+    err = cb.err;
+
+    if (err) {
+        cb.doUpdate = 0; // rollback
+        cb.err = 0;
+
+        for (i = 0; i < nCallbackDriver; i++)
+            callbackDrvArray[i]->vmFilterRebuild(conn,
+                                                 virNWFilterDomainFWUpdateCB,
+                                                 &cb);
+    }
+
+    return err;
+}
+
+
+int
+virNWFilterTestUnassignDef(virConnectPtr conn,
+                           virNWFilterPoolObjPtr pool)
+{
+    int rc = 0;
+
+    virNWFilterLockFilterUpdates();
+
+    pool->wantRemoved = 1;
+    // trigger the update on VMs referencing the filter
+    if (virNWFilterTriggerVMFilterRebuild(conn))
+        rc = 1;
+
+    pool->wantRemoved = 0;
+    virNWFilterUnlockFilterUpdates();
+    return rc;
+}
+
+
+virNWFilterPoolObjPtr
+virNWFilterPoolObjAssignDef(virConnectPtr conn,
+                           virNWFilterPoolObjListPtr pools,
+                           virNWFilterDefPtr def)
+{
+    virNWFilterPoolObjPtr pool;
+
+    if (virNWFilterDefLoopDetect(conn, pools, def)) {
+        virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+                              "%s", _("filter would introduce loop"));
+        return NULL;
+    }
+
+    if ((pool = virNWFilterPoolObjFindByName(pools, def->name))) {
+        virNWFilterLockFilterUpdates();
+        pool->newDef = def;
+        // trigger the update on VMs referencing the filter
+        if (virNWFilterTriggerVMFilterRebuild(conn)) {
+            pool->newDef = NULL;
+            virNWFilterUnlockFilterUpdates();
+            virNWFilterPoolObjUnlock(pool);
+            return NULL;
+        }
+
+        virNWFilterDefFree(pool->def);
+        pool->def = def;
+        pool->newDef = NULL;
+        virNWFilterUnlockFilterUpdates();
+        return pool;
+    }
+
+    if (VIR_ALLOC(pool) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    if (virRecursiveMutexInit(&pool->lock) < 0) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("cannot initialize mutex"));
+        VIR_FREE(pool);
+        return NULL;
+    }
+    virNWFilterPoolObjLock(pool);
+    pool->active = 0;
+    pool->def = def;
+
+    if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
+        pool->def = NULL;
+        virNWFilterPoolObjUnlock(pool);
+        virNWFilterPoolObjFree(pool);
+        virReportOOMError();
+        return NULL;
+    }
+    pools->objs[pools->count++] = pool;
+
+    return pool;
+}
+
+
+static virNWFilterPoolObjPtr
+virNWFilterPoolObjLoad(virConnectPtr conn,
+                      virNWFilterPoolObjListPtr pools,
+                      const char *file,
+                      const char *path)
+{
+    virNWFilterDefPtr def;
+    virNWFilterPoolObjPtr pool;
+
+    if (!(def = virNWFilterDefParseFile(conn, path))) {
+        return NULL;
+    }
+
+    if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+        virNWFilterError(conn, VIR_ERR_INVALID_NWFILTER,
+            "NWFilter pool config filename '%s' does not match pool name '%s'",
+                      path, def->name);
+        virNWFilterDefFree(def);
+        return NULL;
+    }
+
+    if (!(pool = virNWFilterPoolObjAssignDef(conn, pools, def))) {
+        virNWFilterDefFree(def);
+        return NULL;
+    }
+
+    pool->configFile = strdup(path);
+    if (pool->configFile == NULL) {
+        virReportOOMError();
+        virNWFilterDefFree(def);
+        return NULL;
+    }
+
+    return pool;
+}
+
+
+int
+virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+                             virNWFilterPoolObjListPtr pools,
+                             const char *configDir)
+{
+    DIR *dir;
+    struct dirent *entry;
+
+    if (!(dir = opendir(configDir))) {
+        if (errno == ENOENT) {
+            return 0;
+        }
+        virReportSystemError(errno, _("Failed to open dir '%s'"),
+                             configDir);
+        return -1;
+    }
+
+    while ((entry = readdir(dir))) {
+        char path[PATH_MAX];
+        virNWFilterPoolObjPtr pool;
+
+        if (entry->d_name[0] == '.')
+            continue;
+
+        if (!virFileHasSuffix(entry->d_name, ".xml"))
+            continue;
+
+        if (virFileBuildPath(configDir, entry->d_name,
+                             NULL, path, PATH_MAX) < 0) {
+            virNWFilterError(conn, VIR_ERR_INTERNAL_ERROR,
+                            "Config filename '%s/%s' is too long",
+                            configDir, entry->d_name);
+            continue;
+        }
+
+        pool = virNWFilterPoolObjLoad(conn, pools, entry->d_name, path);
+        if (pool)
+            virNWFilterPoolObjUnlock(pool);
+    }
+
+    closedir(dir);
+
+    return 0;
+}
+
+
+int
+virNWFilterPoolObjSaveDef(virConnectPtr conn,
+                         virNWFilterDriverStatePtr driver,
+                         virNWFilterPoolObjPtr pool,
+                         virNWFilterDefPtr def)
+{
+    char *xml;
+    int fd = -1, ret = -1;
+    ssize_t towrite;
+
+    if (!pool->configFile) {
+        int err;
+        char path[PATH_MAX];
+
+        if ((err = virFileMakePath(driver->configDir))) {
+            virReportSystemError(err,
+                                 _("cannot create config directory %s"),
+                                 driver->configDir);
+            return -1;
+        }
+
+        if (virFileBuildPath(driver->configDir, def->name, ".xml",
+                             path, sizeof(path)) < 0) {
+            virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  "%s", _("cannot construct config file path"));
+            return -1;
+        }
+        if (!(pool->configFile = strdup(path))) {
+            virReportOOMError();
+            return -1;
+        }
+    }
+
+    if (!(xml = virNWFilterDefFormat(conn, def))) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("failed to generate XML"));
+        return -1;
+    }
+
+    if ((fd = open(pool->configFile,
+                   O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR )) < 0) {
+        virReportSystemError(errno,
+                             _("cannot create config file %s"),
+                             pool->configFile);
+        goto cleanup;
+    }
+
+    towrite = strlen(xml);
+    if (safewrite(fd, xml, towrite) != towrite) {
+        virReportSystemError(errno,
+                             _("cannot write config file %s"),
+                             pool->configFile);
+        goto cleanup;
+    }
+
+    if (close(fd) < 0) {
+        virReportSystemError(errno,
+                             _("cannot save config file %s"),
+                             pool->configFile);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (fd != -1)
+        close(fd);
+
+    VIR_FREE(xml);
+
+    return ret;
+}
+
+
+int
+virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+                           virNWFilterPoolObjPtr pool)
+{
+    if (!pool->configFile) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("no config file for %s"), pool->def->name);
+        return -1;
+    }
+
+    if (unlink(pool->configFile) < 0) {
+        virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("cannot remove config for %s"),
+                              pool->def->name);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static void
+virNWIPAddressFormat(virBufferPtr buf, nwIPAddressPtr ipaddr)
+{
+    if (!ipaddr->isIPv6) {
+        virBufferVSprintf(buf, "%d.%d.%d.%d",
+                          ipaddr->addr.ipv4Addr[0],
+                          ipaddr->addr.ipv4Addr[1],
+                          ipaddr->addr.ipv4Addr[2],
+                          ipaddr->addr.ipv4Addr[3]);
+    } else {
+        virBufferAddLit(buf, "MISSING IPv6 ADDRESS FORMATTER");
+    }
+}
+
+
+static void
+virNWFilterRuleDefDetailsFormat(virConnectPtr conn,
+                                virBufferPtr buf,
+                                const char *type,
+                                const virXMLAttr2Struct *att,
+                                virNWFilterRuleDefPtr def)
+{
+    int i, j;
+    bool typeShown = 0;
+    bool neverShown = 1;
+    enum match {
+        MATCH_NONE = 0,
+        MATCH_YES,
+        MATCH_NO
+    } matchShown = MATCH_NONE;
+    nwItemDesc *item;
+
+    while (att[i].name) {
+        item = (nwItemDesc *)((char *)def + att[i].dataIdx);
+        enum virNWFilterEntryItemFlags flags = item->flags;
+        void *storage_ptr;
+        if ((flags & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)) {
+            if (!typeShown) {
+                virBufferVSprintf(buf, "    <%s", type);
+                typeShown = 1;
+                neverShown = 0;
+            }
+
+            if ((flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG)) {
+                if (matchShown == MATCH_NONE) {
+                    virBufferAddLit(buf, " match='no'");
+                    matchShown = MATCH_NO;
+                } else if (matchShown == MATCH_YES) {
+                    virBufferAddLit(buf, "/>\n");
+                    typeShown = 0;
+                    matchShown = MATCH_NONE;
+                    continue;
+                }
+            } else {
+                if (matchShown == MATCH_NO) {
+                    virBufferAddLit(buf, "/>\n");
+                    typeShown = 0;
+                    matchShown = MATCH_NONE;
+                    continue;
+                }
+                matchShown = MATCH_YES;
+            }
+
+            virBufferVSprintf(buf, " %s='",
+                              att[i].name);
+            if (att[i].formatter) {
+               if (!att[i].formatter(buf, def)) {
+                  virNWFilterReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                         _("formatter for %s %s reported error"),
+                                         type,
+                                         att[i].name);
+                   goto err_exit;
+               }
+            } else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
+                virBufferVSprintf(buf, "$%s", item->var);
+            } else {
+               switch (att[i].datatype) {
+
+               case DATATYPE_IPMASK:
+                   // display all masks in CIDR format
+               case DATATYPE_UINT8:
+                   storage_ptr = &item->u.u8;
+                   virBufferVSprintf(buf, "%d", *(uint8_t *)storage_ptr);
+               break;
+
+               case DATATYPE_UINT16:
+                   storage_ptr = &item->u.u16;
+                   virBufferVSprintf(buf, "%d", *(uint16_t *)storage_ptr);
+               break;
+
+               case DATATYPE_IPADDR:
+                   storage_ptr = &item->u.ipaddr;
+                   virNWIPAddressFormat(buf,
+                                        (nwIPAddressPtr)storage_ptr);
+               break;
+
+               case DATATYPE_MACMASK:
+               case DATATYPE_MACADDR:
+                   storage_ptr = &item->u.macaddr;
+                   for (j = 0; j < 6; j++)
+                       virBufferVSprintf(buf, "%02x%s",
+                                      ((nwMACAddressPtr)storage_ptr)->addr[j],
+                                      (j < 5) ? ":" : "");
+               break;
+
+               case DATATYPE_STRING:
+               default:
+                   virBufferVSprintf(buf,
+                                     "UNSUPPORTED DATATYPE 0x%02x\n",
+                                     att[i].datatype);
+               }
+            }
+            virBufferAddLit(buf, "'");
+        }
+        i++;
+    }
+    if (typeShown)
+       virBufferAddLit(buf, "/>\n");
+
+    if (neverShown)
+       virBufferVSprintf(buf,
+                         "    <%s/>\n", type);
+
+err_exit:
+    return;
+}
+
+
+static char *
+virNWFilterRuleDefFormat(virConnectPtr conn,
+                         virNWFilterRuleDefPtr def)
+{
+    int i;
+    virBuffer buf  = VIR_BUFFER_INITIALIZER;
+    virBuffer buf2 = VIR_BUFFER_INITIALIZER;
+    char *data;
+
+    virBufferVSprintf(&buf, "  <rule action='%s' direction='%s' priority='%d'",
+                      virNWFilterRuleActionTypeToString(def->action),
+                      virNWFilterRuleDirectionTypeToString(def->tt),
+                      def->priority);
+
+    i = 0;
+    while (virAttr[i].id) {
+        if (virAttr[i].prtclType == def->prtclType) {
+            virNWFilterRuleDefDetailsFormat(conn,
+                                            &buf2,
+                                            virAttr[i].id,
+                                            virAttr[i].att,
+                                            def);
+            break;
+        }
+        i++;
+    }
+
+    if (virBufferError(&buf2))
+        goto no_memory;
+
+    data = virBufferContentAndReset(&buf2);
+
+    if (data) {
+        virBufferAddLit(&buf, ">\n");
+        virBufferVSprintf(&buf, "%s  </rule>\n", data);
+        VIR_FREE(data);
+    } else
+        virBufferAddLit(&buf, "/>\n");
+
+    if (virBufferError(&buf))
+        goto no_memory;
+
+    return virBufferContentAndReset(&buf);
+
+no_memory:
+    virReportOOMError();
+    virBufferFreeAndReset(&buf);
+    virBufferFreeAndReset(&buf2);
+
+    return NULL;
+}
+
+
+static char *
+virNWFilterIncludeDefFormat(virNWFilterIncludeDefPtr inc)
+{
+    char *attrs;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferVSprintf(&buf,"  <filterref filter='%s'",
+                      inc->filterref);
+
+    attrs = virNWFilterFormatParamAttributes(inc->params, "    ");
+
+    if (!attrs || strlen(attrs) <= 1)
+        virBufferAddLit(&buf, "/>\n");
+    else
+        virBufferVSprintf(&buf, ">\n%s  </filterref>\n", attrs);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        virBufferFreeAndReset(&buf);
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+static char *
+virNWFilterEntryFormat(virConnectPtr conn,
+                       virNWFilterEntryPtr entry)
+{
+    if (entry->rule)
+        return virNWFilterRuleDefFormat(conn, entry->rule);
+    return virNWFilterIncludeDefFormat(entry->include);
+}
+
+
+char *
+virNWFilterDefFormat(virConnectPtr conn,
+                     virNWFilterDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    int i;
+    char *xml;
+
+    virBufferVSprintf(&buf, "<filter name='%s' chain='%s'",
+                      def->name,
+                      virNWFilterChainSuffixTypeToString(def->chainsuffix));
+    virBufferAddLit(&buf, ">\n");
+
+    virUUIDFormat(def->uuid, uuid);
+    virBufferVSprintf(&buf,"  <uuid>%s</uuid>\n", uuid);
+
+    for (i = 0; i < def->nentries; i++) {
+        xml = virNWFilterEntryFormat(conn, def->filterEntries[i]);
+        if (!xml)
+            goto err_exit;
+        virBufferVSprintf(&buf, "%s", xml);
+        VIR_FREE(xml);
+    }
+
+    virBufferAddLit(&buf, "</filter>\n");
+
+    if (virBufferError(&buf))
+        goto no_memory;
+
+    return virBufferContentAndReset(&buf);
+
+ no_memory:
+    virReportOOMError();
+
+ err_exit:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *virNWFilterConfigFile(virConnectPtr conn ATTRIBUTE_UNUSED,
+                            const char *dir,
+                            const char *name)
+{
+    char *ret = NULL;
+
+    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return ret;
+}
+
+
+int virNWFilterConfLayerInit(void) {
+    if (virMutexInit(&updateMutex))
+        return 1;
+
+    if (regcomp(&regex_nam, "^[a-zA-Z0-9_]+$"  , REG_NOSUB|REG_EXTENDED) != 0)
+        return -1;
+
+    if (regcomp(&regex_val, "^[a-zA-Z0-9_.:]+$", REG_NOSUB|REG_EXTENDED) != 0) {
+        regfree(&regex_nam);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+void virNWFilterConfLayerShutdown(void) {
+    regfree(&regex_nam);
+    regfree(&regex_val);
+}
+
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj)
+{
+    virMutexLock(&obj->lock);
+}
+
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj)
+{
+    virMutexUnlock(&obj->lock);
+}
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -0,0 +1,472 @@
+/*
+ * nwfilter_conf.h: network filter XML processing
+ *                  (derived from storage_conf.h)
+ *
+ * Copyright (C) 2006-2010 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * 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@xxxxxxxxxx>
+ */
+#ifndef NWFILTER_CONF_H
+#define NWFILTER_CONF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "internal.h"
+#include "util.h"
+#include "hash.h"
+#include "xml.h"
+
+/**
+ * Chain suffix size is:
+ * max. user define table name length -
+ *   sizeof("FO-") -
+ *   max. interface name size -
+ *   sizeof("-") -
+ *   terminating '0' =
+ * 32-3-15-1-1 = 12
+ */
+#define MAX_CHAIN_SUFFIX_SIZE	12
+
+
+enum virNWFilterEntryItemFlags {
+    NWFILTER_ENTRY_ITEM_FLAG_EXISTS   = 1 << 0,
+    NWFILTER_ENTRY_ITEM_FLAG_IS_NEG   = 1 << 1,
+    NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR  = 1 << 2,
+};
+
+
+#define HAS_ENTRY_ITEM(data) \
+  (((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)
+
+#define ENTRY_GET_NEG_SIGN(data) \
+  ((((data)->flags) & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) ? "!" : "")
+
+// datatypes appearing in rule attributes
+enum attrDatatype {
+    DATATYPE_UINT16           = (1 << 0),
+    DATATYPE_UINT8            = (1 << 1),
+    DATATYPE_MACADDR          = (1 << 2),
+    DATATYPE_MACMASK          = (1 << 3),
+    DATATYPE_IPADDR           = (1 << 4),
+    DATATYPE_IPMASK           = (1 << 5),
+    DATATYPE_STRING           = (1 << 6),
+
+    DATATYPE_LAST             = (1 << 7),
+};
+
+
+typedef struct _nwMACAddress nwMACAddress;
+typedef nwMACAddress *nwMACAddressPtr;
+struct _nwMACAddress {
+    unsigned char addr[6];
+};
+
+
+typedef struct _nwIPAddress nwIPAddress;
+typedef nwIPAddress *nwIPAddressPtr;
+struct _nwIPAddress {
+    int isIPv6;
+    union {
+        unsigned char ipv4Addr[4];
+        /* unsigned char ipv6Addr[16]; future :-) */
+    } addr;
+};
+
+
+typedef struct _nwItemDesc nwItemDesc;
+typedef nwItemDesc *nwItemDescPtr;
+struct _nwItemDesc {
+    enum virNWFilterEntryItemFlags flags;
+    char *var;
+    enum attrDatatype datatype;
+    union {
+        nwMACAddress macaddr;
+        nwIPAddress  ipaddr;
+        uint8_t      u8;
+        uint16_t     u16;
+        char         protocolID[10];
+    } u;
+};
+
+
+typedef struct _ethHdrFilterDef  ethHdrFilterDef;
+typedef ethHdrFilterDef *ethHdrFilterDefPtr;
+struct _ethHdrFilterDef {
+    nwItemDesc dataSrcMACAddr;
+    nwItemDesc dataSrcMACMask;
+    nwItemDesc dataDstMACAddr;
+    nwItemDesc dataDstMACMask;
+    nwItemDesc dataProtocolID;
+    nwItemDesc dataPriority;
+    nwItemDesc dataVLANID;
+};
+
+
+typedef struct _arpHdrFilterDef  arpHdrFilterDef;
+typedef arpHdrFilterDef *arpHdrFilterDefPtr;
+struct _arpHdrFilterDef {
+    nwItemDesc dataHWType;
+    nwItemDesc dataProtocolType;
+    nwItemDesc dataOpcode;
+    nwItemDesc dataSrcMACAddr;
+    nwItemDesc dataSrcIPAddr;
+    nwItemDesc dataDstMACAddr;
+    nwItemDesc dataDstIPAddr;
+};
+
+
+typedef struct _ipHdrDataDef  ipHdrDataDef;
+typedef ipHdrDataDef *ipHdrDataDefPtr;
+struct _ipHdrDataDef {
+    nwItemDesc dataIPVersion;
+    nwItemDesc dataSrcAddr;
+    nwItemDesc dataSrcMask;
+    nwItemDesc dataDstAddr;
+    nwItemDesc dataDstMask;
+    nwItemDesc dataProtocolID;
+};
+
+
+typedef struct _portDataDef portDataDef;
+typedef portDataDef *portDataDefPtr;
+struct _portDataDef {
+    nwItemDesc dataSrcPortStart;
+    nwItemDesc dataSrcPortEnd;
+    nwItemDesc dataDstPortStart;
+    nwItemDesc dataDstPortEnd;
+};
+
+
+typedef struct _ipHdrFilterDef  ipHdrFilterDef;
+typedef ipHdrFilterDef *ipHdrFilterDefPtr;
+struct _ipHdrFilterDef {
+    ipHdrDataDef ipHdr;
+    portDataDef  portData;
+    nwItemDesc dataDSCP;
+};
+
+
+enum virNWFilterRuleActionType {
+    VIR_NWFILTER_RULE_ACTION_DROP = 0,
+    VIR_NWFILTER_RULE_ACTION_ACCEPT,
+
+    VIR_NWFILTER_RULE_ACTION_LAST,
+};
+
+enum virNWFilterRuleDirectionType {
+    VIR_NWFILTER_RULE_DIRECTION_IN = 0,
+    VIR_NWFILTER_RULE_DIRECTION_OUT,
+    VIR_NWFILTER_RULE_DIRECTION_INOUT,
+
+    VIR_NWFILTER_RULE_DIRECTION_LAST,
+};
+
+enum virNWFilterChainPolicyType {
+    VIR_NWFILTER_CHAIN_POLICY_ACCEPT = 0,
+    VIR_NWFILTER_CHAIN_POLICY_DROP,
+
+    VIR_NWFILTER_CHAIN_POLICY_LAST,
+};
+
+enum virNWFilterRuleProtocolType {
+    VIR_NWFILTER_RULE_PROTOCOL_NONE = 0,
+    VIR_NWFILTER_RULE_PROTOCOL_MAC,
+    VIR_NWFILTER_RULE_PROTOCOL_ARP,
+    VIR_NWFILTER_RULE_PROTOCOL_IP,
+};
+
+enum virNWFilterEbtablesTableType {
+    VIR_NWFILTER_EBTABLES_TABLE_FILTER = 0,
+    VIR_NWFILTER_EBTABLES_TABLE_NAT,
+    VIR_NWFILTER_EBTABLES_TABLE_BROUTE,
+
+    VIR_NWFILTER_EBTABLES_TABLE_LAST,
+};
+
+
+#define MAX_RULE_PRIORITY  1000
+
+
+typedef struct _virNWFilterRuleDef  virNWFilterRuleDef;
+typedef virNWFilterRuleDef *virNWFilterRuleDefPtr;
+struct _virNWFilterRuleDef {
+    unsigned int priority;
+    int action; /*enum virNWFilterRuleActionType*/
+    int tt; /*enum virNWFilterRuleDirectionType*/
+    enum virNWFilterRuleProtocolType prtclType;
+    union {
+        ethHdrFilterDef  ethHdrFilter;
+        arpHdrFilterDef  arpHdrFilter;
+        ipHdrFilterDef   ipHdrFilter;
+    } p;
+
+    int nvars;
+    char **vars;
+};
+
+
+typedef struct _virNWFilterHashTable virNWFilterHashTable;
+typedef virNWFilterHashTable *virNWFilterHashTablePtr;
+struct _virNWFilterHashTable {
+    virHashTablePtr hashTable;
+
+    int nNames;
+    char **names;
+};
+
+
+typedef struct _virNWFilterIncludeDef virNWFilterIncludeDef;
+typedef virNWFilterIncludeDef *virNWFilterIncludeDefPtr;
+struct _virNWFilterIncludeDef {
+    char *filterref;
+    virNWFilterHashTablePtr params;
+};
+
+
+typedef struct _virNWFilterEntry virNWFilterEntry;
+typedef virNWFilterEntry *virNWFilterEntryPtr;
+struct _virNWFilterEntry {
+    virNWFilterRuleDef    *rule;
+    virNWFilterIncludeDef *include;
+};
+
+enum virNWFilterChainSuffixType {
+    VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
+    VIR_NWFILTER_CHAINSUFFIX_ARP,
+    VIR_NWFILTER_CHAINSUFFIX_IPv4,
+
+    VIR_NWFILTER_CHAINSUFFIX_LAST,
+};
+
+
+typedef struct _virNWFilterDef virNWFilterDef;
+typedef virNWFilterDef *virNWFilterDefPtr;
+
+struct _virNWFilterDef {
+    char *name;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+
+    int chainsuffix; /*enum virNWFilterChainSuffixType */
+
+    int nentries;
+    virNWFilterEntryPtr *filterEntries;
+};
+
+
+typedef struct _virNWFilterPoolObj virNWFilterPoolObj;
+typedef virNWFilterPoolObj *virNWFilterPoolObjPtr;
+
+struct _virNWFilterPoolObj {
+    virMutex lock;
+
+    char *configFile;
+    int active;
+    int wantRemoved;
+
+    virNWFilterDefPtr def;
+    virNWFilterDefPtr newDef;
+};
+
+
+typedef struct _virNWFilterPoolObjList virNWFilterPoolObjList;
+typedef virNWFilterPoolObjList *virNWFilterPoolObjListPtr;
+struct _virNWFilterPoolObjList {
+    unsigned int count;
+    virNWFilterPoolObjPtr *objs;
+};
+
+
+typedef struct _virNWFilterDriverState virNWFilterDriverState;
+typedef virNWFilterDriverState *virNWFilterDriverStatePtr;
+struct _virNWFilterDriverState {
+    virMutex lock;
+
+    virNWFilterPoolObjList pools;
+
+    char *configDir;
+};
+
+
+typedef struct _virNWFilterTechDriver virNWFilterTechDriver;
+typedef virNWFilterTechDriver *virNWFilterTechDriverPtr;
+
+
+typedef struct _virNWFilterRuleInst virNWFilterRuleInst;
+typedef virNWFilterRuleInst *virNWFilterRuleInstPtr;
+struct _virNWFilterRuleInst {
+   int ndata;
+   void **data;
+   virNWFilterTechDriverPtr techdriver;
+};
+
+
+enum virDomainNetType;
+
+typedef int (*virNWFilterRuleCreateInstance)(virConnectPtr conn,
+                                             enum virDomainNetType nettype,
+                                             virNWFilterDefPtr filter,
+                                             virNWFilterRuleDefPtr rule,
+                                             const char *ifname,
+                                             virNWFilterHashTablePtr vars,
+                                             virNWFilterRuleInstPtr res);
+
+typedef int (*virNWFilterRuleApplyRules)(virConnectPtr conn,
+                                         const char *ifname,
+                                         int nruleInstances,
+                                         void **_inst);
+
+typedef int (*virNWFilterRuleRemoveRules)(virConnectPtr conn,
+                                          const char *ifname,
+                                          int nruleInstances,
+                                          void **_inst);
+
+typedef int (*virNWFilterRuleAllTeardown)(const char *ifname);
+
+typedef int (*virNWFilterRuleFreeInstanceData)(void * _inst);
+
+typedef int (*virNWFilterRuleDisplayInstanceData)(virConnectPtr conn,
+                                                  void *_inst);
+
+
+struct _virNWFilterTechDriver {
+    const char *name;
+
+    virNWFilterRuleCreateInstance createRuleInstance;
+    virNWFilterRuleApplyRules applyRules;
+    virNWFilterRuleRemoveRules removeRules;
+    virNWFilterRuleAllTeardown allTeardown;
+    virNWFilterRuleFreeInstanceData freeRuleInstance;
+    virNWFilterRuleDisplayInstanceData displayRuleInstance;
+};
+
+
+virNWFilterHashTablePtr virNWFilterParseParamAttributes(xmlNodePtr cur);
+char * virNWFilterFormatParamAttributes(virNWFilterHashTablePtr table,
+                                        const char *indent);
+
+virNWFilterHashTablePtr virNWFilterHashTableCreate(int n);
+void virNWFilterHashTableFree(virNWFilterHashTablePtr table);
+int virNWFilterHashTablePut(virNWFilterHashTablePtr table,
+                            const char *name,
+                            char *val,
+                            int freeName);
+int virNWFilterHashTableRemoveEntry(virNWFilterHashTablePtr table,
+                                    const char *name);
+int virNWFilterHashTablePutAll(virConnectPtr conn,
+                               virNWFilterHashTablePtr src,
+                               virNWFilterHashTablePtr dest);
+
+void virNWFilterRuleDefFree(virNWFilterRuleDefPtr def);
+
+void virNWFilterDefFree(virNWFilterDefPtr def);
+void virNWFilterPoolObjListFree(virNWFilterPoolObjListPtr pools);
+void virNWFilterPoolObjRemove(virNWFilterPoolObjListPtr pools,
+                              virNWFilterPoolObjPtr pool);
+
+void virNWFilterPoolObjFree(virNWFilterPoolObjPtr obj);
+
+virNWFilterPoolObjPtr
+        virNWFilterPoolObjFindByUUID(virNWFilterPoolObjListPtr pools,
+                                     const unsigned char *uuid);
+
+virNWFilterPoolObjPtr
+        virNWFilterPoolObjFindByName(virNWFilterPoolObjListPtr pools,
+                                     const char *name);
+
+
+int virNWFilterPoolObjSaveDef(virConnectPtr conn,
+                              virNWFilterDriverStatePtr driver,
+                              virNWFilterPoolObjPtr pool,
+                              virNWFilterDefPtr def);
+
+int virNWFilterPoolObjDeleteDef(virConnectPtr conn,
+                                virNWFilterPoolObjPtr pool);
+
+virNWFilterPoolObjPtr virNWFilterPoolObjAssignDef(virConnectPtr conn,
+                                                  virNWFilterPoolObjListPtr pools,
+                                                  virNWFilterDefPtr def);
+
+int virNWFilterTestUnassignDef(virConnectPtr conn,
+                               virNWFilterPoolObjPtr pool);
+
+virNWFilterDefPtr virNWFilterDefParseNode(virConnectPtr conn,
+                                          xmlDocPtr xml,
+                                          xmlNodePtr root);
+
+char *virNWFilterDefFormat(virConnectPtr conn,
+                           virNWFilterDefPtr def);
+
+int virNWFilterSaveXML(virConnectPtr conn,
+                       const char *configDir,
+                       virNWFilterDefPtr def,
+                       const char *xml);
+
+int virNWFilterSaveConfig(virConnectPtr conn,
+                          const char *configDir,
+                          virNWFilterDefPtr def);
+
+int virNWFilterPoolLoadAllConfigs(virConnectPtr conn,
+                                  virNWFilterPoolObjListPtr pools,
+                                  const char *configDir);
+
+char *virNWFilterConfigFile(virConnectPtr conn,
+                            const char *dir,
+                            const char *name);
+
+virNWFilterDefPtr virNWFilterDefParseString(virConnectPtr conn,
+                                            const char *xml);
+virNWFilterDefPtr virNWFilterDefParseFile(virConnectPtr conn,
+                                          const char *filename);
+
+void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj);
+void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj);
+
+int virNWFilterConfLayerInit(void);
+void virNWFilterConfLayerShutdown(void);
+
+#define virNWFilterReportError(conn, code, fmt...)                          \
+        virReportErrorHelper(conn, VIR_FROM_NWFILTER, code, __FILE__,       \
+                               __FUNCTION__, __LINE__, fmt)
+
+
+typedef int (*virNWFilterRebuild)(virConnectPtr conn,
+                                  virHashIterator, void *data);
+
+typedef struct _virNWFilterCallbackDriver virNWFilterCallbackDriver;
+typedef virNWFilterCallbackDriver *virNWFilterCallbackDriverPtr;
+struct _virNWFilterCallbackDriver {
+    const char *name;
+
+    virNWFilterRebuild vmFilterRebuild;
+};
+
+void virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr);
+
+
+VIR_ENUM_DECL(virNWFilterRuleAction);
+VIR_ENUM_DECL(virNWFilterRuleDirection);
+VIR_ENUM_DECL(virNWFilterRuleProtocol);
+VIR_ENUM_DECL(virNWFilterJumpTarget);
+VIR_ENUM_DECL(virNWFilterChainPolicy);
+VIR_ENUM_DECL(virNWFilterEbtablesTable);
+VIR_ENUM_DECL(virNWFilterChainSuffix);
+
+#endif
Index: libvirt-acl/include/libvirt/virterror.h
===================================================================
--- libvirt-acl.orig/include/libvirt/virterror.h
+++ libvirt-acl/include/libvirt/virterror.h
@@ -69,6 +69,7 @@ typedef enum {
     VIR_FROM_PHYP,      /* Error from IBM power hypervisor */
     VIR_FROM_SECRET,    /* Error from secret storage */
     VIR_FROM_CPU,       /* Error from CPU driver */
+    VIR_FROM_NWFILTER,  /* Error from network filter driver */
 } virErrorDomain;
 
 
@@ -168,6 +169,10 @@ typedef enum {
     VIR_ERR_NO_INTERFACE, /* interface driver not running */
     VIR_ERR_INVALID_INTERFACE, /* invalid interface object */
     VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */
+    VIR_WAR_NO_NWFILTER, /* failed to start nwfilter driver */
+    VIR_ERR_INVALID_NWFILTER, /* invalid nwfilter object */
+    VIR_ERR_NO_NWFILTER, /* nw filter pool not found */
+    VIR_ERR_BUILD_FIREWALL, /* nw filter pool not found */
     VIR_WAR_NO_SECRET, /* failed to start secret storage */
     VIR_ERR_INVALID_SECRET, /* invalid secret */
     VIR_ERR_NO_SECRET, /* secret not found */
Index: libvirt-acl/src/util/virterror.c
===================================================================
--- libvirt-acl.orig/src/util/virterror.c
+++ libvirt-acl/src/util/virterror.c
@@ -175,6 +175,9 @@ static const char *virErrorDomainName(vi
         case VIR_FROM_CPU:
             dom = "CPU ";
             break;
+        case VIR_FROM_NWFILTER:
+            dom = "Network Filter";
+            break;
     }
     return(dom);
 }
@@ -1097,6 +1100,30 @@ virErrorMsg(virErrorNumber error, const 
             else
                 errmsg = _("Secret not found: %s");
             break;
+        case VIR_WAR_NO_NWFILTER:
+            if (info == NULL)
+                errmsg = _("Failed to start the nwfilter driver");
+            else
+                errmsg = _("Failed to start the nwfilter driver: %s");
+            break;
+        case VIR_ERR_INVALID_NWFILTER:
+            if (info == NULL)
+                    errmsg = _("Invalid network filter");
+            else
+                    errmsg = _("Invalid network filter: %s");
+            break;
+        case VIR_ERR_NO_NWFILTER:
+            if (info == NULL)
+                    errmsg = _("Network filter not found");
+            else
+                    errmsg = _("Network filter not found: %s");
+            break;
+        case VIR_ERR_BUILD_FIREWALL:
+            if (info == NULL)
+                    errmsg = _("Error while building firewall");
+            else
+                    errmsg = _("Error while building firewall: %s");
+            break;
         case VIR_ERR_CONFIG_UNSUPPORTED:
             if (info == NULL)
                 errmsg = _("unsupported configuration");
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -0,0 +1,429 @@
+/*
+ * 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@xxxxxxxxxx>
+ *         Stefan Berger <stefanb@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "util.h"
+#include "nwfilter_driver.h"
+#include "nwfilter_conf.h"
+#include "memory.h"
+
+#include "domain_conf.h"
+#include "nwfilter_conf.h"
+#include "nwfilter_gentech_driver.h"
+#include "nwfilter_ebiptables_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;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_driver.h
@@ -0,0 +1,35 @@
+/*
+ * 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@xxxxxxxxxx>
+ *         Stefan Berger <stefanb@xxxxxxxxxx>
+ */
+
+#ifndef __VIR_NWFILTER_DRIVER_H__
+#define __VIR_NWFILTER_DRIVER_H__
+
+#include "nwfilter_conf.h"
+
+int nwfilterRegister(void);
+
+#endif /* __VIR_NWFILTER_DRIVER_H__ */
Index: libvirt-acl/src/datatypes.h
===================================================================
--- libvirt-acl.orig/src/datatypes.h
+++ libvirt-acl/src/datatypes.h
@@ -121,6 +121,17 @@
 
 
 /**
+ * VIR_NWFILTER_MAGIC:
+ *
+ * magic value used to protect the API when pointers to network filter
+ * pool structures are passed down by the users.
+ */
+#define VIR_NWFILTER_MAGIC			0xDEAD7777
+#define VIR_IS_NWFILTER(obj)			((obj) && (obj)->magic==VIR_NWFILTER_MAGIC)
+#define VIR_IS_CONNECTED_NWFILTER(obj)		(VIR_IS_NWFILTER(obj) && VIR_IS_CONNECT((obj)->conn))
+
+
+/**
  * _virConnect:
  *
  * Internal structure associated to a connection
@@ -141,6 +152,7 @@ struct _virConnect {
     virStorageDriverPtr storageDriver;
     virDeviceMonitorPtr  deviceMonitor;
     virSecretDriverPtr secretDriver;
+    virNWFilterDriverPtr nwfilterDriver;
 
     /* Private data pointer which can be used by driver and
      * network driver as they wish.
@@ -152,6 +164,7 @@ struct _virConnect {
     void *            storagePrivateData;
     void *            devMonPrivateData;
     void *            secretPrivateData;
+    void *            nwfilterPrivateData;
 
     /*
      * The lock mutex must be acquired before accessing/changing
@@ -173,6 +186,7 @@ struct _virConnect {
     virHashTablePtr storageVols;/* hash table for known storage vols */
     virHashTablePtr nodeDevices; /* hash table for known node devices */
     virHashTablePtr secrets;  /* hash taboe for known secrets */
+    virHashTablePtr nwfilterPools; /* hash tables ofr known nw filter pools */
     int refs;                 /* reference count */
 };
 
@@ -336,4 +350,22 @@ int virUnrefSecret(virSecretPtr secret);
 virStreamPtr virGetStream(virConnectPtr conn);
 int virUnrefStream(virStreamPtr st);
 
+/**
+* _virNWFilter:
+*
+* Internal structure associated to a network filter
+*/
+struct _virNWFilter {
+    unsigned int magic;                  /* specific value to check */
+    int refs;                            /* reference count */
+    virConnectPtr conn;                  /* pointer back to the connection */
+    char *name;                          /* the network filter external name */
+    unsigned char uuid[VIR_UUID_BUFLEN]; /* the network filter unique identifier */
+};
+
+virNWFilterPtr virGetNWFilter(virConnectPtr conn,
+                                  const char *name,
+                                  const unsigned char *uuid);
+int virUnrefNWFilter(virNWFilterPtr pool);
+
 #endif
Index: libvirt-acl/src/datatypes.c
===================================================================
--- libvirt-acl.orig/src/datatypes.c
+++ libvirt-acl/src/datatypes.c
@@ -175,6 +175,9 @@ virGetConnect(void) {
     ret->secrets = virHashCreate(20);
     if (ret->secrets == NULL)
         goto failed;
+    ret->nwfilterPools = virHashCreate(20);
+    if (ret->nwfilterPools == NULL)
+        goto failed;
 
     ret->refs = 1;
     return(ret);
@@ -1362,3 +1365,142 @@ int virUnrefStream(virStreamPtr st) {
     virMutexUnlock(&st->conn->lock);
     return (refs);
 }
+
+
+/**
+ * virGetNWFilter:
+ * @conn: the hypervisor connection
+ * @name: pointer to the network filter pool name
+ * @uuid: pointer to the uuid
+ *
+ * Lookup if the network filter is already registered for that connection,
+ * if yes return a new pointer to it, if no allocate a new structure,
+ * and register it in the table. In any case a corresponding call to
+ * virFreeNWFilterPool() is needed to not leak data.
+ *
+ * Returns a pointer to the network, or NULL in case of failure
+ */
+virNWFilterPtr
+virGetNWFilter(virConnectPtr conn, const char *name, const unsigned char *uuid) {
+    virNWFilterPtr ret = NULL;
+
+    if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return(NULL);
+    }
+    virMutexLock(&conn->lock);
+
+    /* TODO search by UUID first as they are better differenciators */
+
+    ret = (virNWFilterPtr) virHashLookup(conn->nwfilterPools, name);
+    /* TODO check the UUID */
+    if (ret == NULL) {
+        if (VIR_ALLOC(ret) < 0) {
+            virMutexUnlock(&conn->lock);
+            virReportOOMError();
+            goto error;
+        }
+        ret->name = strdup(name);
+        if (ret->name == NULL) {
+            virMutexUnlock(&conn->lock);
+            virReportOOMError();
+            goto error;
+        }
+        ret->magic = VIR_NWFILTER_MAGIC;
+        ret->conn = conn;
+        if (uuid != NULL)
+            memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN);
+
+        if (virHashAddEntry(conn->nwfilterPools, name, ret) < 0) {
+            virMutexUnlock(&conn->lock);
+            virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("failed to add network filter pool to connection hash table"));
+            goto error;
+        }
+        conn->refs++;
+    }
+    ret->refs++;
+    virMutexUnlock(&conn->lock);
+    return(ret);
+
+error:
+    if (ret != NULL) {
+        VIR_FREE(ret->name);
+        VIR_FREE(ret);
+    }
+    return(NULL);
+}
+
+
+/**
+ * virReleaseNWFilterPool:
+ * @pool: the pool to release
+ *
+ * Unconditionally release all memory associated with a pool.
+ * The conn.lock mutex must be held prior to calling this, and will
+ * be released prior to this returning. The pool obj must not
+ * be used once this method returns.
+ *
+ * It will also unreference the associated connection object,
+ * which may also be released if its ref count hits zero.
+ */
+static void
+virReleaseNWFilterPool(virNWFilterPtr pool) {
+    virConnectPtr conn = pool->conn;
+    DEBUG("release pool %p %s", pool, pool->name);
+
+    /* TODO search by UUID first as they are better differenciators */
+    if (virHashRemoveEntry(conn->nwfilterPools, pool->name, NULL) < 0) {
+        virMutexUnlock(&conn->lock);
+        virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("pool missing from connection hash table"));
+        conn = NULL;
+    }
+
+    pool->magic = -1;
+    VIR_FREE(pool->name);
+    VIR_FREE(pool);
+
+    if (conn) {
+        DEBUG("unref connection %p %d", conn, conn->refs);
+        conn->refs--;
+        if (conn->refs == 0) {
+            virReleaseConnect(conn);
+            /* Already unlocked mutex */
+            return;
+        }
+        virMutexUnlock(&conn->lock);
+    }
+}
+
+
+/**
+ * virUnrefNWFilter:
+ * @pool: the nwfilter to unreference
+ *
+ * Unreference the networkf itler. If the use count drops to zero, the
+ * structure is actually freed.
+ *
+ * Returns the reference count or -1 in case of failure.
+ */
+int
+virUnrefNWFilter(virNWFilterPtr pool) {
+    int refs;
+
+    if (!VIR_IS_CONNECTED_NWFILTER(pool)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return(-1);
+    }
+    virMutexLock(&pool->conn->lock);
+    DEBUG("unref pool %p %s %d", pool, pool->name, pool->refs);
+    pool->refs--;
+    refs = pool->refs;
+    if (refs == 0) {
+        virReleaseNWFilterPool(pool);
+        /* Already unlocked mutex */
+        return (0);
+    }
+
+    virMutexUnlock(&pool->conn->lock);
+    return (refs);
+}
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -0,0 +1,1313 @@
+/*
+ * 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@xxxxxxxxxx>
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+#include <sys/stat.h>
+
+#include "internal.h"
+
+#include "buf.h"
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "virterror_internal.h"
+#include "domain_conf.h"
+#include "nwfilter_conf.h"
+#include "nwfilter_driver.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), "%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 port number"));
+            return 1;
+        }
+    break;
+    default:
+        virNWFilterReportError(conn, VIR_ERR_INVALID_NWFILTER,
+                               _("Unhandled 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);
+}
+
+/*
+ * 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],
+         portstr[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 (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
+            virBufferVSprintf(&buf,
+                          " -p %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
+                          rule->p.ethHdrFilter.dataProtocolID.u.u16);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataSrcMACAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              macaddr, sizeof(macaddr),
+                              &rule->p.ethHdrFilter.dataSrcMACAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " -s %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataSrcMACAddr),
+                          macaddr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataSrcMACMask)) {
+                if (printDataType(conn,
+                                  vars,
+                                  macaddr, sizeof(macaddr),
+                                  &rule->p.ethHdrFilter.dataSrcMACMask))
+                    goto err_exit;
+
+                virBufferVSprintf(&buf,
+                                  "/%s",
+                                  macaddr);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataDstMACAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              macaddr, sizeof(macaddr),
+                              &rule->p.ethHdrFilter.dataDstMACAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " -d %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataDstMACAddr),
+                          macaddr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataDstMACMask)) {
+                if (printDataType(conn,
+                                  vars,
+                                  macaddr, sizeof(macaddr),
+                                  &rule->p.ethHdrFilter.dataDstMACMask))
+                    goto err_exit;
+
+                virBufferVSprintf(&buf,
+                                  "/%s",
+                                  macaddr);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataPriority)) {
+            virBufferVSprintf(&buf,
+                              " --vlan-prio %s %d",
+                              ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataPriority),
+                              rule->p.ethHdrFilter.dataPriority.u.u8);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataVLANID)) {
+            virBufferVSprintf(&buf,
+                              " --vlan-id %s %d",
+                              ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataVLANID),
+                              rule->p.ethHdrFilter.dataVLANID.u.u16);
+        }
+    break;
+
+    case VIR_NWFILTER_RULE_PROTOCOL_ARP:
+
+        virBufferVSprintf(&buf,
+                          CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+                          EBTABLES_DEFAULT_TABLE, chain);
+
+        virBufferAddLit(&buf, " -p arp");
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
+            virBufferVSprintf(&buf,
+                          " --arp-htype %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
+                          rule->p.arpHdrFilter.dataHWType.u.u16);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
+            virBufferVSprintf(&buf,
+                          " --arp-opcode %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
+                          rule->p.arpHdrFilter.dataOpcode.u.u16);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
+            virBufferVSprintf(&buf,
+                          " --arp-ptype %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
+                          rule->p.arpHdrFilter.dataProtocolType.u.u16);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataSrcIPAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              ipaddr, sizeof(ipaddr),
+                              &rule->p.arpHdrFilter.dataSrcIPAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --arp-ip-src  %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataSrcIPAddr),
+                          ipaddr);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataDstIPAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              ipaddr, sizeof(ipaddr),
+                              &rule->p.arpHdrFilter.dataDstIPAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --arp-ip-dst  %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataDstIPAddr),
+                          ipaddr);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataSrcMACAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              macaddr, sizeof(macaddr),
+                              &rule->p.arpHdrFilter.dataSrcMACAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --arp-mac-src %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataSrcMACAddr),
+                          macaddr);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataDstMACAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              macaddr, sizeof(macaddr),
+                              &rule->p.arpHdrFilter.dataDstMACAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --arp-mac-dst %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataDstMACAddr),
+                          macaddr);
+        }
+    break;
+
+    case VIR_NWFILTER_RULE_PROTOCOL_IP:
+        virBufferVSprintf(&buf,
+                          CMD_DEF_PRE EBTABLES_CMD " -t %s -%%c %s %%s",
+                          EBTABLES_DEFAULT_TABLE, chain);
+
+        // FIXME -- may not be necessary if rule is in IPv4 user defined
+        // table...
+        virBufferAddLit(&buf,
+                        " -p ipv4");
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcAddr)) {
+            if (printDataType(conn,
+                              vars,
+                              ipaddr, sizeof(ipaddr),
+                              &rule->p.ipHdrFilter.ipHdr.dataSrcAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --ip-source %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcAddr),
+                          ipaddr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcMask)) {
+                 virBufferVSprintf(&buf,
+                              "/%d",
+                              rule->p.ipHdrFilter.ipHdr.dataSrcMask.u.u8);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstAddr)) {
+
+            if (printDataType(conn,
+                              vars,
+                              ipaddr, sizeof(ipaddr),
+                              &rule->p.ipHdrFilter.ipHdr.dataDstAddr))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --ip-destination %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstAddr),
+                          ipaddr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstMask)) {
+                 virBufferVSprintf(&buf,
+                              "/%d",
+                              rule->p.ipHdrFilter.ipHdr.dataDstMask.u.u8);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
+            virBufferVSprintf(&buf,
+                          " --ip-protocol %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
+                          rule->p.ipHdrFilter.ipHdr.dataProtocolID.u.u16);
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
+
+            if (printDataType(conn,
+                              vars,
+                              portstr, sizeof(portstr),
+                              &rule->p.ipHdrFilter.portData.dataSrcPortStart))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --ip-source-port %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
+                          portstr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
+                if (printDataType(conn,
+                                  vars,
+                                  portstr, sizeof(portstr),
+                                  &rule->p.ipHdrFilter.portData.dataSrcPortEnd))
+                    goto err_exit;
+
+                virBufferVSprintf(&buf,
+                                  ":%s",
+                                  portstr);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
+
+            if (printDataType(conn,
+                              vars,
+                              portstr, sizeof(portstr),
+                              &rule->p.ipHdrFilter.portData.dataDstPortStart))
+                goto err_exit;
+
+            virBufferVSprintf(&buf,
+                          " --ip-destination-port %s %s",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
+                          portstr);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
+                if (printDataType(conn,
+                                vars,
+                                portstr, sizeof(portstr),
+                                &rule->p.ipHdrFilter.portData.dataDstPortEnd))
+                    goto err_exit;
+
+                virBufferVSprintf(&buf,
+                                  ":%s",
+                                  portstr);
+            }
+        }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.dataDSCP)) {
+            virBufferVSprintf(&buf,
+                          " --ip-tos %s %d",
+                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.dataDSCP),
+                          rule->p.ipHdrFilter.dataDSCP.u.u8);
+        }
+    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
+ebiptablesApplyRules(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;
+
+    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;
+
+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;
+}
+
+
+/**
+ * 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,
+    .applyRules          = ebiptablesApplyRules,
+    .allTeardown         = ebiptablesAllTeardown,
+    .removeRules         = ebiptablesRemoveRules,
+    .freeRuleInstance    = ebiptablesFreeRuleInstance,
+    .displayRuleInstance = ebiptablesDisplayRuleInstance,
+};
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
@@ -0,0 +1,656 @@
+/*
+ * 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@xxxxxxxxxx>
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "config.h"
+
+#include "memory.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "domain_conf.h"
+#include "nwfilter_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 (!strcmp(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_ROLLBACK_NEWFILTER:
+                    if (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)
+{
+    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_ROLLBACK_NEWFILTER:
+    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->applyRules(conn, ifname, nptrs, ptrs);
+
+        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,
+                              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_ROLLBACK_NEWFILTER:
+       if (obj->newDef)
+           foundNewFilter = 1;
+    break;
+
+    case INSTANTIATE_ALWAYS:
+    break;
+    }
+
+    rc = virNWFilterInstantiate(conn,
+                                techdriver,
+                                net->type,
+                                filter,
+                                net->ifname,
+                                vars,
+                                useNewFilter, &foundNewFilter);
+
+    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,
+                                         INSTANTIATE_ALWAYS);
+}
+
+
+int
+virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+                                   const virDomainNetDefPtr net)
+{
+    return _virNWFilterInstantiateFilter(conn, net,
+                                         INSTANTIATE_FOLLOW_NEWFILTER);
+}
+
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+                                 const virDomainNetDefPtr net)
+{
+    return _virNWFilterInstantiateFilter(conn, net,
+                                         INSTANTIATE_ROLLBACK_NEWFILTER);
+}
+
+
+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;
+}
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
@@ -0,0 +1,52 @@
+/*
+ * 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@xxxxxxxxxx>
+ */
+#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,
+    INSTANTIATE_ROLLBACK_NEWFILTER,
+};
+
+
+int virNWFilterInstantiateFilter(virConnectPtr conn,
+                                 const virDomainNetDefPtr net);
+int virNWFilterUpdateInstantiateFilter(virConnectPtr conn,
+                                       const virDomainNetDefPtr net);
+int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
+                                    const virDomainNetDefPtr net);
+
+int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
+
+virNWFilterHashTablePtr virNWFilterCreateVarHashmap(virConnectPtr conn,
+                                                     char *macaddr);
+
+#endif
Index: libvirt-acl/daemon/libvirtd.c
===================================================================
--- libvirt-acl.orig/daemon/libvirtd.c
+++ libvirt-acl/daemon/libvirtd.c
@@ -96,6 +96,9 @@
 # ifdef WITH_SECRETS
 #  include "secret/secret_driver.h"
 # endif
+# ifdef WITH_NWFILTER
+#  include "nwfilter/nwfilter_driver.h"
+# endif
 #endif
 
 
@@ -876,6 +879,7 @@ static struct qemud_server *qemudInitial
     virDriverLoadModule("lxc");
     virDriverLoadModule("uml");
     virDriverLoadModule("one");
+    virDriverLoadModule("nwfilter");
 #else
 # ifdef WITH_NETWORK
     networkRegister();
@@ -892,6 +896,9 @@ static struct qemud_server *qemudInitial
 # ifdef WITH_SECRETS
     secretRegister();
 # endif
+# ifdef WITH_NWFILTER
+    nwfilterRegister();
+# endif
 # ifdef WITH_QEMU
     qemuRegister();
 # endif
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
===================================================================
--- /dev/null
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.h
@@ -0,0 +1,41 @@
+/*
+ * nwfilter_ebiptables_driver.h: ebtables/iptables driver support
+ *
+ * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Stefan Berger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Stefan Berger <stefanb@xxxxxxxxxx>
+ */
+#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
Index: libvirt-acl/python/generator.py
===================================================================
--- libvirt-acl.orig/python/generator.py
+++ libvirt-acl/python/generator.py
@@ -170,6 +170,7 @@ skipped_types = {
 #    'int *': "usually a return type",
      'virConnectDomainEventCallback': "No function types in python",
      'virEventAddHandleFunc': "No function types in python",
+     'virNWFilterPoolPtr': "No function types in python",
 }
 
 #######################################################################
@@ -268,6 +269,7 @@ skip_impl = (
     'virConnectListStorageVols',
     'virConnectListDefinedStorageVols',
     'virConnectListDefinedInterfaces',
+    'virConnectListNWFilters',
     'virConnGetLastError',
     'virGetLastError',
     'virDomainGetInfo',
Index: libvirt-acl/configure.ac
===================================================================
--- libvirt-acl.orig/configure.ac
+++ libvirt-acl/configure.ac
@@ -291,6 +291,9 @@ if test x"$with_rhel5_api" = x"yes"; the
    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])
 
--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]