[Libvirt-cim] [PATCH] Add write support for FilterList and NestedFilterList

Chip Vincent cvincent at linux.vnet.ibm.com
Mon Jun 27 22:35:15 UTC 2011


# HG changeset patch
# User Chip Vincent <cvincent at us.ibm.com>
# Date 1309213800 14400
# Node ID 03e3f95547078be19d8d22cac83ce38daf7510b9
# Parent  75411f53df02159c3fa6ce5810c9446579e3d66d
Add write support for FilterList and NestedFilterList

This allows clients to create new filter lists and then associate them
with other filter lists to create complex filters. This patch also has some
minor bug fixes to AppliedFilterList so the new filters can be applied
to existing NetworkPort instances. The new cimtests for the create/delete
associations are still under construction, but you can easily test
FilterList create/delete (foundation) with the following commands:

# wbemcli ci 'http://localhost:5988/root/virt:KVM_FilterList.CreationClassName="",Name="",SystemCreationClassName="",SystemName=""' 'Name="test"'

# wbemcli di 'http://localhost:5988/root/virt:KVM_FilterList.CreationClassName="KVM_FilterList",Name="test",SystemCreationClassName="KVM_HostSystem",SystemName="oc0840652111.ibm.com"'

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

diff --git a/libxkutil/acl_parsing.c b/libxkutil/acl_parsing.c
--- a/libxkutil/acl_parsing.c
+++ b/libxkutil/acl_parsing.c
@@ -551,6 +551,57 @@
 #endif
 }
 
+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;
+}
 
 int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule)
 {
@@ -605,6 +656,28 @@
         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;
+}
+
 char *make_rule_id(const char *filter, int index)
 {
         int ret;
diff --git a/libxkutil/acl_parsing.h b/libxkutil/acl_parsing.h
--- a/libxkutil/acl_parsing.h
+++ b/libxkutil/acl_parsing.h
@@ -194,11 +194,17 @@
 char *make_rule_id(const char *filter, int index);
 int parse_rule_id(const char *rule_id, char **filter, int *index);
 
+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);
+
 /** NOTE: Both append functions take parameters allocated by caller and
  *  freed by cleanup_filter(s)
  */
 int append_filter_rule(struct acl_filter *filter, struct acl_rule *rule);
 int append_filter_ref(struct acl_filter *filter, char *name);
