[Libvirt-cim] [PATCH] Add DCN ACL classes & providers to support libvirt NWFilters

Chip Vincent cvincent at linux.vnet.ibm.com
Wed May 25 04:59:08 UTC 2011


# HG changeset patch
# User Chip Vincent <cvincent at us.ibm.com>
# Date 1305221061 14400
# Node ID 51c1f55fa776f68ce794ea626b06b08691ff7a47
# Parent  f51a1ccadbcce1c7f9ba6268267866f7721420c1
Add DCN ACL classes & providers to support libvirt NWFilters.

This patch adds several new classes and providers to add support for filter
rules and filter lists.

The patch is rather large since all aspects are intertwined.
Here's an overview of the implementation:

libxkutil:
The instrumentation is implemented in acl_parsing.c/.h since this function
is essentially independent of the device and/or pool parsing. ACLs are
associated to devices (via filterref) so there are some minor changes in
device_parsing.c & xmlgen.c to support this. Since there's lots of rule types,
there's lots of new functions in xmlgen. A future patch should refactor
xmlgen to be more manageable like device/pool/acl_parsing.

+libxkutil/acl_parsing.h & .c
Adds several new structures to represent filters and rules. Since rules can
only exist within the context of a filter, the main structure used in the APIs
is acl_fitler.

Also adds several new APIs to libxkutil to allow providers (see below) to
convert acl_filter and acl_rule structures to CIM objects, and to support
associations between themselves and existing resource (host system & network
port).

schema & providers:
The ACL function does not map to an exiting profile so a subset of the
classes defined in the CIM Network schema are used.

+schema/FilterEntry.mof &.registration
+src/FilterEntry.h & .c
Adds two new classes to represent IP-level rules (IPHeadersFilter) and
MAC-level (Hdr8021Filter). These classes include two new properties to
surface libvirt features not defined by the schema (Direction & Priority).

NOTE: Read-write. Requires Name property to be in the form
<filter_name>:<index>, where <filter_name> is the name of an existing filter,
and <index> is an arbitrary number. Example: "clean-traffic:0". This allows
the provider to create the rule properly in the context of a pre-defined
filter. The <index> element will be changed as needed by the provider to
avoid conflict, and will be communicated to the client via the object path
returned during a CreateInstance operation.

+schema/FilterList.mof & .registration
+src/FilterList.h & .c
Adds a class to represent ACL filters (FilterList)

NOTE: Read-write. Requires Name property only.

+schema/EntriesInFilterList.mof & .registration
+src/EntriesInFilterList.c
Adds a class to represent the relationship (association) between a filter
(FilterList) and the rules it contains (IPHeadersFilter or Hdr8021Filter).

NOTE: Read-only. Clients may not explicitly create associations between
filters and rules. Rather, the relationship is implicitly formed when the
rule is created (see above).

+schema/NestedFilterList.mof & .registration
+src/NestedFilterList.c
Adds a class to represent filters that have references (filterref) to
other pre-defined filters. This is not covered by the current schema so
a new class was introduced to a) allow filters to reference each other, and
b) do it in a way that allows the client to determine if a filter
reference_s_ a filter or is reference_d_ by a filter.

NOTE: New associations are created via CIM intrinsic methods (create/modify/
delete). It requires the client to provide fully qualified object paths to
the 'parent' filter and 'child' filter so the providers can a) validate their
existance, and b) apply the necessary links in the XML so new associations
will appear when queried.

+schema/HostedFilterList.mof & .registration
+src/HostedFilterList.c
Adds a class to represent the relationship (association) between a filter
and the computer system that hosts them. In the case of ACL filters, which
are essentially defined once but available to all VMs, they are always linked
to the host system (hypervisor) rather than the individual computer
systems (VMs).

NOTE: Read-only. Clients may not change the host associated to filters.

+schema/AppliedFilterList.mof & .registration
+src/AppliedFilterList.c
Adds a class to represent the relationship (association) between a filter
and a network port referencing it. This is not covered by the current schema
so a new class was introduced.

NOTE: New associations are created via CIM intrinsic methods (create/modify/
delete). It requires the client to provide fully qualified object paths to
the filter and network port so the providers can a) validate their existance,
and b) apply the necessary links in the XML so new associations appear when
queried.

Signed-off-by: Chip Vincent <cvincent at us.ibm.com>

diff --git a/Makefile.am b/Makefile.am
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,7 +57,13 @@
 	schema/InputPool.mof \
 	schema/HostedAccessPoint.mof \
 	schema/ServiceAccessBySAP.mof \
-	schema/SAPAvailableForElement.mof
+	schema/SAPAvailableForElement.mof \
+	schema/FilterEntry.mof \
+	schema/FilterList.mof \
+	schema/EntriesInFilterList.mof \
+	schema/NestedFilterList.mof \
+	schema/AppliedFilterList.mof \
+	schema/HostedFilterList.mof
 
 INTEROP_MOFS = \
 	schema/ComputerSystem.mof \
@@ -138,7 +144,13 @@
 	schema/InputPool.registration \
 	schema/HostedAccessPoint.registration \
 	schema/ServiceAccessBySAP.registration \
-	schema/SAPAvailableForElement.registration
+	schema/SAPAvailableForElement.registration \
+	schema/FilterEntry.registration \
+	schema/FilterList.registration \
+	schema/EntriesInFilterList.registration \
+	schema/NestedFilterList.registration \
+	schema/AppliedFilterList.registration \
+	schema/HostedFilterList.registration
 
 INTEROP_REGS = \
 	schema/RegisteredProfile.registration \
diff --git a/libxkutil/Makefile.am b/libxkutil/Makefile.am
--- a/libxkutil/Makefile.am
+++ b/libxkutil/Makefile.am
@@ -4,12 +4,12 @@
 CFLAGS += $(CFLAGS_STRICT)
 
 noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h \
-                 pool_parsing.h
+                 pool_parsing.h acl_parsing.h
 
 lib_LTLIBRARIES = libxkutil.la
 
 libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \
-                       xmlgen.c infostore.c pool_parsing.c
+                       xmlgen.c infostore.c pool_parsing.c acl_parsing.c
 
 libxkutil_la_LIBADD = @LIBVIRT_LIBS@ \
 		      @LIBUUID_LIBS@
diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c
new file mode 100644
--- /dev/null
+++ b/libxkutil/acl_parsing.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+
+#include "acl_parsing.h"
+#include "device_parsing.h"
+#include "xmlgen.h"
+#include "../src/svpc_types.h"
+
+void cleanup_rule(struct acl_rule *rule)
+{
+        if(rule == NULL)
+                return;
+
+        free(rule->name);
+        free(rule->protocol_id);
+        free(rule->action);
+        free(rule->direction);
+        free(rule->priority);
+
+        switch(rule->type) {
+        case MAC_RULE:
+                free(rule->var.mac.srcmacaddr);
+                free(rule->var.mac.srcmacmask);
+                free(rule->var.mac.dstmacaddr);
+                free(rule->var.mac.dstmacmask);
+                free(rule->var.mac.protocol_id);
+                free(rule->var.mac.comment);
+                break;
+        case ARP_RULE:
+                free(rule->var.arp.srcmacaddr);
+                free(rule->var.arp.srcmacmask);
+                free(rule->var.arp.dstmacaddr);
+                free(rule->var.arp.dstmacmask);
+                free(rule->var.arp.hw_type);
+                free(rule->var.arp.protocol_type);
+                free(rule->var.arp.opcode);
+                free(rule->var.arp.arpsrcmacaddr);
+                free(rule->var.arp.arpdstmacaddr);
+                free(rule->var.arp.arpsrcipaddr);
+                free(rule->var.arp.arpdstipaddr);
+                free(rule->var.arp.comment);
+                break;
+        case IP_RULE:
+                free(rule->var.ip.srcmacaddr);
+                free(rule->var.ip.srcmacmask);
+                free(rule->var.ip.dstmacaddr);
+                free(rule->var.ip.dstmacmask);
+                free(rule->var.ip.srcipaddr);
+                free(rule->var.ip.srcipmask);
+                free(rule->var.ip.dstipaddr);
+                free(rule->var.ip.dstipmask);
+                free(rule->var.ip.srcportstart);
+                free(rule->var.ip.srcportend);
+                free(rule->var.ip.dstportstart);
+                free(rule->var.ip.dstportend);
+                free(rule->var.ip.comment);
+                break;
+        case TCP_RULE:
+                free(rule->var.tcp.srcmacaddr);
+                free(rule->var.tcp.srcipaddr);
+                free(rule->var.tcp.srcipmask);
+                free(rule->var.tcp.dstipaddr);
+                free(rule->var.tcp.srcipfrom);
+                free(rule->var.tcp.srcipto);
+                free(rule->var.tcp.dstipfrom);
+                free(rule->var.tcp.dstipto);
+                free(rule->var.tcp.srcportstart);
+                free(rule->var.tcp.srcportend);
+                free(rule->var.tcp.dstportstart);
+                free(rule->var.tcp.dstportend);
+                free(rule->var.tcp.comment);
+                free(rule->var.tcp.state);
+                break;
+        case IGMP_RULE:
+                free(rule->var.igmp.srcmacaddr);
+                free(rule->var.igmp.srcmacmask);
+                free(rule->var.igmp.dstmacaddr);
+                free(rule->var.igmp.dstmacmask);
+                free(rule->var.igmp.srcipaddr);
+                free(rule->var.igmp.srcipmask);
+                free(rule->var.igmp.dstipaddr);
+                free(rule->var.igmp.dstipmask);
+                free(rule->var.igmp.srcipfrom);
+                free(rule->var.igmp.srcipto);
+                free(rule->var.igmp.dstipfrom);
+                free(rule->var.igmp.dstipto);
+                free(rule->var.igmp.type);
+                free(rule->var.igmp.code);
+                free(rule->var.igmp.comment);
+                free(rule->var.igmp.state);
+                break;
+        case ICMP_RULE:
+                free(rule->var.icmp.srcmacaddr);
+                free(rule->var.icmp.srcmacmask);
+                free(rule->var.icmp.dstmacaddr);
+                free(rule->var.icmp.dstmacmask);
+                free(rule->var.icmp.srcipaddr);
+                free(rule->var.icmp.srcipmask);
+                free(rule->var.icmp.dstipaddr);
+                free(rule->var.icmp.dstipmask);
+                free(rule->var.icmp.srcipfrom);
+                free(rule->var.icmp.srcipto);
+                free(rule->var.icmp.dstipfrom);
+                free(rule->var.icmp.dstipto);
+                free(rule->var.icmp.type);
+                free(rule->var.icmp.code);
+                free(rule->var.icmp.comment);
+                free(rule->var.icmp.state);
+                break;
+        case UNKNOWN_RULE:
+        default:
+                break;
+        };
+
+        rule->type = UNKNOWN_RULE;
+}
+
+void cleanup_filter(struct acl_filter *filter)
+{
+        int i;
+
+        if(filter == NULL)
+                return;
+
+        free(filter->uuid);
+        free(filter->name);
+        free(filter->chain);
+
+        for (i = 0; i < filter->rule_ct; i++) {
+                cleanup_rule(filter->rules[i]);
+                free(filter->rules[i]);
+        }
+
+        free(filter->rules);
+        filter->rule_ct = 0;
+
+        for (i = 0; i < filter->ref_ct; i++)
+                free(filter->refs[i]);
+
+        free(filter->refs);
+        filter->ref_ct = 0;
+}
+
+void cleanup_filters(struct acl_filter **filters, int count)
+{
+        int i;
+        struct acl_filter *_filters = *filters;
+
+        if((filters == NULL) || (*filters == NULL) || (count == 0))
+                return;
+
+        for (i = 0; i < count; i++)
+                cleanup_filter(&_filters[i]);
+
+        free(_filters);
+        *filters = NULL;
+}
+
+
+static int parse_acl_mac_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACL mac rule %s", rnode->name);
+
+        rule->type = MAC_RULE;
+        rule->var.mac.protocol_id = get_attr_value(rnode, "protocolid");
+        rule->var.mac.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.mac.srcmacmask = get_attr_value(rnode, "srcmacmask");
+        rule->var.mac.dstmacaddr = get_attr_value(rnode, "dstmacaddr");
+        rule->var.mac.dstmacmask = get_attr_value(rnode, "dstmacmask");
+        rule->var.mac.comment = get_attr_value(rnode, "comment");
+
+        return 1;
+}
+
+static int parse_acl_arp_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACL arp rule %s", rnode->name);
+
+        rule->type = ARP_RULE;
+        rule->var.arp.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.arp.srcmacmask = get_attr_value(rnode, "srcmacmask");
+        rule->var.arp.dstmacaddr = get_attr_value(rnode, "dstmacaddr");
+        rule->var.arp.dstmacmask = get_attr_value(rnode, "dstmacmask");
+        rule->var.arp.hw_type = get_attr_value(rnode, "hwtype");
+        rule->var.arp.protocol_type = get_attr_value(rnode, "protocoltype");
+        rule->var.arp.opcode = get_attr_value(rnode, "opcode");
+        rule->var.arp.arpsrcmacaddr = get_attr_value(rnode, "arpsrcmacaddr");
+        rule->var.arp.arpdstmacaddr = get_attr_value(rnode, "arpdstmacaddr");
+        rule->var.arp.arpsrcipaddr = get_attr_value(rnode, "arpsrcipaddr");
+        rule->var.arp.arpdstipaddr = get_attr_value(rnode, "arpdstipaddr");
+        rule->var.arp.comment = get_attr_value(rnode, "comment");
+
+        return 1;
+}
+
+static int parse_acl_ip_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACP ip rule %s", rnode->name);
+
+        rule->type = IP_RULE;
+        rule->var.ip.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.ip.srcmacmask = get_attr_value(rnode, "srcmacmask");
+        rule->var.ip.dstmacaddr = get_attr_value(rnode, "dstmacaddr");
+        rule->var.ip.dstmacmask = get_attr_value(rnode, "dstmacmaks");
+        rule->var.ip.srcipaddr = get_attr_value(rnode, "srcipaddr");
+        rule->var.ip.srcipmask = get_attr_value(rnode, "srcipmask");
+        rule->var.ip.dstipaddr = get_attr_value(rnode, "dstipaddr");
+        rule->var.ip.dstipmask = get_attr_value(rnode, "dstipmask");
+        rule->var.ip.protocol = get_attr_value(rnode, "protocol");
+        rule->var.ip.srcportstart = get_attr_value(rnode, "srcportstart");
+        rule->var.ip.srcportend = get_attr_value(rnode, "srcportend");
+        rule->var.ip.dstportstart = get_attr_value(rnode, "dstportstart");
+        rule->var.ip.dstportend = get_attr_value(rnode, "dstportend");
+        rule->var.ip.comment = get_attr_value(rnode, "comment");
+
+        return 1;
+}
+
+static int parse_acl_tcp_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACL tcp rule %s", rnode->name);
+
+        rule->type = TCP_RULE;
+        rule->var.tcp.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.tcp.srcipaddr = get_attr_value(rnode, "srcipaddr");
+        rule->var.tcp.srcipmask = get_attr_value(rnode, "srcipmask");
+        rule->var.tcp.dstipaddr = get_attr_value(rnode, "dstipaddr");
+        rule->var.tcp.dstipmask = get_attr_value(rnode, "dstipmask");
+        rule->var.tcp.srcipfrom = get_attr_value(rnode, "srcipfrom");
+        rule->var.tcp.srcipto = get_attr_value(rnode, "srcipto");
+        rule->var.tcp.dstipfrom = get_attr_value(rnode, "dstipfrom");
+        rule->var.tcp.dstipto = get_attr_value(rnode, "dstipto");
+        rule->var.tcp.srcportstart = get_attr_value(rnode, "srcportstart");
+        rule->var.tcp.srcportend = get_attr_value(rnode, "srcportend");
+        rule->var.tcp.dstportstart = get_attr_value(rnode, "dstportstart");
+        rule->var.tcp.dstportend = get_attr_value(rnode, "dstportend");
+        rule->var.tcp.comment = get_attr_value(rnode, "comment");
+        rule->var.tcp.state = get_attr_value(rnode, "state");
+
+        return 1;
+}
+
+static int parse_acl_icmp_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACL icmp rule %s", rnode->name);
+
+        rule->type = ICMP_RULE;
+        rule->var.icmp.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.icmp.srcmacmask = get_attr_value(rnode, "srcmacmask");
+        rule->var.icmp.dstmacaddr = get_attr_value(rnode, "dstmacaddr");
+        rule->var.icmp.dstmacmask = get_attr_value(rnode, "dstmacmask");
+        rule->var.icmp.srcipaddr = get_attr_value(rnode, "srcipaddr");
+        rule->var.icmp.srcipmask = get_attr_value(rnode, "srcipmask");
+        rule->var.icmp.dstipaddr = get_attr_value(rnode, "dstipaddr");
+        rule->var.icmp.dstipmask = get_attr_value(rnode, "dstipmask");
+        rule->var.icmp.srcipfrom = get_attr_value(rnode, "srcipfrom");
+        rule->var.icmp.srcipto = get_attr_value(rnode, "srcipto");
+        rule->var.icmp.dstipfrom = get_attr_value(rnode, "dstipfrom");
+        rule->var.icmp.dstipto = get_attr_value(rnode, "dstipto");
+        rule->var.icmp.comment = get_attr_value(rnode, "comment");
+        rule->var.icmp.state = get_attr_value(rnode, "state");
+
+        return 1;
+}
+
+static int parse_acl_igmp_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        CU_DEBUG("ACL igmp rule %s", rnode->name);
+
+        rule->type = IGMP_RULE;
+        rule->var.igmp.srcmacaddr = get_attr_value(rnode, "srcmacaddr");
+        rule->var.igmp.srcmacmask = get_attr_value(rnode, "srcmacmask");
+        rule->var.igmp.dstmacaddr = get_attr_value(rnode, "dstmacaddr");
+        rule->var.igmp.dstmacmask = get_attr_value(rnode, "dstmacmask");
+        rule->var.igmp.srcipaddr = get_attr_value(rnode, "srcipaddr");
+        rule->var.igmp.srcipmask = get_attr_value(rnode, "srcipmask");
+        rule->var.igmp.dstipaddr = get_attr_value(rnode, "dstipaddr");
+        rule->var.igmp.dstipmask = get_attr_value(rnode, "dstipmask");
+        rule->var.igmp.srcipfrom = get_attr_value(rnode, "srcipfrom");
+        rule->var.igmp.srcipto = get_attr_value(rnode, "srcipto");
+        rule->var.igmp.dstipfrom = get_attr_value(rnode, "dstipfrom");
+        rule->var.igmp.dstipto = get_attr_value(rnode, "dstipto");
+        rule->var.igmp.type = get_attr_value(rnode, "type");
+        rule->var.igmp.code = get_attr_value(rnode, "code");
+        rule->var.igmp.comment = get_attr_value(rnode, "comment");
+        rule->var.igmp.state = get_attr_value(rnode, "state");
+
+        return 1;
+}
+
+static int parse_acl_rule(xmlNode *rnode, struct acl_rule *rule)
+{
+        xmlNode *child = NULL;
+
+        memset(rule, 0, sizeof(*rule));
+
+        rule->action = get_attr_value(rnode, "action");
+        if (rule->action == NULL)
+                goto err;
+
+        rule->direction = get_attr_value(rnode, "direction");
+        if (rule->direction == NULL)
+                goto err;
+
+        rule->priority = get_attr_value(rnode, "priority");
+        rule->statematch = get_attr_value(rnode, "statematch");
+
+        for (child = rnode->children; child != NULL; child = child->next) {
+                if (XSTREQ(child->name, "mac")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_mac_rule(child, rule);
+                } else if (XSTREQ(child->name, "arp") ||
+                        XSTREQ(child->name, "rarp")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_arp_rule(child, rule);
+                } else if (XSTREQ(child->name, "ip") ||
+                        XSTREQ(child->name, "ipv6")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_ip_rule(child, rule);
+                } else if (XSTREQ(child->name, "tcp") ||
+                        XSTREQ(child->name, "tcp-ipv6") ||
+                        XSTREQ(child->name, "udp") ||
+                        XSTREQ(child->name, "udp-ipv6") ||
+                        XSTREQ(child->name, "sctp") ||
+                        XSTREQ(child->name, "sctp-ipv6")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_tcp_rule(child, rule);
+                } else if (XSTREQ(child->name, "icmp") ||
+                        XSTREQ(child->name, "icmpv6")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_icmp_rule(child, rule);
+                } else if (XSTREQ(child->name, "igmp") ||
+                        XSTREQ(child->name, "igmp-ipv6") ||
+                        XSTREQ(child->name, "esp") ||
+                        XSTREQ(child->name, "esp-ipv6") ||
+                        XSTREQ(child->name, "ah") ||
+                        XSTREQ(child->name, "ah-ipv6") ||
+                        XSTREQ(child->name, "udplite") ||
+                        XSTREQ(child->name, "udplite-ipv6") ||
+                        XSTREQ(child->name, "all") ||
+                        XSTREQ(child->name, "all-ipv6")) {
+                        rule->protocol_id = strdup((char *)child->name);
+                        parse_acl_igmp_rule(child, rule);
+                }
+        }
+
+        return 1;
+
+ err:
+        cleanup_rule(rule);
+
+        return 0;
+}
+
+static int parse_acl_filter(xmlNode *fnode, struct acl_filter *filter)
+{
+        struct acl_rule *rule = NULL;
+        char *filter_ref = NULL;
+        xmlNode *child = NULL;
+
+        filter->name = get_attr_value(fnode, "name");
+        if (filter->name == NULL)
+                goto err;
+
+        filter->chain = get_attr_value(fnode, "chain");
+
+        for (child = fnode->children; child != NULL; child = child->next) {
+                if (XSTREQ(child->name, "uuid")) {
+                        STRPROP(filter, uuid, child);
+                } else if (XSTREQ(child->name, "rule")) {
+                        rule = malloc(sizeof(*rule));
+                        if (rule == NULL)
+                                goto err;
+
+                        if (parse_acl_rule(child, rule) == 0)
+                                goto err;
+
+                        append_filter_rule(filter, rule);
+                }
+                else if (XSTREQ(child->name, "filterref")) {
+                        filter_ref = get_attr_value(child, "filter");
+                        if (filter_ref == NULL)
+                                goto err;
+
+                        append_filter_ref(filter, filter_ref);
+                }
+        }
+
+        return 1;
+
+ err:
+        cleanup_filter(filter);
+
+        return 0;
+}
+
+/* Dummy function to suppress error message from libxml2 */
+static void swallow_err_msg(void *ctx, const char *msg, ...)
+{
+        /* do nothing, just swallow the message. */
+}
+
+int get_filter_from_xml(const char *xml, struct acl_filter **filter)
+{
+        xmlDoc *xmldoc = NULL;
+
+        if (xml == NULL || filter == NULL)
+                return 0;
+
+        xmlSetGenericErrorFunc(NULL, swallow_err_msg);
+
+        xmldoc = xmlParseMemory(xml, strlen(xml) + 1);
+        if (xmldoc == NULL)
+                goto err;
+
+        *filter = malloc(sizeof(**filter));
+
+        memset(*filter, 0, sizeof(**filter));
+        parse_acl_filter(xmldoc->children, *filter);
+
+ err:
+        xmlSetGenericErrorFunc(NULL, NULL);
+        xmlFreeDoc(xmldoc);
+
+        return 1;
+}
+
+int get_filter_by_name(
+        virConnectPtr conn,
+        const char *name,
+        struct acl_filter **filter)
+{
+        virNWFilterPtr vfilter = NULL;
+        char *xml = NULL;
+
+        if (name == NULL || filter == NULL)
+                return 0;
+
+        vfilter = virNWFilterLookupByName(conn, name);
+
+        xml = virNWFilterGetXMLDesc(vfilter, 0);
+
+        virNWFilterFree(vfilter);
+
+        if (xml == NULL)
+                return 0;
+
+        get_filter_from_xml(xml, filter);
+
+        return 1;
+}
+
+int get_filter_by_uuid(
+        virConnectPtr conn,
+        const char *uuid,
+        struct acl_filter **filter)
+{
+        virNWFilterPtr vfilter = NULL;
+        char *xml = NULL;
+
+        if (uuid == NULL || filter == NULL)
+                return 0;
+
+        vfilter = virNWFilterLookupByUUIDString(conn, uuid);
+
+        xml = virNWFilterGetXMLDesc(vfilter, 0);
+
+        virNWFilterFree(vfilter);
+
+        if (xml == NULL)
+                return 0;
+
+        get_filter_from_xml(xml, filter);
+
+        return 1;
+}
+
+int get_filters(
+        virConnectPtr conn,
+        struct acl_filter **list)
+{
+        int count = 0;
+        char **names = NULL;
+        struct acl_filter *filters = NULL;
+        int i = 0;
+
+        count = virConnectNumOfNWFilters(conn);
+
+        names = calloc(count, sizeof(char *));
+        if (names == NULL)
+                goto err;
+
+        virConnectListNWFilters(conn, names, count);
+
+        filters = malloc(count * sizeof(struct acl_filter));
+        if (filters == NULL)
+                goto err;
+
+        for(i = 0; i < count; i++)
+        {
+                struct acl_filter *filter = NULL;
+
+                get_filter_by_name(conn, names[i], &filter);
+
+                memcpy(&filters[i], filter, sizeof(*filter));
+        }
+
+        *list = filters;
+
+ err:
+        free(names);
+
+        return i;
+}
+
+
+int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule)
+{
+        struct acl_rule **old_rules = NULL;
+
+        if ((filter == NULL) || (rule == NULL))
+                return 0;
+
+        rule->name = make_rule_id(filter->name, filter->rule_ct);
+        if (rule->name == NULL)
+                return 0;
+
+        old_rules = filter->rules;
+
+        filter->rules =
+                malloc((filter->rule_ct + 1) * sizeof(struct acl_rule *));
+
+        memcpy(filter->rules,
+                old_rules,
+                filter->rule_ct * sizeof(struct acl_rule *));
+
+        filter->rules[filter->rule_ct] = rule;
+        filter->rule_ct++;
+
+        free(old_rules);
+
+        return 1;
+}
+
+int remove_filter_rule(struct acl_filter *filter, struct acl_rule *rule)
+{
+        char *filter_name = NULL;
+        int i, index = 0;
+        struct acl_rule **old_rules = NULL;
+
+        if ((filter == NULL) || (rule == NULL))
+                return 0;
+
+        if (parse_rule_id(rule->name, &filter_name, &index) == 0)
+                return 0;
+
+        if (index > filter->rule_ct)
+                return 0;
+
+        /* TODO: called infrequently, but needs optimization */
+        old_rules = filter->rules;
+        filter->rules = NULL;
+
+        for (i = 0; i < filter->rule_ct; i++)
+                if (index == i) {
+                        cleanup_rule(old_rules[i]);
+                }
+                else
+                        append_filter_rule(filter, old_rules[i]);
+
+        return 1;
+}
+
+int append_filter_ref(struct acl_filter *filter, char *name)
+{
+        int i;
+        char **old_refs = NULL;
+
+        if ((filter == NULL) || (name == NULL))
+                return 0;
+
+        for (i = 0; i < filter->ref_ct; i++)
+                if (STREQC(filter->refs[i], name))
+                        return 0; /* already exists */
+
+        old_refs = filter->refs;
+
+        filter->refs = malloc((filter->ref_ct + 1) * sizeof(char *));
+        memcpy(filter->refs, old_refs, filter->ref_ct * sizeof(char *));
+
+        filter->refs[filter->ref_ct] = name;
+        filter->ref_ct++;
+
+        free(old_refs);
+
+        return 1;
+}
+
+int remove_filter_ref(struct acl_filter *filter, const char *name)
+{
+        int i;
+        char **old_refs = NULL;
+
+        if ((filter == NULL) || (name == NULL))
+                return 0;
+
+        /* TODO: called infrequently, but needs optimization */
+        old_refs = filter->refs;
+
+        for (i = 0; i < filter->ref_ct; i++)
+                if (STREQC(old_refs[i], name)) {
+                        free(old_refs[i]);
+                }
+                else
+                        append_filter_ref(filter, old_refs[i]);
+
+        return 1;
+}
+
+int create_filter(virConnectPtr conn, struct acl_filter *filter)
+{
+        virNWFilterPtr vfilter = NULL;
+        char *xml = NULL;
+
+        if (filter == NULL)
+                return 0;
+
+        xml = filter_to_xml(filter);
+        if (xml == NULL)
+                return 0;
+
+        vfilter = virNWFilterDefineXML(conn, xml);
+
+        free(xml);
+
+        if (vfilter == NULL)
+                return 0;
+
+        virNWFilterFree(vfilter);
+
+        return 1;
+}
+
+int update_filter(virConnectPtr conn, struct acl_filter *filter)
+{
+        if (delete_filter(conn, filter) == 0 || 
+                create_filter(conn, filter) == 0)
+                return 0;
+
+        return 1;
+}
+
+int delete_filter(virConnectPtr conn, struct acl_filter *filter)
+{
+        virNWFilterPtr vfilter = NULL;
+
+        if (filter == NULL)
+                return 0;
+
+        vfilter = virNWFilterLookupByUUIDString(conn, filter->uuid);
+        if (vfilter == NULL)
+                return 0;
+
+        if (virNWFilterUndefine(vfilter) != 0) {
+                virNWFilterFree(vfilter);
+                return 0;
+        }
+
+        return 1;
+}
+
+char *make_rule_id(const char *filter, int index)
+{
+        int ret;
+        char *rule_id = NULL;
+
+        if (filter == NULL)
+                return NULL;
+
+        ret = asprintf(&rule_id, "%s:%u", filter, index);
+        if (ret == -1) {
+                free(rule_id);
+                rule_id = NULL;
+        }
+
+
+        return rule_id;
+}
+
+int parse_rule_id(const char *rule_id, char **filter, int *index)
+{
+        int ret;
+
+        if ((filter == NULL) || (index == NULL))
+                return 0;
+        ret = sscanf(rule_id, "%as[^:]:%u", filter, index);
+        if (ret != 2) {
+                free(*filter);
+                *filter = NULL;
+
+                return 0;
+        }
+
+        return 1;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h
new file mode 100644
--- /dev/null
+++ b/libxkutil/acl_parsing.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#ifndef __ACL_PARSING_H
+#define __ACL_PARSING_H
+
+#include <libvirt/libvirt.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+struct acl_mac_rule {
+        char *srcmacaddr;
+        char *srcmacmask;
+        char *dstmacaddr;
+        char *dstmacmask;
+
+        char *protocol_id;
+        char *comment;
+};
+
+struct acl_arp_rule {
+        char *srcmacaddr;
+        char *srcmacmask;
+        char *dstmacaddr;
+        char *dstmacmask;
+
+        char *hw_type;
+        char *protocol_type;
+        char *opcode;
+        char *arpsrcmacaddr;
+        char *arpdstmacaddr;
+        char *arpsrcipaddr;
+        char *arpdstipaddr;
+        char *comment;
+};
+
+struct acl_ip_rule {
+        char *srcmacaddr;
+        char *srcmacmask;
+        char *dstmacaddr;
+        char *dstmacmask;
+
+        char *srcipaddr;
+        char *srcipmask;
+        char *dstipaddr;
+        char *dstipmask;
+
+        char *protocol;
+
+        char *srcportstart;
+        char *srcportend;
+        char *dstportstart;
+        char *dstportend;
+
+        char *comment;
+};
+
+struct acl_tcp_rule {
+        char *srcmacaddr;
+
+        char *srcipaddr;
+        char *srcipmask;
+        char *dstipaddr;
+        char *dstipmask;
+
+        char *srcipfrom;
+        char *srcipto;
+        char *dstipfrom;
+        char *dstipto;
+
+        char *srcportstart;
+        char *srcportend;
+        char *dstportstart;
+        char *dstportend;
+
+        char *comment;
+        char *state;
+};
+
+struct acl_igmp_rule {
+        char *srcmacaddr;
+        char *srcmacmask;
+        char *dstmacaddr;
+        char *dstmacmask;
+
+        char *srcipaddr;
+        char *srcipmask;
+        char *dstipaddr;
+        char *dstipmask;
+
+        char *srcipfrom;
+        char *srcipto;
+        char *dstipfrom;
+        char *dstipto;
+
+        char *type;
+        char *code;
+        char *comment;
+        char *state;
+};
+
+struct acl_icmp_rule {
+        char *srcmacaddr;
+        char *srcmacmask;
+        char *dstmacaddr;
+        char *dstmacmask;
+
+        char *srcipaddr;
+        char *srcipmask;
+        char *dstipaddr;
+        char *dstipmask;
+
+        char *srcipfrom;
+        char *srcipto;
+        char *dstipfrom;
+        char *dstipto;
+
+        char *type;
+        char *code;
+        char *comment;
+        char *state;
+};
+
+struct acl_rule {
+        char *name;
+        char *protocol_id;
+        char *action;
+        char *direction;
+        char *priority;
+        char *statematch;
+
+        enum {
+                UNKNOWN_RULE,
+                MAC_RULE,
+                ARP_RULE,
+                IP_RULE,
+                TCP_RULE,
+                ICMP_RULE,
+                IGMP_RULE
+        } type;
+
+        union {
+                struct acl_mac_rule mac;
+                struct acl_arp_rule arp;
+                struct acl_ip_rule ip;
+                struct acl_tcp_rule tcp;
+                struct acl_icmp_rule icmp;
+                struct acl_igmp_rule igmp;
+        } var;
+};
+
+struct acl_filter {
+        char *uuid;
+        char *name;
+        char *chain;
+
+        struct acl_rule **rules;
+        int rule_ct;
+
+        char **refs;
+        int ref_ct;
+};
+
+void cleanup_rule(struct acl_rule *rule);
+void cleanup_filter(struct acl_filter *filter);
+void cleanup_filters(struct acl_filter **filters, int count);
+
+int get_filters(virConnectPtr conn, struct acl_filter **list);
+
+int get_filter_from_xml(const char *xml, struct acl_filter **filter);
+int get_filter_by_uuid(virConnectPtr conn, const char *uuid, 
+        struct acl_filter **filter);
+int get_filter_by_name(virConnectPtr conn, const char *name,
+        struct acl_filter **filter);
+
+char *make_rule_id(const char *filter, int index);
+int parse_rule_id(const char *rule_id, char **filter, int *index);
+
+int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule);
+int remove_filter_rule(struct acl_filter *filter, struct acl_rule *rule);
+
+/* NOTE: caller allocates name and cleanup_filter() releases it */
+int append_filter_ref(struct acl_filter *filter, char *name);
+int remove_filter_ref(struct acl_filter *filter, const char *name);
+
+int create_filter(virConnectPtr conn, struct acl_filter *filter);
+int update_filter(virConnectPtr conn, struct acl_filter *filter);
+int delete_filter(virConnectPtr conn, struct acl_filter *filter);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c
--- a/libxkutil/device_parsing.c
+++ b/libxkutil/device_parsing.c
@@ -80,6 +80,7 @@
         free(dev->model);
         free(dev->device);
         free(dev->net_mode);