+int remove_filter_ref(struct acl_filter *filter, const char *name);
+
 #endif
 
 /*
diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c
--- a/libxkutil/xmlgen.c
+++ b/libxkutil/xmlgen.c
@@ -1360,6 +1360,59 @@
         return xml;
 }
 
+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;
+        }
+
+        /* TODO: Not yet supported
+        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/schema/NestedFilterList.registration b/schema/NestedFilterList.registration
--- a/schema/NestedFilterList.registration
+++ b/schema/NestedFilterList.registration
@@ -1,3 +1,3 @@
 # Copyright IBM Corp. 2011
 # Classname Namespace ProviderName ProviderModule ProviderTypes
-KVM_NestedFilterList root/virt Virt_NestedFilterList Virt_NestedFilterList association
+KVM_NestedFilterList root/virt Virt_NestedFilterList Virt_NestedFilterList instance association
diff --git a/src/Virt_AppliedFilterList.c b/src/Virt_AppliedFilterList.c
--- a/src/Virt_AppliedFilterList.c
+++ b/src/Virt_AppliedFilterList.c
@@ -411,10 +411,6 @@
         libvirt_cim_init(),
         handlers);
 
-DEFAULT_GI();
-DEFAULT_EIN();
-DEFAULT_EI();
-
 static CMPIStatus CreateInstance(
         CMPIInstanceMI *self,
         const CMPIContext *context,
@@ -434,6 +430,8 @@
         virConnectPtr conn = NULL;
         virDomainPtr dom = NULL;
 
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
         if (cu_get_ref_prop(instance, "Antecedent",
                 &antecedent) != CMPI_RC_OK) {
                 cu_statusf(_BROKER, &s,
@@ -473,6 +471,8 @@
                 goto out;
         }
 
+        CU_DEBUG("DeviceID = %s", device_name);
+
         if (parse_fq_devid(device_name, &domain_name, &net_name) == 0) {
                 CU_DEBUG("Failed to parse devid");
                 goto out;
@@ -492,7 +492,11 @@
                 goto out;
         }
 
-        free(device->dev.net.filter_ref);
+        if (device->dev.net.filter_ref != NULL) {
+                free(device->dev.net.filter_ref);
+                device->dev.net.filter_ref = NULL;
+        }
+
         device->dev.net.filter_ref = strdup(filter_name);
 
         if (update_device(dom, device) == 0) {
@@ -502,10 +506,10 @@
                 goto out;
         }
 
+        CU_DEBUG("CreateInstance complete");
+
  out:
-        free((char *)filter_name);
         free(domain_name);
-        free((char *)device_name);
         free(net_name);
 
         cleanup_filter(filter);
@@ -535,6 +539,8 @@
         virConnectPtr conn = NULL;
         virDomainPtr dom = NULL;
 
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
         if (cu_get_ref_path(reference, "Antecedent",
                 &antecedent) != CMPI_RC_OK) {
                 cu_statusf(_BROKER, &s,
@@ -574,6 +580,8 @@
                 goto out;
         }
 
+        CU_DEBUG("DeviceID = %s", device_name);
+
         if (parse_fq_devid(device_name, &domain_name, &net_name) == 0) {
                 CU_DEBUG("Failed to parse devid");
                 goto out;
@@ -593,8 +601,10 @@
                 goto out;
         }
 
-        free(device->dev.net.filter_ref);
-        device->dev.net.filter_ref = NULL;
+        if (device->dev.net.filter_ref != NULL) {
+                free(device->dev.net.filter_ref);
+                device->dev.net.filter_ref = NULL;
+        }
 
         if (update_device(dom, device) == 0) {
                 cu_statusf(_BROKER, &s,
@@ -603,10 +613,10 @@
                 goto out;
         }
 
+        CU_DEBUG("CreateInstance complete");
+
  out:
-        free((char *)filter_name);
         free(domain_name);
-        free((char *)device_name);
         free(net_name);
 
         cleanup_filter(filter);
@@ -618,12 +628,15 @@
         return s;
 }
 
+DEFAULT_GI();
+DEFAULT_EIN();
+DEFAULT_EI();
 DEFAULT_MI();
 DEFAULT_EQ();
 DEFAULT_INST_CLEANUP();
 
 STD_InstanceMIStub(,
-        Virt_AppliedFilterEntry,
+        Virt_AppliedFilterList,
         _BROKER,
         libvirt_cim_init());
 
diff --git a/src/Virt_FilterList.c b/src/Virt_FilterList.c
--- a/src/Virt_FilterList.c
+++ b/src/Virt_FilterList.c
@@ -81,6 +81,32 @@
         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 = strdup(name);
+
+ out:
+        return filter;
+}
+
 CMPIStatus enum_filter_lists(const CMPIBroker *broker,
                         const CMPIContext *context,
                         const CMPIObjectPath *reference,
@@ -230,9 +256,114 @@
         return s;
 }
 
-DEFAULT_CI();
+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;
+        }
+
+        _instance = convert_filter_to_instance(filter,
+                                        _BROKER,
+                                        context,
+                                        reference,
+                                        &s);
+
+        if(_instance != NULL)
+                cu_return_instance_name(results, _instance);
+
+        CU_DEBUG("CreateInstance complete");
+
+ 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_MI();
-DEFAULT_DI();
 DEFAULT_EQ();
 DEFAULT_INST_CLEANUP();
 
diff --git a/src/Virt_NestedFilterList.c b/src/Virt_NestedFilterList.c
--- a/src/Virt_NestedFilterList.c
+++ b/src/Virt_NestedFilterList.c
@@ -38,6 +38,71 @@
 
 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
  */
@@ -224,6 +289,203 @@
         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;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        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;
+        }
+
+        if (append_filter_ref(parent_filter, strdup(child_name)) == 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;
+        }
+
+        CU_DEBUG("CreateInstance completed");
+
+ out:
+        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;
+
+        CU_DEBUG("Reference = %s", REF2STR(reference));
+
+        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;
+        }
+
+        CU_DEBUG("CreateInstance completed");
+
+ out:
+        cleanup_filter(parent_filter);
+        cleanup_filter(child_filter);
+        virConnectClose(conn);
+
+        return s;
+}
+
+DEFAULT_MI();
+DEFAULT_EQ();
+DEFAULT_INST_CLEANUP();
+
+STD_InstanceMIStub(,
+        Virt_NestedFilterList,
+        _BROKER,
+        libvirt_cim_init());
+
 /*
  * Local Variables:
  * mode: C




More information about the Libvirt-cim mailing list