+        free(dev->filter_ref);
 }
 
 static void cleanup_emu_device(struct emu_device *dev)
@@ -386,9 +387,12 @@
                         ndev->model = get_attr_value(child, "type");
                         if (ndev->model == NULL)
                                 goto err;
+                } else if (XSTREQ(child->name, "filterref")) {
+                        ndev->filter_ref = get_attr_value(child, "filter");
                 } else if (XSTREQ(child->name, "virtualport")) {
                         parse_vsi_device(child, ndev);
                 }
+
         }
 
         if (ndev->source == NULL)
@@ -764,6 +768,7 @@
                 DUP_FIELD(dev, _dev, dev.net.model);
                 DUP_FIELD(dev, _dev, dev.net.device);
                 DUP_FIELD(dev, _dev, dev.net.net_mode);
+                DUP_FIELD(dev, _dev, dev.net.filter_ref);
                 DUP_FIELD(dev, _dev, dev.net.vsi.vsi_type);
                 DUP_FIELD(dev, _dev, dev.net.vsi.manager_id);
                 DUP_FIELD(dev, _dev, dev.net.vsi.type_id);
diff --git a/libxkutil/device_parsing.h b/libxkutil/device_parsing.h
--- a/libxkutil/device_parsing.h
+++ b/libxkutil/device_parsing.h
@@ -64,6 +64,7 @@
         char *model;
         char *device;
         char *net_mode;
+        char *filter_ref;
         struct vsi_device vsi;
 };
 
diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c
--- a/libxkutil/xmlgen.c
+++ b/libxkutil/xmlgen.c
@@ -301,6 +301,15 @@
                         xmlNewProp(tmp, BAD_CAST "type", BAD_CAST net->model);
                 }
 
+                if (net->filter_ref != NULL) {
+                        tmp = xmlNewChild(nic, NULL, 
+                                BAD_CAST "filterref", NULL);
+                        if (tmp == NULL)
+                                return XML_ERROR;
+                        xmlNewProp(tmp, BAD_CAST "filter", 
+                                BAD_CAST net->filter_ref);
+                }
+
                 if (STREQ(dev->dev.net.type, "network"))
                         msg = set_net_source(nic, net, "network");
                 else if (STREQ(dev->dev.net.type, "bridge"))
@@ -1351,6 +1360,642 @@
         return xml;
 }
 
+static char *mac_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        prop = rule->var.mac.protocol_id;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "protocolid",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.mac.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.mac.srcmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.mac.dstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.mac.dstmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.mac.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error */
+ out:
+        return msg;
+}
+
+static char *arp_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        prop = rule->var.arp.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.srcmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.dstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.dstmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.hw_type;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "hwtype",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.protocol_type;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "protocol_type",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.opcode;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "opcode",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.arpsrcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "arpsrcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.arpdstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "arpdstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.arpsrcipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "arpsrcipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.arp.arpdstipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "arpdstipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.arp.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error */
+ out:
+
+        return msg;
+}
+
+static char *ip_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        rule->var.ip.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.srcmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.srcipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.srcipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.protocol;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "protocol",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.srcportstart;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcportstart",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.srcportend;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcportend",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstportstart;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstportstart",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.dstportend;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstportend",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        rule->var.ip.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error */
+ out:
+
+        return msg;
+}
+
+static char *tcp_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        prop = rule->var.tcp.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop =rule->var.tcp.srcipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.srcipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.dstipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop =rule->var.tcp.dstipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.srcipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.srcipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop =rule->var.tcp.dstipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.dstipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.srcportstart;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcportstart",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.srcportend;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcportend",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.dstportstart;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstportstart",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.dstportend;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstportend",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.tcp.state;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "state",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error */
+ out:
+
+        return msg;
+}
+
+static char *icmp_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        prop = rule->var.icmp.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.srcmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.dstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.dstmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.srcipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.srcipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.dstipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop =rule->var.icmp.dstipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop =rule->var.icmp.srcipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.srcipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.dstipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.dstipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.icmp.state;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "state",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error*/
+ out:
+
+        return msg;
+}
+
+static char *igmp_rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        char *msg = XML_ERROR;
+        char *prop = NULL;
+
+        prop = rule->var.igmp.srcmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.srcmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstmacaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstmacmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstmacmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.srcipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.srcipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstipaddr;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipaddr",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstipmask;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipmask",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.srcipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.srcipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "srcipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstipfrom;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipfrom",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.dstipto;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "dstipto",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.type;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "type",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.code;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "code",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.comment;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "comment",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        prop = rule->var.igmp.state;
+        if (prop != NULL)
+                if (xmlNewProp(root, BAD_CAST "state",
+                        BAD_CAST prop) == NULL)
+                        goto out;
+
+        msg = NULL; /* no error*/
+ out:
+
+        return msg;
+}
+
+static char *rule_to_xml(xmlNodePtr root, struct acl_rule *rule)
+{
+        xmlNodePtr r = NULL;
+        char *msg = XML_ERROR;
+
+        r = xmlNewChild(root, NULL, BAD_CAST "rule", NULL);
+        if (r == NULL)
+                goto out;
+
+        if (rule->action != NULL)
+                if (xmlNewProp(r, BAD_CAST "action",
+                        BAD_CAST rule->action) == NULL)
+                        goto out;
+
+        if (rule->direction != NULL)
+                if (xmlNewProp(r, BAD_CAST "direction",
+                        BAD_CAST rule->direction) == NULL)
+                        goto out;
+
+        if (rule->priority != NULL)
+                if (xmlNewProp(r, BAD_CAST "priority",
+                        BAD_CAST rule->priority) == NULL)
+                        goto out;
+
+        if (rule->statematch != NULL)
+                if (xmlNewProp(r, BAD_CAST "statematch",
+                        BAD_CAST rule->statematch) == NULL)
+                        goto out;
+
+        switch (rule->type) {
+        case MAC_RULE:
+                msg = mac_rule_to_xml(r, rule);
+                break;
+        case ARP_RULE:
+                msg = arp_rule_to_xml(r, rule);
+                break;
+        case IP_RULE:
+                msg = ip_rule_to_xml(r, rule);
+                break;
+        case TCP_RULE:
+                msg = tcp_rule_to_xml(r, rule);
+                break;
+        case ICMP_RULE:
+                msg = icmp_rule_to_xml(r, rule);
+                break;
+        case IGMP_RULE:
+                msg = igmp_rule_to_xml(r, rule);
+                break;
+        case UNKNOWN_RULE:
+        default:
+                CU_DEBUG("Ignoring unknown rule.");
+                break;
+        }
+
+ out:
+        return msg;
+}
+
+char *filter_to_xml(struct acl_filter *filter)
+{
+        char *msg = XML_ERROR;
+        char *xml = NULL;
+        xmlNodePtr root = NULL;
+        xmlNodePtr tmp = NULL;
+        int i;
+
+        root = xmlNewNode(NULL, BAD_CAST "filter");
+        if (root == NULL)
+                goto out;
+
+        if (xmlNewProp(root, BAD_CAST "name", BAD_CAST filter->name) == NULL)
+                goto out;
+
+        if (filter->chain != NULL)
+                if (xmlNewProp(root, BAD_CAST "chain",
+                        BAD_CAST filter->chain) == NULL)
+                        goto out;
+
+        if (filter->uuid != NULL) {
+                tmp = xmlNewChild(root, NULL, BAD_CAST "uuid", NULL);
+                if (xmlNewProp(tmp, NULL, BAD_CAST filter->uuid) == NULL)
+                        goto out;
+        }
+
+        for (i = 0; i < filter->ref_ct; i++) {
+                tmp = xmlNewChild(root, NULL, BAD_CAST "filterref", NULL);
+                if (xmlNewProp(tmp, BAD_CAST "filter",
+                        BAD_CAST filter->refs[i]) == NULL)
+                        goto out;
+        }
+
+        for (i = 0; i < filter->rule_ct; i++) {
+                msg = rule_to_xml(root, filter->rules[i]);
+                if (msg != NULL)
+                        goto out;
+        }
+
+        xml = tree_to_xml(root);
+        if (xml != NULL)
+                msg = NULL; /* no errors */
+
+ out:
+        CU_DEBUG("Filter XML: %s", msg);
+
+        xmlFreeNode(root);
+
+        return xml;
+}
+
 /*
  * Local Variables:
  * mode: C
diff --git a/libxkutil/xmlgen.h b/libxkutil/xmlgen.h
--- a/libxkutil/xmlgen.h
+++ b/libxkutil/xmlgen.h
@@ -23,6 +23,7 @@
 
 #include "device_parsing.h"
 #include "pool_parsing.h"
+#include "acl_parsing.h"
 
 #include "cmpidt.h"
 
@@ -38,4 +39,6 @@
 
 char *res_to_xml(struct virt_pool_res *res);
 
+char *filter_to_xml(struct acl_filter *filter);
+
 #endif
diff --git a/schema/AppliedFilterList.mof b/schema/AppliedFilterList.mof
new file mode 100644
--- /dev/null
+++ b/schema/AppliedFilterList.mof
@@ -0,0 +1,8 @@
+// Copyright IBM Corp. 2011
+[Association,
+ Provider("cmpi::Virt_AppliedFilterList")]
+class KVM_AppliedFilterList : CIM_ConcreteDependency
+{
+        CIM_NetworkPort ref Antecedent;
+        CIM_FilterList ref Dependent;
+};
diff --git a/schema/AppliedFilterList.registration b/schema/AppliedFilterList.registration
new file mode 100644
--- /dev/null
+++ b/schema/AppliedFilterList.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_AppliedFilterList root/virt Virt_AppliedFilterList Virt_AppliedFilterList association
diff --git a/schema/EntriesInFilterList.mof b/schema/EntriesInFilterList.mof
new file mode 100644
--- /dev/null
+++ b/schema/EntriesInFilterList.mof
@@ -0,0 +1,6 @@
+// Copyright IBM Corp. 2011
+[Association,
+ Provider("cmpi::Virt_EntriesInFilterList")]
+class KVM_EntriesInFilterList : CIM_EntriesInFilterList
+{
+};
diff --git a/schema/EntriesInFilterList.registration b/schema/EntriesInFilterList.registration
new file mode 100644
--- /dev/null
+++ b/schema/EntriesInFilterList.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_EntriesInFilterList root/virt Virt_EntriesInFilterList Virt_EntriesInFilterList association
diff --git a/schema/FilterEntry.mof b/schema/FilterEntry.mof
new file mode 100644
--- /dev/null
+++ b/schema/FilterEntry.mof
@@ -0,0 +1,60 @@
+// Copyright IBM Corp. 2010
+[Provider("cmpi::Virt_FilterEntry")]
+class KVM_Hdr8021Filter : CIM_Hdr8021Filter
+{
+		 		  		 		   		 		  		 		    [Description("This defines whether the Filter is used for input, "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "output, or both input and output filtering.  All values are "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "used with respect to the interface for which the Filter "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "applies. \"Not Applicable\" (0) is used when there is no "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "direction applicable to the Filter. \"Input\" (1) is "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "used when the Filter applies to packets that are inbound "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "on the related interface. \"Output\" (2) is used when the "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "Filter applies to packets that are outbound on the "
+                "related interface. \"Both\" (3) is used to indicate that "
+                "the direction is immaterial, e.g., to filter on a source "
+                "subnet regardless of whether the flow is inbound or "
+                "outbound."),
+		 		  		 		   		 		  		 		    ValueMap { "0", "1", "2", "3", "4" },
+		 		  		 		   		 		  		 		    Values { "Not Applicable", "Input, Output", "Both", "Mirrored" }]
+		 		  		 		   		 		  		 		    uint16 Direction;
+
+		 		  		 		   		 		  		 		    [Description("The priority of the rule controls the order in which "
+                "the rule will be, instantiated relative to other rules. "
+                "Rules with lower value will be instantiated and therefore "
+                "evaluated before rules with higher value. Valid values are "
+                "in the range of 0 to 1000. If this attribute is not "
+                "provided, the value 500 will automatically be assigned."),
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    MinValue(0),
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    MaxValue(1000)]
+		 		  		 		   		 		  		 		    uint16 Priority = 500;
+};
+
+[Provider("cmpi::Virt_FilterEntry")]
+class KVM_IPHeadersFilter : CIM_IPHeadersFilter
+{
+		 		  		 		   		 		  		 		    [Description("This defines whether the Filter is used for input, "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "output, or both input and output filtering.  All values are "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "used with respect to the interface for which the Filter "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "applies. \"Not Applicable\" (0) is used when there is no "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "direction applicable to the Filter. \"Input\" (1) is "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "used when the Filter applies to packets that are inbound "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "on the related interface. \"Output\" (2) is used when the "
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    "Filter applies to packets that are outbound on the "
+                "related interface. \"Both\" (3) is used to indicate that "
+                "the direction is immaterial, e.g., to filter on a source "
+                "subnet regardless of whether the flow is inbound or "
+                "outbound."),
+		 		  		 		   		 		  		 		    ValueMap { "0", "1", "2", "3", "4" },
+		 		  		 		   		 		  		 		    Values { "Not Applicable", "Input, Output", "Both", "Mirrored" }]
+		 		  		 		   		 		  		 		    uint16 Direction;
+
+		 		  		 		   		 		  		 		    [Description("The priority of the rule controls the order in which "
+                "the rule will be, instantiated relative to other rules. "
+                "Rules with lower value will be instantiated and therefore "
+                "evaluated before rules with higher value. Valid values are "
+                "in the range of 0 to 1000. If this attribute is not "
+                "provided, the value 500 will automatically be assigned."),
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    MinValue(0),
+		 		  		 		   		 		  		 		    		 		  		 		   		 		  		 		    MaxValue(1000)]
+		 		  		 		   		 		  		 		    uint16 Priority = 500;
+};
diff --git a/schema/FilterEntry.registration b/schema/FilterEntry.registration
new file mode 100644
--- /dev/null
+++ b/schema/FilterEntry.registration
@@ -0,0 +1,4 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_Hdr8021Filter root/virt Virt_FilterEntry Virt_FilterEntry instance
+KVM_IPHeadersFilter root/virt Virt_FilterEntry Virt_FilterEntry instance
diff --git a/schema/FilterList.mof b/schema/FilterList.mof
new file mode 100644
--- /dev/null
+++ b/schema/FilterList.mof
@@ -0,0 +1,4 @@
+// Copyright IBM Corp. 2011
+class KVM_FilterList : CIM_FilterList
+{
+};
diff --git a/schema/FilterList.registration b/schema/FilterList.registration
new file mode 100755
--- /dev/null
+++ b/schema/FilterList.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_FilterList root/virt Virt_FilterList Virt_FilterList instance
diff --git a/schema/HostedFilterList.mof b/schema/HostedFilterList.mof
new file mode 100644
--- /dev/null
+++ b/schema/HostedFilterList.mof
@@ -0,0 +1,6 @@
+// Copyright IBM Corp. 2011
+[Association,
+ Provider("cmpi::Virt_HostedFilterList")]
+class KVM_HostedFilterList : CIM_HostedFilterList
+{
+};
diff --git a/schema/HostedFilterList.registration b/schema/HostedFilterList.registration
new file mode 100644
--- /dev/null
+++ b/schema/HostedFilterList.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_HostedFilterList root/virt Virt_HostedFilterList Virt_HostedFilterList association
diff --git a/schema/NestedFilterList.mof b/schema/NestedFilterList.mof
new file mode 100644
--- /dev/null
+++ b/schema/NestedFilterList.mof
@@ -0,0 +1,8 @@
+// Copyright IBM Corp. 2011
+[Association,
+ Provider("cmpi::Virt_NestedFilterList")]
+class KVM_NestedFilterList : CIM_ConcreteDependency
+{
+        CIM_FilterList ref Antecedent;
+        CIM_FilterList ref Dependent;
+};
diff --git a/schema/NestedFilterList.registration b/schema/NestedFilterList.registration
new file mode 100644
--- /dev/null
+++ b/schema/NestedFilterList.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2011
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+KVM_NestedFilterList root/virt Virt_NestedFilterList Virt_NestedFilterList association
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,7 +23,9 @@
     Virt_VSMigrationSettingData.h \
     Virt_ConsoleRedirectionService.h \
     Virt_ConsoleRedirectionServiceCapabilities.h \
-    Virt_KVMRedirectionSAP.h
+    Virt_KVMRedirectionSAP.h \
+    Virt_FilterList.h \
+    Virt_FilterEntry.h
 
 XKUADD = $(top_builddir)/libxkutil/libxkutil.la
 
@@ -77,7 +79,13 @@
                        libVirt_ServiceAffectsElement.la \
                        libVirt_HostedAccessPoint.la \
                        libVirt_ServiceAccessBySAP.la \
-                       libVirt_SAPAvailableForElement.la
+                       libVirt_SAPAvailableForElement.la \
+                       libVirt_FilterList.la \
+                       libVirt_FilterEntry.la \
+                       libVirt_EntriesInFilterList.la \
+                       libVirt_NestedFilterList.la \
+                       libVirt_HostedFilterList.la \
+                       libVirt_AppliedFilterList.la
 
 libVirt_ComputerSystem_la_SOURCES = Virt_ComputerSystem.c
 libVirt_ComputerSystem_la_DEPENDENCIES = libVirt_VirtualSystemSnapshotService.la
@@ -243,3 +251,26 @@
 libVirt_SAPAvailableForElement_la_SOURCES = Virt_SAPAvailableForElement.c
 libVirt_SAPAvailableForElement_la_LIBADD = -lVirt_ComputerSystem -lVirt_KVMRedirectionSAP
 
+libVirt_FilterEntry_la_DEPENDENCIES = libVirt_HostSystem.la
+libVirt_FilterEntry_la_SOURCES = Virt_FilterEntry.c
+libVirt_FilterEntry_la_LIBADD = -lVirt_HostSystem
+
+libVirt_FilterList_la_DEPENDENCIES = libVirt_HostSystem.la
+libVirt_FilterList_la_SOURCES = Virt_FilterList.c
+libVirt_FilterList_la_LIBADD = -lVirt_HostSystem
+
+libVirt_EntriesInFilterList_la_DEPENDENCIES = libVirt_FilterEntry.la libVirt_FilterList.la 
+libVirt_EntriesInFilterList_la_SOURCES = Virt_EntriesInFilterList.c
+libVirt_EntriesInFilterList_la_LIBADD = -lVirt_FilterEntry -lVirt_FilterList
+
+libVirt_NestedFilterList_la_DEPENDENCIES = libVirt_FilterList.la 
+libVirt_NestedFilterList_la_SOURCES = Virt_NestedFilterList.c
+libVirt_NestedFilterList_la_LIBADD = -lVirt_FilterList
+
+libVirt_HostedFilterList_la_DEPENDENCIES = libVirt_HostSystem.la libVirt_FilterList.la 
+libVirt_HostedFilterList_la_SOURCES = Virt_HostedFilterList.c
+libVirt_HostedFilterList_la_LIBADD = -lVirt_HostSystem -lVirt_FilterList
+
+libVirt_AppliedFilterList_la_DEPENDENCIES = libVirt_Device.la libVirt_FilterList.la
+libVirt_AppliedFilterList_la_SOURCES = Virt_AppliedFilterList.c
+libVirt_AppliedFilterList_la_LIBADD = -lVirt_Device -lVirt_FilterList
diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_AppliedFilterList.c
@@ -0,0 +1,627 @@
+/*
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_association.h>
+#include <libcmpiutil/std_instance.h>
+
+#include "device_parsing.h"
+#include "acl_parsing.h"
+#include "misc_util.h"
+#include "cs_util.h"
+
+#include "Virt_Device.h"
+#include "Virt_FilterList.h"
+
+static const CMPIBroker *_BROKER;
+
+/* TODO: Port to libcmpiutil/args_util.c */
+/**
+ * Get a reference property of an instance
+ *
+ * @param inst The instance
+ * @param prop The property name
+ * @param reference A pointer to a CMPIObjectPath* that will be set
+ *                  if successful
+ * @returns
+ *      - CMPI_RC_OK on success
+ *      - CMPI_RC_ERR_NO_SUCH_PROPERTY if prop is not present
+ *      - CMPI_RC_ERR_TYPE_MISMATCH if prop is not a reference
+ *      - CMPI_RC_OK otherwise
+ */
+static CMPIrc cu_get_ref_prop(const CMPIInstance *instance,
+                              const char *prop,
+                              CMPIObjectPath **reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIData value;
+
+        /* REQUIRE_PROPERY_DEFINED(instance, prop, value, &s); */
+        value = CMGetProperty(instance, prop, &s);
+        if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value))
+                return CMPI_RC_ERR_NO_SUCH_PROPERTY;
+
+        if ((value.type != CMPI_ref) ||  CMIsNullObject(value.value.ref))
+                return CMPI_RC_ERR_TYPE_MISMATCH;
+
+        *reference = value.value.ref;
+
+        return CMPI_RC_OK;
+}
+
+/* TODO: Port to libcmpiutil/args_util.c */
+/**
+ * Get a reference component of an object path
+ *
+ * @param _reference The reference
+ * @param key The key name
+ * @param reference A pointer to a CMPIObjectPath* that will be set
+ *                  if successful
+ * @returns
+ *      - CMPI_RC_OK on success
+ *      - CMPI_RC_ERR_NO_SUCH_PROPERTY if prop is not present
+ *      - CMPI_RC_ERR_TYPE_MISMATCH if prop is not a reference
+ *      - CMPI_RC_OK otherwise
+ */
+static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference,
+                              const char *key,
+                              CMPIObjectPath **_reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIData value;
+
+        /* REQUIRE_PROPERY_DEFINED(instance, prop, value, &s); */
+        value = CMGetKey(reference, key, &s);
+        if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value))
+                return CMPI_RC_ERR_NO_SUCH_PROPERTY;
+
+        /* how to parse and object path? */
+
+        return CMPI_RC_OK;
+}
+
+/* TODO: Port to libxkutil/device_parsing.c */
+static int update_device(virDomainPtr dom,
+                         struct virt_device *dev)
+{
+        char *xml = NULL;
+        int flags = VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
+                    VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
+        int ret = 0;
+
+        /** device_to_xml() is not exported, so this function needs
+         * to be moved
+         */
+
+        /* xml = device_to_xml(dev); */
+
+        if (xml == NULL) {
+                CU_DEBUG("Failed to get XML for device '%s'", dev->id);
+                goto out;
+        }
+
+        if (virDomainUpdateDeviceFlags(dom, xml, flags) != 0) {
+                CU_DEBUG("Failed to dynamically update device:");
+                CU_DEBUG("%s", xml);
+                goto out;
+        }
+
+        ret = 1;
+ out:
+        free(xml);
+
+        return ret;
+}
+
+/* TODO: Port to libxkutil/device_parsing.c */
+static int get_device_by_devid(virDomainPtr dom,
+                               const char *devid,
+                               int type,
+                               struct virt_device **dev)
+{
+        int i, ret = 0;
+        struct virt_device *devices = NULL;
+        int count = get_devices(dom, &devices, type);
+
+        for (i = 0; i < count; i++) {
+                if (STREQC(devid, devices[i].id)) {
+                        *dev = virt_device_dup(&devices[i]);
+                        if (*dev != NULL)
+                                ret = 1;
+
+                        break;
+                }
+        }
+
+        cleanup_virt_devices(&devices, count);
+
+        return ret;
+}
+
+/**
+ *  given a filter, get the network interface
+ */
+static CMPIStatus list_to_net(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+        struct acl_filter *filter = NULL;
+        virDomainPtr *doms = NULL;
+        virConnectPtr conn = NULL;
+        int i, j, dcount, ncount;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        /* validate filter */
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL)
+                goto out;
+
+        cleanup_filter(filter);
+
+        /* get domains */
+        dcount = get_domain_list(conn, &doms);
+        if (dcount < 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to get domain list");
+                goto out;
+        }
+
+        for (i = 0; i < dcount; i++) {
+                /* get domain's network devices */
+                struct virt_device *devices = NULL;
+                ncount = get_devices(doms[i], &devices, CIM_RES_TYPE_NET);
+
+                CU_DEBUG("Found %u network devices", ncount);
+
+                for (j = 0; j < ncount; j++) {
+                        struct net_device *ndev = &(devices[j].dev.net);
+
+                        CU_DEBUG("filterref = %s", ndev->filter_ref);
+
+                        if ((ndev->filter_ref != NULL) &&
+                        STREQC(name, ndev->filter_ref)) {
+                                CU_DEBUG("Getting network device instance");
+
+                                CMPIInstance *instance = NULL;
+                                char *device_id =
+                                        get_fq_devid(
+                                        (char *)virDomainGetName(doms[i]),
+                                        devices[j].id);
+
+                                CU_DEBUG("Processing %s", device_id);
+
+                                s = get_device_by_name(_BROKER,
+                                                        reference,
+                                                        device_id,
+                                                        CIM_RES_TYPE_NET,
+                                                        &instance);
+
+                                if (instance != NULL) {
+                                        CU_DEBUG("adding instance to list");
+                                        inst_list_add(list, instance);
+                                }
+                        }
+                }
+
+                cleanup_virt_devices(&devices, ncount);
+                virDomainFree(doms[i]);
+        }
+
+ out:
+        virConnectClose(conn);
+
+        return s;
+}
+
+/**
+ * given a network interface, find the filter lists
+ */
+static CMPIStatus net_to_list(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+        char *domain_name = NULL;
+        const char *device_name = NULL;
+        char *net_name = NULL;
+        virConnectPtr conn = NULL;
+        virDomainPtr dom = NULL;
+        int i;
+        struct acl_filter *filter = NULL;
+
+        CU_DEBUG("Reference %s", REF2STR(reference));
+
+        /* validate device
+         * TODO: This may be redundant since it's necessary to get
+         * the device structure in order to determine the filter_ref
+         */
+        if (!STREQC(CLASSNAME(reference), "KVM_NetworkPort"))
+                goto out;
+
+        s = get_device_by_ref(_BROKER, reference, &instance);
+        if ((s.rc != CMPI_RC_OK) || (instance == NULL))
+                goto out;
+
+        if (cu_get_str_path(reference, "DeviceID",
+                &device_name) != CMPI_RC_OK) {
+                CU_DEBUG("Failed to get DeviceID");
+                goto out;
+        }
+
+        if (parse_fq_devid(device_name, &domain_name, &net_name) == 0) {
+                CU_DEBUG("Failed to parse devid");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        /* connect to domain */
+        dom = virDomainLookupByName(conn, domain_name);
+        if (dom == NULL) {
+                CU_DEBUG("Failed to connect to Domain '%s'", domain_name);
+                goto out;
+        }
+
+        /* get domain's network devices */
+        struct virt_device *devices = NULL;
+        int count = get_devices(dom, &devices, CIM_RES_TYPE_NET);
+
+        for (i = 0; i < count; i++) {
+                struct net_device *ndev = &(devices[i].dev.net);
+
+                if (STREQC(device_name, devices[i].id)) {
+                        CMPIInstance *instance = NULL;
+
+                        CU_DEBUG("Processing %s", ndev->filter_ref);
+
+                        get_filter_by_name(conn, ndev->filter_ref, &filter);
+                        if (filter == NULL)
+                                continue;
+
+                        s = instance_from_filter(_BROKER,
+                                                info->context,
+                                                reference,
+                                                filter,
+                                                &instance);
+
+                        if (instance != NULL)
+                                inst_list_add(list, instance);
+
+                }
+
+        }
+
+        cleanup_virt_devices(&devices, count);
+ out:
+
+        free(domain_name);
+        free((char *)device_name);
+        free(net_name);
+
+        virDomainFree(dom);
+        virConnectClose(conn);
+
+        return s;
+}
+
+LIBVIRT_CIM_DEFAULT_MAKEREF()
+
+static char *antecedent[] = {
+        "KVM_FilterList",
+        NULL
+};
+
+static char *dependent[] = {
+        "KVM_NetworkPort",
+        NULL
+};
+
+static char *assoc_class_name[] = {
+        "KVM_AppliedFilterList",
+        NULL
+};
+
+static struct std_assoc _list_to_net = {
+        .source_class = (char **)&antecedent,
+        .source_prop = "Antecedent",
+
+        .target_class = (char **)&dependent,
+        .target_prop = "Dependent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = list_to_net,
+        .make_ref = make_ref
+};
+
+static struct std_assoc _net_to_list = {
+        .source_class = (char **)&dependent,
+        .source_prop = "Dependent",
+
+        .target_class = (char **)&antecedent,
+        .target_prop = "Antecedent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = net_to_list,
+        .make_ref = make_ref
+};
+
+static struct std_assoc *handlers[] = {
+        &_list_to_net,
+        &_net_to_list,
+        NULL
+};
+
+STDA_AssocMIStub(,
+        Virt_AppliedFilterList,
+        _BROKER,
+        libvirt_cim_init(),
+        handlers);
+
+DEFAULT_GI();
+DEFAULT_EIN();
+DEFAULT_EI();
+
+static CMPIStatus CreateInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *antecedent = NULL;
+        const char *filter_name = NULL;
+        struct acl_filter *filter = NULL;
+        CMPIObjectPath *dependent = NULL;
+        char *domain_name = NULL;
+        const char *device_name = NULL;
+        char *net_name = NULL;
+        struct virt_device *device = NULL;
+        virConnectPtr conn = NULL;
+        virDomainPtr dom = NULL;
+
+        if (cu_get_ref_prop(instance, "Antecedent",
+                &antecedent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &filter_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Antecedent.Name object does not exist");
+                goto out;
+        }
+
+        if (cu_get_ref_prop(instance, "Dependent",
+                &dependent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "DeviceID",
+                &device_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent.DeviceID property");
+                goto out;
+        }
+
+        if (parse_fq_devid(device_name, &domain_name, &net_name) == 0) {
+                CU_DEBUG("Failed to parse devid");
+                goto out;
+        }
+
+        dom = virDomainLookupByName(conn, domain_name);
+        if (dom == NULL) {
+                CU_DEBUG("Failed to connect to Domain '%s'", domain_name);
+                goto out;
+        }
+
+        get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device);
+        if (device == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Dependent.Name object does not exist");
+                goto out;
+        }
+
+        free(device->dev.net.filter_ref);
+        device->dev.net.filter_ref = strdup(filter_name);
+
+        if (update_device(dom, device) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to update device");
+                goto out;
+        }
+
+ out:
+        free((char *)filter_name);
+        free(domain_name);
+        free((char *)device_name);
+        free(net_name);
+
+        cleanup_filter(filter);
+        cleanup_virt_device(device);
+
+        virDomainFree(dom);
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus DeleteInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *antecedent = NULL;
+        const char *filter_name = NULL;
+        struct acl_filter *filter = NULL;
+        CMPIObjectPath *dependent = NULL;
+        char *domain_name = NULL;
+        const char *device_name = NULL;
+        char *net_name = NULL;
+        struct virt_device *device = NULL;
+        virConnectPtr conn = NULL;
+        virDomainPtr dom = NULL;
+
+        if (cu_get_ref_path(reference, "Antecedent",
+                &antecedent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &filter_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Antecedent.Name object does not exist");
+                goto out;
+        }
+
+        if (cu_get_ref_path(reference, "Dependent",
+                &dependent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "DeviceID",
+                &device_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent.DeviceID property");
+                goto out;
+        }
+
+        if (parse_fq_devid(device_name, &domain_name, &net_name) == 0) {
+                CU_DEBUG("Failed to parse devid");
+                goto out;
+        }
+
+        dom = virDomainLookupByName(conn, domain_name);
+        if (dom == NULL) {
+                CU_DEBUG("Failed to connect to Domain '%s'", domain_name);
+                goto out;
+        }
+
+        get_device_by_devid(dom, net_name, CIM_RES_TYPE_NET, &device);
+        if (device == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Dependent.Name object does not exist");
+                goto out;
+        }
+
+        free(device->dev.net.filter_ref);
+        device->dev.net.filter_ref = NULL;
+
+        if (update_device(dom, device) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to update device");
+                goto out;
+        }
+
+ out:
+        free((char *)filter_name);
+        free(domain_name);
+        free((char *)device_name);
+        free(net_name);
+
+        cleanup_filter(filter);
+        cleanup_virt_device(device);
+
+        virDomainFree(dom);
+        virConnectClose(conn);
+
+        return s;
+}
+
+DEFAULT_MI();
+DEFAULT_EQ();
+DEFAULT_INST_CLEANUP();
+
+STD_InstanceMIStub(,
+        Virt_AppliedFilterEntry,
+        _BROKER,
+        libvirt_cim_init());
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_EntriesInFilterList.c b/src/Virt_EntriesInFilterList.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_EntriesInFilterList.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_association.h>
+
+#include <strings.h>
+
+#include "acl_parsing.h"
+#include "misc_util.h"
+#include "Virt_FilterList.h"
+#include "Virt_FilterEntry.h"
+
+static const CMPIBroker *_BROKER;
+
+/**
+ *  given a filter, find all *direct* children
+ */
+static CMPIStatus list_to_rule(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+        struct acl_filter *filter = NULL;
+        const char *name = NULL;
+        virConnectPtr conn = NULL;
+        int i;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        name = CMGetCharsPtr(CMGetKey(reference, "Name", &s).value.string, &s);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL)
+                goto out;
+
+        for (i = 0; i < filter->rule_ct; i++) {
+
+                CU_DEBUG("Processing %s", filter->rules[i]->name);
+
+                s = instance_from_rule(_BROKER,
+                                        info->context,
+                                        reference,
+                                        filter->rules[i],
+                                        &instance);
+
+                if (instance != NULL) {
+                        inst_list_add(list, instance);
+                        instance = NULL;
+                }
+        }
+
+        cleanup_filter(filter);
+
+ out:
+        virConnectClose(conn);
+
+        return s;
+}
+
+/**
+ * given a rule, fine the parent filter
+ */
+static CMPIStatus rule_to_list(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct acl_filter *_list = NULL;
+        struct acl_filter *filter = NULL;
+        CMPIInstance *instance = NULL;
+        const char *name = NULL;
+        virConnectPtr conn = NULL;
+        int count, i, j;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        name = CMGetCharsPtr(CMGetKey(reference, "Name", &s).value.string, &s);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        count = get_filters(conn, &_list);
+        if (_list == NULL)
+                goto out;
+
+        /* return the filter that contains the rule */
+        for (i = 0; i < count; i++) {
+                for (j = 0; j < _list[i].rule_ct; j++) {
+                        if (STREQC(name, _list[i].rules[j]->name)) {
+                                CU_DEBUG("Processing %s,", _list[i].name);
+
+                                s = instance_from_filter(_BROKER,
+                                                        info->context,
+                                                        reference,
+                                                        &_list[i],
+                                                        &instance);
+
+                                if (instance != NULL)
+                                        inst_list_add(list, instance);
+
+                                cleanup_filter(filter);
+
+                                filter = NULL;
+                                instance = NULL;
+                        }
+
+                }
+        }
+
+ out:
+        virConnectClose(conn);
+
+        return s;
+}
+
+LIBVIRT_CIM_DEFAULT_MAKEREF()
+
+static char *group_component[] = {
+        "KVM_FilterList",
+        NULL
+};
+
+static char *part_component[] = {
+        "KVM_Hdr8021Filter",
+        "KVM_IPHeadersFilter",
+        NULL
+};
+
+static char *assoc_class_name[] = {
+        "KVM_EntriesInFilterList",
+        NULL
+};
+
+static struct std_assoc _list_to_rule = {
+        .source_class = (char **)&group_component,
+        .source_prop = "GroupComponent",
+
+        .target_class = (char **)&part_component,
+        .target_prop = "PartComponent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = list_to_rule,
+        .make_ref = make_ref
+};
+
+static struct std_assoc _rule_to_list = {
+        .source_class = (char **)&part_component,
+        .source_prop = "PartComponent",
+
+        .target_class = (char **)&group_component,
+        .target_prop = "GroupComponent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = rule_to_list,
+        .make_ref = make_ref
+};
+
+static struct std_assoc *handlers[] = {
+        &_list_to_rule,
+        &_rule_to_list,
+        NULL
+};
+
+STDA_AssocMIStub(,
+        Virt_EntriesInFilterList,
+        _BROKER,
+        libvirt_cim_init(),
+        handlers);
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_FilterEntry.c b/src/Virt_FilterEntry.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_FilterEntry.c
@@ -0,0 +1,886 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_instance.h>
+
+#include <arpa/inet.h>
+
+#include "acl_parsing.h"
+#include "misc_util.h"
+#include "xmlgen.h"
+
+#include "Virt_FilterEntry.h"
+#include "Virt_HostSystem.h"
+
+const static CMPIBroker *_BROKER;
+
+static bool is_mac_rule(int type)
+{
+        if (type == MAC_RULE || type == ARP_RULE)
+                return 1;
+
+        return 0;
+}
+
+static bool is_ip_rule(int type)
+{
+        if (type == IP_RULE || type == TCP_RULE || type == ICMP_RULE ||
+                type == IGMP_RULE)
+                return 1;
+
+        return 0;
+}
+
+static int octets_from_mac(const char * s, unsigned int *buffer,
+                                unsigned int size)
+{
+        unsigned int _buffer[6];
+        unsigned int i, ret;
+
+        if ((s == 0) || (buffer == NULL) || (size < 6))
+                return 0;
+
+        ret = sscanf(s, "%x:%x:%x:%x:%x:%x",
+                &_buffer[0], &_buffer[1], &_buffer[2],
+                &_buffer[3], &_buffer[4], &_buffer[5]);
+
+        for (i = 0; i < ret; i++)
+                buffer[i] = _buffer[i];
+
+        return ret;
+}
+
+static int octets_from_ip(const char * s, unsigned int *buffer,
+                                unsigned int size)
+{
+        struct in6_addr addr;
+        unsigned int family = 0;
+        unsigned int n = 0;
+        int i;
+
+        if (s == 0)
+                return 0;
+
+        family = strstr(s, ":") ? AF_INET6 : AF_INET;
+        n  = family == AF_INET6 ? 16 : 4;
+
+        if (size < n)
+                return 0;
+
+        if (inet_pton(family, s, &addr)) {
+                n = n <= size ? n : size;
+                for (i = 0; i < n; i++)
+                        buffer[i] = addr.s6_addr[i];
+        }
+
+        return n;
+}
+
+static CMPIArray *octets_to_cmpi(unsigned int *bytes, int size)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIArray *array = NULL;
+        int i;
+
+        if (bytes == 0 || size == 0)
+                return array;
+
+        array = CMNewArray(_BROKER, size, CMPI_uint8, &s);
+
+        for (i = 0; i < size; i++) {
+                s = CMSetArrayElementAt(array, i,
+                        (CMPIValue*)&bytes[i], CMPI_uint8);
+        }
+
+        return array;
+}
+
+static int convert_direction(const char *s)
+{
+        enum {NOT_APPLICABLE, INPUT, OUTPUT, BOTH} direction = NOT_APPLICABLE;
+
+        if (s != NULL) {
+                if (STREQC(s, "in"))
+                        direction = INPUT;
+                else if (STREQC(s, "out"))
+                        direction = OUTPUT;
+                else if (STREQC(s, "inout"))
+                        direction = BOTH;
+        }
+
+        return direction;
+}
+
+static int convert_priority(const char *s)
+{
+        int priority = 0;
+
+        if (s != NULL) {
+                priority = atoi(s);
+        }
+
+        return priority;
+}
+
+static int parse_rule_name(const char *name, char **filter, int *index)
+{
+        int ret;
+
+        ret = sscanf(name, "%a[^:]:%u", filter, index);
+        if (ret != 2) {
+                free(*filter);
+                return 0;
+        }
+
+        return 1;
+}
+
+
+static CMPIInstance *convert_mac_rule_to_instance(
+        struct acl_rule *rule,
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        CMPIStatus *s)
+{
+        CMPIInstance *inst = NULL;
+        const char *sys_name = NULL;
+        const char *sys_ccname = NULL;
+        int direction, priority = 0;
+        unsigned int bytes[48];
+        unsigned int size = 0;
+        CMPIArray *array = NULL;
+
+        inst = get_typed_instance(broker,
+                                  CLASSNAME(reference),
+                                  "Hdr8021Filter",
+                                  NAMESPACE(reference));
+        if (inst == NULL) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get 8021 filter instance");
+
+                goto out;
+        }
+
+        *s = get_host_system_properties(&sys_name,
+                                       &sys_ccname,
+                                       reference,
+                                       broker,
+                                       context);
+
+        if (s->rc != CMPI_RC_OK) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get host attributes");
+                goto out;
+        }
+
+        CMSetProperty(inst, "SystemName", sys_name, CMPI_chars);
+        CMSetProperty(inst, "SystemCreationClassName", sys_ccname, CMPI_chars);
+        CMSetProperty(inst, "Name", (CMPIValue *)rule->name, CMPI_chars);
+
+        direction = convert_direction(rule->direction);
+        CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16);
+
+        priority = convert_priority(rule->priority);
+        CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_uint16);
+
+        size = octets_from_mac(rule->var.mac.srcmacaddr,
+                bytes, sizeof(bytes));
+
+        array = octets_to_cmpi(bytes, size);
+        if (array != NULL)
+                CMSetProperty(inst, "HdrSrcMACAddr8021",
+                        (CMPIValue *)&array, CMPI_uint8A);
+
+        size = octets_from_mac(rule->var.mac.srcmacmask,
+                bytes, sizeof(bytes));
+
+        array = octets_to_cmpi(bytes, size);
+        if (array != NULL)
+                CMSetProperty(inst, "HdrSrcMACMask8021",
+                        (CMPIValue *)&array, CMPI_uint8A);
+
+        size = octets_from_mac(rule->var.mac.dstmacaddr,
+                bytes, sizeof(bytes));
+
+        array = octets_to_cmpi(bytes, size);
+        if (array != NULL)
+                CMSetProperty(inst, "HdrDestMACAddr8021", (CMPIValue *)
+                        (CMPIValue *)&array, CMPI_uint8A);
+
+        size = octets_from_mac(rule->var.mac.dstmacmask,
+                bytes, sizeof(bytes));
+
+        array = octets_to_cmpi(bytes, size);
+        if (array != NULL)
+                CMSetProperty(inst, "HdrDestMACMask8021", (CMPIValue *)
+                        (CMPIValue *)&array, CMPI_uint8A);
+
+ out:
+        return inst;
+}
+
+static CMPIInstance *convert_ip_rule_to_instance(
+        struct acl_rule *rule,
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        CMPIStatus *s)
+{
+        CMPIInstance *inst = NULL;
+        const char *sys_name = NULL;
+        const char *sys_ccname = NULL;
+        int direction, priority = 0;
+        unsigned int bytes[48];
+        unsigned int size = 0;
+        unsigned int n = 0;
+        CMPIArray *array = NULL;
+
+        inst = get_typed_instance(broker,
+                                  CLASSNAME(reference),
+                                  "IPHeadersFilter",
+                                  NAMESPACE(reference));
+        if (inst == NULL) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get ip headers filter instance");
+                goto out;
+        }
+
+        *s = get_host_system_properties(&sys_name,
+                                       &sys_ccname,
+                                       reference,
+                                       broker,
+                                       context);
+
+        if (s->rc != CMPI_RC_OK) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get host attributes");
+                goto out;
+        }
+
+        CMSetProperty(inst, "SystemName", sys_name, CMPI_chars);
+        CMSetProperty(inst, "SystemCreationClassName", sys_ccname, CMPI_chars);
+        CMSetProperty(inst, "Name", (CMPIValue *)rule->name, CMPI_chars);
+
+        direction = convert_direction(rule->direction);
+        CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16);
+
+        priority = convert_priority(rule->priority);
+        CMSetProperty(inst, "Priority", (CMPIValue *)&priority, CMPI_uint16);
+
+        if (strstr(rule->protocol_id, "v6"))
+                n = 6;
+        else
+                n = 4;
+
+        CMSetProperty(inst, "HdrIPVersion",(CMPIValue *)&n, CMPI_uint8);
+
+        if (rule->var.tcp.srcipfrom && rule->var.tcp.srcipto) {
+                size = octets_from_ip(rule->var.tcp.srcipfrom,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrSrcAddress",
+                                (CMPIValue *)&array, CMPI_uint8A);
+
+                size = octets_from_ip(rule->var.tcp.srcipto,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrSrcAddressEndOfRange",
+                                (CMPIValue *)&array, CMPI_uint8A);
+        } else {
+                size = octets_from_ip(rule->var.tcp.srcmacaddr,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrSrcAddress",
+                                (CMPIValue *)&array, CMPI_uint8A);
+
+                size = octets_from_ip(rule->var.tcp.srcipmask,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrSrcMask",
+                                (CMPIValue *)&array, CMPI_uint8A);
+        }
+
+        if (rule->var.tcp.dstipfrom && rule->var.tcp.dstipto) {
+                size = octets_from_ip(rule->var.tcp.dstipfrom,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrDestAddress",
+                                (CMPIValue *)&array, CMPI_uint8A);
+
+                size = octets_from_ip(rule->var.tcp.dstipto,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrDestAddressEndOfRange",
+                                (CMPIValue *)&array, CMPI_uint8A);
+        } else {
+                size = octets_from_ip(rule->var.tcp.dstipaddr,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrDestAddress",
+                                (CMPIValue *)&array, CMPI_uint8A);
+
+                size = octets_from_ip(rule->var.tcp.dstipmask,
+                        bytes, sizeof(bytes));
+
+                array = octets_to_cmpi(bytes, size);
+                if (array != NULL)
+                        CMSetProperty(inst, "HdrDestMask",
+                                (CMPIValue *)&array, CMPI_uint8A);
+        }
+
+        if ((rule->type == IP_RULE) || (rule->type == TCP_RULE)) {
+                if (rule->var.tcp.srcportstart) {
+                        n = atoi(rule->var.tcp.srcportstart);
+                        CMSetProperty(inst, "HdrSrcPortStart",
+                                (CMPIValue *)&n, CMPI_uint16);
+                }
+
+                if (rule->var.tcp.srcportend) {
+                        n = atoi(rule->var.tcp.srcportend);
+                        CMSetProperty(inst, "HdrSrcPortEnd",
+                                (CMPIValue *)&n, CMPI_uint16);
+                }
+
+                if (rule->var.tcp.dstportstart) {
+                        n = atoi(rule->var.tcp.dstportstart);
+                        CMSetProperty(inst, "HdrDestPortStart",
+                                (CMPIValue *)&n, CMPI_uint16);
+                }
+
+                if (rule->var.tcp.dstportend) {
+                        n = atoi(rule->var.tcp.dstportend);
+                        CMSetProperty(inst, "HdrDestPortEnd",
+                                (CMPIValue *)&n, CMPI_uint16);
+                }
+        }
+
+ out:
+        return inst;
+}
+
+static CMPIInstance *convert_rule_to_instance(
+        struct acl_rule *rule,
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        CMPIStatus *s)
+{
+        CMPIInstance *instance = NULL;
+
+        if (rule == NULL)
+                return NULL;
+
+        if(is_mac_rule(rule->type)) {
+                instance = convert_mac_rule_to_instance(rule,
+                                                broker,
+                                                context,
+                                                reference,
+                                                s);
+        }
+        else if(is_ip_rule(rule->type)) {
+                instance = convert_ip_rule_to_instance(rule,
+                                                broker,
+                                                context,
+                                                reference,
+                                                s);
+        }
+
+        return instance;
+}
+
+static struct acl_rule *convert_instance_to_rule(
+        const CMPIInstance *instance)
+{
+        struct acl_rule *rule = NULL;
+
+        return rule;
+}
+
+CMPIStatus enum_filter_rules(
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        struct inst_list *list)
+{
+        virConnectPtr conn = NULL;
+        struct acl_filter *filters = NULL;
+        int i, j, count = 0;
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        enum {NONE, MAC, IP, FILTER} class_type = NONE;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        if (STREQC(CLASSNAME(reference), "KVM_Hdr8021Filter"))
+                class_type = MAC;
+        else if (STREQC(CLASSNAME(reference), "KVM_IPHeadersFilter"))
+                class_type = IP;
+        else if (STREQC(CLASSNAME(reference), "KVM_FilterEntry"))
+                class_type = FILTER;
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        count = get_filters(conn, &filters);
+
+        CU_DEBUG("Found %d filters", count);
+
+        for (i = 0; i < count; i++) {
+                for (j = 0; j < filters[i].rule_ct; j++) {
+                        CMPIInstance *instance = NULL;
+
+                        if (((class_type == NONE) ||
+                                (class_type == MAC)) &&
+                                is_mac_rule(filters[i].rules[j]->type)) {
+                                instance = convert_mac_rule_to_instance(
+                                                filters[i].rules[j],
+                                                broker,
+                                                context,
+                                                reference,
+                                                &s);
+                        }
+                        else if (((class_type == NONE) ||
+                                (class_type == IP)) &&
+                                is_ip_rule(filters[i].rules[j]->type)) {
+                                instance = convert_ip_rule_to_instance(
+                                                filters[i].rules[j],
+                                                broker,
+                                                context,
+                                                reference,
+                                                &s);
+                        }
+                        else
+                                CU_DEBUG("Unrecognized rule type %u",
+                                        filters[i].rules[j]->type);
+
+                        if (instance != NULL)
+                                inst_list_add(list, instance);
+                }
+
+        }
+
+ out:
+        cleanup_filters(&filters, count);
+        virConnectClose(conn);
+
+        return s;
+}
+
+CMPIStatus get_rule_by_ref(
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        CMPIInstance **instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct acl_filter *filter = NULL;
+        struct acl_rule *rule = NULL;
+        const char *name = NULL;
+        char *filter_name = NULL;
+        int rule_index;
+        virConnectPtr conn = NULL;
+        int ret, i;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        ret = sscanf(name, "%a[^:]:%u", &filter_name, &rule_index);
+        if (ret != 2) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not parse filter name");
+                goto out;
+        }
+
+        CU_DEBUG("Filter name = %s, rule index = %u", filter_name, rule_index);
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve filter");
+                goto out;
+        }
+
+        for (i = 0; i < filter->rule_ct; i++) {
+                if (rule_index == i) {
+                        rule = filter->rules[i];
+                        break;
+                }
+        }
+
+        if (rule == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve rule");
+                goto out;
+        }
+
+        *instance = convert_rule_to_instance(rule,
+                                        broker,
+                                        context,
+                                        reference,
+                                        &s);
+ out:
+        free(filter_name);
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+
+CMPIStatus instance_from_rule(
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        struct acl_rule *rule,
+        CMPIInstance **instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+
+        *instance = convert_rule_to_instance(rule,
+                                        broker,
+                                        context,
+                                        reference,
+                                        &s);
+
+        return s;
+
+}
+
+static CMPIStatus GetInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+
+        s = get_rule_by_ref(_BROKER, context, reference, &instance);
+
+        if (instance != NULL)
+                CMReturnInstance(results, instance);
+
+        return s;
+}
+
+static CMPIStatus EnumInstanceNames(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct inst_list list;
+
+        inst_list_init(&list);
+
+        s = enum_filter_rules(_BROKER, context, reference, &list);
+
+        cu_return_instance_names(results, &list);
+
+        inst_list_free(&list);
+
+        return s;
+}
+
+static CMPIStatus EnumInstances(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct inst_list list;
+
+        inst_list_init(&list);
+
+        s = enum_filter_rules(_BROKER, context, reference, &list);
+
+        cu_return_instances(results, &list);
+
+        return s;
+}
+
+static CMPIStatus CreateInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+        virConnectPtr conn = NULL;
+        struct acl_filter *filter = NULL;
+        struct acl_rule *rule = NULL;
+        char *filter_name = NULL;
+        int index;
+
+        /** Get Name from instance rather than reference since keys
+         * are set by this provider, not the client.
+         */
+        if (cu_get_str_prop(instance, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get Name property");
+                goto out;
+        }
+
+        if (parse_rule_name(name, &filter_name, &index) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to parse Name property");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter != NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve parent filter");
+                CU_DEBUG("%s:%s", s.msg, filter_name);
+                goto out;
+        }
+
+        rule = convert_instance_to_rule(instance);
+        if (rule == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to convert instance");
+                goto out;
+        }
+
+        append_filter_rule(filter, rule);
+        update_filter(conn, filter);
+
+ out:
+        free(filter_name);
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus ModifyInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        virConnectPtr conn = NULL;
+        struct acl_filter *filter = NULL;
+        struct acl_rule *rule = NULL;
+        const char *name = NULL;
+        char *filter_name = NULL;
+        int i, index;
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        if (parse_rule_name(name, &filter_name, &index) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to parse Name property");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter != NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve parent filter");
+                goto out;
+        }
+
+        for (i = 0; i < filter->rule_ct; i++) {
+                if (index == i) {
+                        rule = filter->rules[i];
+                        break;
+                }
+        }
+
+        if (rule == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve rule");
+                goto out;
+        }
+
+        /* TODO: Needs to be done so that previous instance is not
+         * removed if error occurs later
+         */
+        remove_filter_rule(filter, rule);
+        cleanup_rule(rule);
+
+        rule = convert_instance_to_rule(instance);
+        if (rule == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to convert instance");
+                goto out;
+        }
+
+        append_filter_rule(filter, rule);
+        update_filter(conn, filter);
+
+ out:
+        free(filter_name);
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus DeleteInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        virConnectPtr conn = NULL;
+        struct acl_filter *filter = NULL;
+        struct acl_rule *rule = NULL;
+        const char *name = NULL;
+        char *filter_name = NULL;
+        int i, index;
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        if (parse_rule_name(name, &filter_name, &index) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to parse Name property");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, filter_name, &filter);
+        if (filter != NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve parent filter");
+                goto out;
+        }
+
+        for (i = 0; i < filter->rule_ct; i++) {
+                if (i == index) {
+                        rule = filter->rules[i];
+                        break;
+                }
+        }
+
+        if (rule == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Could not retrieve rule");
+                goto out;
+        }
+
+        remove_filter_rule(filter, rule);
+        update_filter(conn, filter);
+
+ out:
+        free(filter_name);
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+DEFAULT_EQ();
+DEFAULT_INST_CLEANUP();
+
+STD_InstanceMIStub(,
+        Virt_FilterEntry,
+        _BROKER,
+        libvirt_cim_init());
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_FilterEntry.h b/src/Virt_FilterEntry.h
new file mode 100644
--- /dev/null
+++ b/src/Virt_FilterEntry.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#ifndef __VIRT_FILTERENTRY_H
+#define __VIRT_FILTERENTRY_H
+
+/**
+ * Return a list of filter instances
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying the parent filter
+ * @param list A pointer to an array of CMPIInstance objects
+ *             (called inits before and frees after)
+ */
+CMPIStatus enum_filter_rules(
+                const CMPIBroker *broker,
+                const CMPIContext *context,
+                const CMPIObjectPath *reference,
+                struct inst_list *list);
+
+/**
+ * Return a single filter instance by reference
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying the parent filter
+ * @param list A pointer to a CMPIInstance *
+ */
+CMPIStatus get_rule_by_ref(
+                const CMPIBroker *broker,
+                const CMPIContext *context,
+                const CMPIObjectPath *reference,
+                CMPIInstance **instance);
+
+/**
+ * Get an instance representing a filter rule
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying the parent filter
+ * @param rule A pointer to a filter rule
+ * @param instance A pointer to a CMPIInstance *
+ */
+CMPIStatus instance_from_rule(
+                const CMPIBroker *broker,
+                const CMPIContext *context,
+                const CMPIObjectPath *reference,
+                struct acl_rule *rule,
+                CMPIInstance **instance);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_FilterList.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_instance.h>
+
+#include "acl_parsing.h"
+#include "misc_util.h"
+#include "xmlgen.h"
+
+#include "Virt_FilterList.h"
+#include "Virt_HostSystem.h"
+
+const static CMPIBroker *_BROKER;
+
+static CMPIInstance *convert_filter_to_instance(
+        struct acl_filter *filter,
+        const CMPIBroker *broker,
+        const CMPIContext *context,
+        const CMPIObjectPath *reference,
+        CMPIStatus *s)
+{
+        CMPIInstance *inst = NULL;
+        const char *sys_name = NULL;
+        const char *sys_ccname = NULL;
+        int direction = 0;
+
+        inst = get_typed_instance(broker,
+                                  CLASSNAME(reference),
+                                  "FilterList",
+                                  NAMESPACE(reference));
+        if (inst == NULL) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get filter list instance");
+                goto out;
+        }
+
+        *s = get_host_system_properties(&sys_name,
+                                       &sys_ccname,
+                                       reference,
+                                       broker,
+                                       context);
+
+        if (s->rc != CMPI_RC_OK) {
+                cu_statusf(broker, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get host attributes");
+                goto out;
+        }
+
+        CMSetProperty(inst, "SystemName", sys_name, CMPI_chars);
+        CMSetProperty(inst, "SystemCreationClassName", sys_ccname, CMPI_chars);
+        CMSetProperty(inst, "Name", (CMPIValue *)filter->name, CMPI_chars);
+        CMSetProperty(inst, "InstanceID", (CMPIValue *)filter->uuid,
+                        CMPI_chars);
+        CMSetProperty(inst, "Direction", (CMPIValue *)&direction, CMPI_uint16);
+
+ out:
+        return inst;
+}
+
+static struct acl_filter *convert_instance_to_filter(
+        const CMPIInstance *instance,
+        const CMPIContext *context,
+        CMPIStatus *s)
+{
+        struct acl_filter *filter = NULL;
+        const char *name = NULL;
+
+        if (cu_get_str_prop(instance, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get Name property");
+                goto out;
+        }
+
+        filter = malloc(sizeof(*filter));
+        if (filter == NULL)
+                goto out;
+
+        memset(filter, 0, sizeof(*filter));
+        filter->name = (char *)name;
+
+ out:
+        return filter;
+}
+
+CMPIStatus enum_filter_lists(const CMPIBroker *broker,
+                        const CMPIContext *context,
+                        const CMPIObjectPath *reference,
+                        struct inst_list *list)
+{
+        virConnectPtr conn = NULL;
+        struct acl_filter *filters = NULL;
+        int i, count = 0;
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+
+        conn = connect_by_classname(broker, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        count = get_filters(conn, &filters);
+
+        CU_DEBUG("found %d filters", count);
+
+        for (i = 0; i < count; i++) {
+                instance = convert_filter_to_instance(&filters[i],
+                                                broker,
+                                                context,
+                                                reference,
+                                                &s);
+
+                if (instance != NULL)
+                        inst_list_add(list, instance);
+        }
+
+ out:
+        cleanup_filters(&filters, count);
+        virConnectClose(conn);
+
+        return s;
+}
+
+CMPIStatus get_filter_by_ref(const CMPIBroker *broker,
+                        const CMPIContext *context,
+                        const CMPIObjectPath *reference,
+                        CMPIInstance **instance)
+{
+        virConnectPtr conn = NULL;
+        struct acl_filter *filter = NULL;
+
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(broker, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "No such instance (Name)");
+                goto out;
+        }
+
+        s = instance_from_filter(broker, context, reference, filter, instance);
+
+ out:
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+CMPIStatus instance_from_filter(const CMPIBroker *broker,
+                        const CMPIContext *context,
+                        const CMPIObjectPath *reference,
+                        struct acl_filter *filter,
+                        CMPIInstance **instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+
+        *instance = convert_filter_to_instance(filter, broker, context,
+                                                reference, &s);
+
+        return s;
+}
+
+static CMPIStatus GetInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+
+        s = get_filter_by_ref(_BROKER, context, reference, &instance);
+
+        if (instance != NULL)
+                CMReturnInstance(results, instance);
+
+        return s;
+}
+
+static CMPIStatus EnumInstanceNames(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct inst_list list;
+
+        inst_list_init(&list);
+
+        s = enum_filter_lists(_BROKER, context, reference, &list);
+
+        cu_return_instance_names(results, &list);
+
+        inst_list_free(&list);
+
+        return s;
+}
+
+static CMPIStatus EnumInstances(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct inst_list list;
+
+        inst_list_init(&list);
+
+        s = enum_filter_lists(_BROKER, context, reference, &list);
+
+        cu_return_instances(results, &list);
+
+        inst_list_free(&list);
+
+        return s;
+}
+
+static CMPIStatus CreateInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+        struct acl_filter *filter = NULL;
+        CMPIInstance *_instance = NULL;
+        virConnectPtr conn = NULL;
+
+        /**Get Name from instance rather than reference since keys
+         * are set by this provider, not the client.
+         */
+        if (cu_get_str_prop(instance, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get Name property");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter != NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_ALREADY_EXISTS,
+                        "Instance already exists");
+                goto out;
+        }
+
+        filter = convert_instance_to_filter(instance, context, &s);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to convert instance to filter");
+                goto out;
+        }
+
+        if (create_filter(conn, filter) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to create filter");
+                goto out;
+        }
+
+        cleanup_filter(filter);
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to get filter");
+                goto out;
+        }
+
+        _instance = convert_filter_to_instance(filter,
+                                        _BROKER,
+                                        context,
+                                        reference,
+                                        &s);
+
+        if(_instance != NULL)
+                cu_return_instance_name(results, _instance);
+
+        CU_DEBUG("CreateInstance complete");
+
+ out:
+        free((char *)name);
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus ModifyInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance,
+        const char **properties)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+        struct acl_filter *filter = NULL;
+        virConnectPtr conn = NULL;
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Instance does not exist");
+                goto out;
+        }
+
+        filter = convert_instance_to_filter(instance, context, &s);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Failed to convert instance to filter");
+                goto out;
+        }
+
+        if (create_filter(conn, filter) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to create filter");
+                goto out;
+        }
+ out:
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus DeleteInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        const char *name = NULL;
+        struct acl_filter *filter = NULL;
+        virConnectPtr conn = NULL;
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &filter);
+        if (filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Instance does not exist");
+                goto out;
+        }
+
+        delete_filter(conn, filter);
+
+ out:
+        cleanup_filter(filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+DEFAULT_EQ();
+DEFAULT_INST_CLEANUP();
+
+STD_InstanceMIStub(,
+        Virt_FilterList,
+        _BROKER,
+        libvirt_cim_init());
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_FilterList.h b/src/Virt_FilterList.h
new file mode 100644
--- /dev/null
+++ b/src/Virt_FilterList.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#ifndef __VIRT_FILTERLIST_H
+#define __VIRT_FILTERLIST_H
+
+#include "acl_parsing.h"
+
+/**
+ * Return a list of filter lists
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying a specific filter
+ * @param list A pointer to an array of CMPIInstance objects
+ *             (caller inits before and frees after)
+ */
+CMPIStatus enum_filter_lists(
+                const CMPIBroker *broker,
+                const CMPIContext *context,
+                const CMPIObjectPath *reference,
+                struct inst_list *list);
+
+/**
+ * Return a filter instance by reference
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying a specific filter
+ * @param instance A pointer to a CMPIInstance * to place the new instance
+ */
+CMPIStatus get_filter_by_ref(
+                const CMPIBroker *broker,
+                const CMPIContext *contest,
+                const CMPIObjectPath *reference,
+                CMPIInstance **instance);
+
+/**
+ * Return a list of filter lists
+ *
+ * @param broker A pointer to the CIM broker
+ * @param context A pointer to an operation context
+ * @param reference Defines the libvirt connection to use (via class name
+ *             prefix), but can also be used to scope the results by
+ *             specifying a specific filter
+ * @param filter A pointer to a acl_filter
+ * @param instance A pointer to a CMPIInstance * to place the new instance
+ */
+CMPIStatus instance_from_filter(
+                const CMPIBroker *broker,
+                const CMPIContext *context,
+                const CMPIObjectPath *reference,
+                struct acl_filter *filter,
+                CMPIInstance **instance);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_HostedFilterList.c b/src/Virt_HostedFilterList.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_HostedFilterList.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_association.h>
+
+#include "misc_util.h"
+#include "Virt_HostSystem.h"
+#include "Virt_FilterList.h"
+
+static const CMPIBroker *_BROKER;
+
+static CMPIStatus host_to_list(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+
+        /* validate host reference */
+        s = get_host(_BROKER, info->context, reference, &instance, false);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        s = cu_validate_ref(_BROKER, reference, instance);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        s = enum_filter_lists(_BROKER, info->context, reference, list);
+
+ out:
+        return s;
+}
+
+static CMPIStatus list_to_host(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIInstance *instance = NULL;
+
+        /* validate filter reference */
+        s = get_filter_by_ref(_BROKER, info->context, reference, &instance);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        s = get_host(_BROKER, info->context, reference, &instance, false);
+        if (s.rc != CMPI_RC_OK)
+                goto out;
+
+        if (instance != NULL)
+                inst_list_add(list, instance);
+
+ out:
+        return s;
+}
+
+LIBVIRT_CIM_DEFAULT_MAKEREF()
+
+static char *antecedent[] = {
+        "KVM_HostSystem",
+        NULL
+};
+
+static char *dependent[] = {
+        "KVM_FilterList",
+        NULL
+};
+
+static char *assoc_class_name[] = {
+        "KVM_HostedFilterList",
+        NULL
+};
+
+static struct std_assoc _host_to_list = {
+        .source_class = (char **)&antecedent,
+        .source_prop = "Antecedent",
+
+        .target_class = (char **)&dependent,
+        .target_prop = "Dependent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = host_to_list,
+        .make_ref = make_ref
+};
+
+static struct std_assoc _list_to_host = {
+        .source_class = (char **)&dependent,
+        .source_prop = "Dependent",
+
+        .target_class = (char **)&antecedent,
+        .target_prop = "Antecedent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = list_to_host,
+        .make_ref = make_ref
+};
+
+static struct std_assoc *handlers[] = {
+        &_host_to_list,
+        &_list_to_host,
+        NULL
+};
+
+STDA_AssocMIStub(,
+        Virt_HostedFilterList,
+        _BROKER,
+        libvirt_cim_init(),
+        handlers);
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c
new file mode 100644
--- /dev/null
+++ b/src/Virt_NestedFilterList.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ *  Chip Vincent <cvincent at us.ibm.com>
+ *
+ * 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
+ */
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_association.h>
+#include <libcmpiutil/std_instance.h>
+
+/* FIXME: This seems to be needed to compile STREQC, which suggests
+ * libcmpiutil.h needs to add the include since the marco is defined there.
+ */
+#include <string.h>
+#include <strings.h>
+
+#include "acl_parsing.h"
+#include "misc_util.h"
+#include "Virt_FilterList.h"
+
+static const CMPIBroker *_BROKER;
+
+/* TODO: Port to libcmpiutil/args_util.c */
+/**
+ * Get a reference property of an instance
+ *
+ * @param inst The instance
+ * @param prop The property name
+ * @param reference A pointer to a CMPIObjectPath* that will be set
+ *                  if successful
+ * @returns
+ *      - CMPI_RC_OK on success
+ *      - CMPI_RC_ERR_NO_SUCH_PROPERTY if prop is not present
+ *      - CMPI_RC_ERR_TYPE_MISMATCH if prop is not a reference
+ *      - CMPI_RC_OK otherwise
+ */
+static CMPIrc cu_get_ref_prop(const CMPIInstance *instance,
+                              const char *prop,
+                              CMPIObjectPath **reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIData value;
+
+        /* REQUIRE_PROPERY_DEFINED(instance, prop, value, &s); */
+        value = CMGetProperty(instance, prop, &s);
+        if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value))
+                return CMPI_RC_ERR_NO_SUCH_PROPERTY;
+
+        if ((value.type != CMPI_ref) ||  CMIsNullObject(value.value.ref))
+                return CMPI_RC_ERR_TYPE_MISMATCH;
+
+        *reference = value.value.ref;
+
+        return CMPI_RC_OK;
+}
+
+/* TODO: Port to libcmpiutil/args_util.c */
+/**
+ * Get a reference component of an object path
+ *
+ * @param _reference The reference
+ * @param key The key name
+ * @param reference A pointer to a CMPIObjectPath* that will be set
+ *                  if successful
+ * @returns
+ *      - CMPI_RC_OK on success
+ *      - CMPI_RC_ERR_NO_SUCH_PROPERTY if prop is not present
+ *      - CMPI_RC_ERR_TYPE_MISMATCH if prop is not a reference
+ *      - CMPI_RC_OK otherwise
+ */
+static CMPIrc cu_get_ref_path(const CMPIObjectPath *reference,
+                              const char *key,
+                              CMPIObjectPath **_reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIData value;
+
+        /* REQUIRE_PROPERY_DEFINED(instance, prop, value, &s); */
+        value = CMGetKey(reference, key, &s);
+        if ((s.rc != CMPI_RC_OK) || CMIsNullValue(value))
+                return CMPI_RC_ERR_NO_SUCH_PROPERTY;
+
+        /* how to parse and object path? */
+
+        return CMPI_RC_OK;
+}
+
+
+/**
+ *  given a filter, find all *direct* filter_refs
+ */
+static CMPIStatus parent_to_child(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct acl_filter *parent_filter = NULL;
+        struct acl_filter *child_filter = NULL;
+        CMPIInstance *instance = NULL;
+        const char * name = NULL;
+        virConnectPtr conn = NULL;
+        int i;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        get_filter_by_name(conn, name, &parent_filter);
+        if (parent_filter == NULL)
+                goto out;
+
+        for (i = 0; i < parent_filter->ref_ct; i++) {
+                get_filter_by_name(conn, parent_filter->refs[i],
+                                        &child_filter);
+                if (child_filter == NULL)
+                        continue;
+
+                CU_DEBUG("Processing %s,", child_filter->name);
+
+                s = instance_from_filter(_BROKER,
+                                        info->context,
+                                        reference,
+                                        child_filter,
+                                        &instance);
+
+                if (instance != NULL) {
+                        CU_DEBUG("Adding instance to inst_list");
+                        inst_list_add(list, instance);
+                }
+
+                cleanup_filter(child_filter);
+
+                child_filter = NULL;
+                instance = NULL;
+        }
+
+        cleanup_filter(parent_filter);
+
+ out:
+        virConnectClose(conn);
+
+        return s;
+}
+
+/**
+ *  given a filter, find all the other filters that reference it
+ */
+static CMPIStatus child_to_parent(
+        const CMPIObjectPath *reference,
+        struct std_assoc_info *info,
+        struct inst_list *list)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        struct acl_filter *_list = NULL;
+        CMPIInstance *instance = NULL;
+        const char *name = NULL;
+        virConnectPtr conn = NULL;
+        int count, i, j;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        if (cu_get_str_path(reference, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_NOT_FOUND,
+                        "Unable to get Name from reference");
+                goto out;
+        }
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        /* TODO: Ensure the referenced filter exists */
+
+        count = get_filters(conn, &_list);
+        if (_list == NULL)
+                goto out;
+
+        /* return any filter that has name in refs */
+        for (i = 0; i < count; i++) {
+                for (j = 0; j < _list[i].ref_ct; j++) {
+                        if (STREQC(name, _list[i].refs[j])) {
+                                CU_DEBUG("Processing %s,", _list[i].name);
+
+                                s = instance_from_filter(_BROKER,
+                                                        info->context,
+                                                        reference,
+                                                        &_list[i],
+                                                        &instance);
+
+                                if (instance != NULL)
+                                        inst_list_add(list, instance);
+
+                                instance = NULL;
+                        }
+
+                }
+
+                cleanup_filter(&_list[i]);
+        }
+
+        free(_list);
+
+ out:
+        virConnectClose(conn);
+
+        return s;
+}
+
+LIBVIRT_CIM_DEFAULT_MAKEREF()
+
+static char *antecedent[] = {
+        "KVM_FilterList",
+        NULL
+};
+
+static char *dependent[] = {
+        "KVM_FilterList",
+        NULL
+};
+
+static char *assoc_class_name[] = {
+        "KVM_NestedFilterList",
+        NULL
+};
+
+static struct std_assoc _list_to_filter_ref = {
+        .source_class = (char **)&antecedent,
+        .source_prop = "Antecedent",
+
+        .target_class = (char **)&dependent,
+        .target_prop = "Dependent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = parent_to_child,
+        .make_ref = make_ref
+};
+
+static struct std_assoc _filter_ref_to_list = {
+        .source_class = (char **)&dependent,
+        .source_prop = "Dependent",
+
+        .target_class = (char **)&antecedent,
+        .target_prop = "Antecedent",
+
+        .assoc_class = (char **)&assoc_class_name,
+
+        .handler = child_to_parent,
+        .make_ref = make_ref
+};
+
+static struct std_assoc *handlers[] = {
+        &_list_to_filter_ref,
+        &_filter_ref_to_list,
+        NULL
+};
+
+STDA_AssocMIStub(,
+        Virt_NestedFilterList,
+        _BROKER,
+        libvirt_cim_init(),
+        handlers);
+
+DEFAULT_GI();
+DEFAULT_EIN();
+DEFAULT_EI();
+
+static CMPIStatus CreateInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference,
+        const CMPIInstance *instance)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *antecedent = NULL;
+        const char *parent_name = NULL;
+        struct acl_filter *parent_filter = NULL;
+        CMPIObjectPath *dependent = NULL;
+        const char *child_name = NULL;
+        struct acl_filter *child_filter = NULL;
+        virConnectPtr conn = NULL;
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        if (cu_get_ref_prop(instance, "Antecedent",
+                &antecedent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &parent_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, parent_name, &parent_filter);
+        if (parent_filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Antecedent.Name object does not exist");
+                goto out;
+        }
+
+        if (cu_get_ref_prop(instance, "Dependent",
+                &dependent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &child_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, child_name, &child_filter);
+        if (child_filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Dependent.Name object does not exist");
+                goto out;
+        }
+
+        char *dup = strdup(child_name);
+
+        if (append_filter_ref(parent_filter, dup) == 0) {
+                free(dup);
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to append filter reference");
+                goto out;
+        }
+
+        if (update_filter(conn, parent_filter) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to update filter");
+                goto out;
+        }
+
+ out:
+        free((char *)parent_name);
+        free((char *)child_name);
+
+        cleanup_filter(parent_filter);
+        cleanup_filter(child_filter);
+
+        virConnectClose(conn);
+
+        return s;
+}
+
+static CMPIStatus DeleteInstance(
+        CMPIInstanceMI *self,
+        const CMPIContext *context,
+        const CMPIResult *results,
+        const CMPIObjectPath *reference)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *antecedent = NULL;
+        const char *parent_name = NULL;
+        struct acl_filter *parent_filter = NULL;
+        CMPIObjectPath *dependent = NULL;
+        const char *child_name = NULL;
+        struct acl_filter *child_filter = NULL;
+        virConnectPtr conn = NULL;
+
+        conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s);
+        if (conn == NULL)
+                goto out;
+
+        if (cu_get_ref_path(reference, "Antecedent",
+                &antecedent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &parent_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Antecedent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, parent_name, &parent_filter);
+        if (parent_filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Antecedent.Name object does not exist");
+                goto out;
+        }
+
+        if (cu_get_ref_path(reference, "Dependent",
+                &dependent) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent property");
+                goto out;
+        }
+
+        if (cu_get_str_path(reference, "Name", &child_name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Unable to get Dependent.Name property");
+                goto out;
+        }
+
+        get_filter_by_name(conn, child_name, &child_filter);
+        if (child_filter == NULL) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Dependent.Name object does not exist");
+                goto out;
+        }
+
+        if (remove_filter_ref(parent_filter, child_name) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to remove filter reference");
+                goto out;
+        }
+
+        if (update_filter(conn, parent_filter) == 0) {
+                cu_statusf(_BROKER, &s,
+                        CMPI_RC_ERR_FAILED,
+                        "Failed to update filter");
+                goto out;
+        }
+
+ out:
+        free((char *)parent_name);
+        free((char *)child_name);
+
+        cleanup_filter(parent_filter);
+        cleanup_filter(child_filter);
+
+        virConnectClose(conn);
+
+        return s;
+}
+
+
+DEFAULT_MI();
+
+DEFAULT_EQ();
+DEFAULT_INST_CLEANUP();
+
+STD_InstanceMIStub(,
+        Virt_AppliedFilterEntry,
+        _BROKER,
+        libvirt_cim_init());
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
+




More information about the Libvirt-cim mailing list