diff options
Diffstat (limited to 'utils/open-isns/objects.c')
-rw-r--r-- | utils/open-isns/objects.c | 1320 |
1 files changed, 1320 insertions, 0 deletions
diff --git a/utils/open-isns/objects.c b/utils/open-isns/objects.c new file mode 100644 index 0000000..1504026 --- /dev/null +++ b/utils/open-isns/objects.c @@ -0,0 +1,1320 @@ +/* + * iSNS object model + * + * Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com> + */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "isns.h" +#include "objects.h" +#include "source.h" +#include "vendor.h" +#include "attrs.h" +#include "util.h" + +/* For relationship stuff - should go */ +#include "db.h" + +static isns_object_template_t * isns_object_templates[] = { + &isns_entity_template, + &isns_portal_template, + &isns_iscsi_node_template, + &isns_fc_port_template, + &isns_fc_node_template, + &isns_iscsi_pg_template, + &isns_dd_template, + &isns_ddset_template, + + /* vendor-specific templates */ + &isns_policy_template, + + NULL +}; + +/* + * Quick lookup of (key) tag to template + */ +#define MAX_QUICK_TAG 2100 +static isns_object_template_t * isns_object_template_key_map[MAX_QUICK_TAG]; +static isns_object_template_t * isns_object_template_any_map[MAX_QUICK_TAG]; +static isns_object_template_t * isns_object_template_idx_map[MAX_QUICK_TAG]; +static int isns_object_maps_inizialized = 0; + + +static void +__isns_object_maps_init(void) +{ + isns_object_template_t *tmpl; + uint32_t i, j, tag; + + isns_object_maps_inizialized = 1; + + for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { + if (tmpl->iot_vendor_specific) + continue; + + tag = tmpl->iot_keys[0]; + isns_assert(tag < MAX_QUICK_TAG); + isns_object_template_key_map[tag] = tmpl; + + for (j = 0; j < tmpl->iot_num_attrs; ++j) { + tag = tmpl->iot_attrs[j]; + isns_assert(tag < MAX_QUICK_TAG); + isns_object_template_any_map[tag] = tmpl; + } + + if ((tag = tmpl->iot_index) != 0) + isns_object_template_idx_map[tag] = tmpl; + } +} + +static void +isns_object_maps_init(void) +{ + if (!isns_object_maps_inizialized) + __isns_object_maps_init(); +} + +/* + * Based on a given key attribute, find the corresponding + * object type. + */ +isns_object_template_t * +isns_object_template_find(uint32_t key_tag) +{ + isns_object_template_t *tmpl; + unsigned int i; + + isns_object_maps_init(); + if (key_tag < MAX_QUICK_TAG) + return isns_object_template_key_map[key_tag]; + + for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { + if (tmpl->iot_keys[0] == key_tag) + return tmpl; + } + + return NULL; +} + +/* + * Given a set of attributes, find the corresponding + * object type. + * Any attributes in the list in *addition to* the keys + * attributes are ignored. + */ +isns_object_template_t * +isns_object_template_for_key_attrs(const isns_attr_list_t *attrs) +{ + isns_object_template_t *tmpl; + const isns_attr_t *attr; + unsigned int i; + + if (attrs->ial_count == 0) + return NULL; + attr = attrs->ial_data[0]; + + tmpl = isns_object_template_find(attr->ia_tag_id); + if (tmpl == NULL) + return NULL; + + /* + * 5.6.4. + * + * Some objects are keyed by more than one object key attribute + * value. For example, the Portal object is keyed by attribute + * tags 16 and 17. When describing an object keyed by more than one + * key attribute, every object key attribute of that object MUST be + * listed sequentially by tag value in the message before non-key + * attributes of that object and key attributes of the next object. + * A group of key attributes of this kind is treated as a single + * logical key attribute when identifying an object. + */ + for (i = 1; i < tmpl->iot_num_keys; ++i) { + attr = attrs->ial_data[i]; + + if (attr->ia_tag_id != tmpl->iot_keys[i]) + return NULL; + } + + return tmpl; +} + +isns_object_template_t * +isns_object_template_for_tag(uint32_t tag) +{ + isns_object_template_t *tmpl; + unsigned int i, j; + + isns_object_maps_init(); + if (tag < MAX_QUICK_TAG) + return isns_object_template_any_map[tag]; + + for (i = 0; (tmpl = isns_object_templates[i]) != NULL; ++i) { + for (j = 0; j < tmpl->iot_num_attrs; ++j) { + if (tmpl->iot_attrs[j] == tag) + return tmpl; + } + } + + return NULL; +} + +isns_object_template_t * +isns_object_template_for_index_tag(uint32_t tag) +{ + isns_object_maps_init(); + if (tag >= MAX_QUICK_TAG) + return NULL; + + return isns_object_template_idx_map[tag]; +} + +isns_object_template_t * +isns_object_template_by_name(const char *name) +{ + isns_object_template_t **pp, *tmpl; + + pp = isns_object_templates; + while ((tmpl = *pp++) != NULL) { + if (!strcasecmp(tmpl->iot_name, name)) + return tmpl; + } + return NULL; +} + +const char * +isns_object_template_name(isns_object_template_t *tmpl) +{ + if (!tmpl) + return NULL; + return tmpl->iot_name; +} + +/* + * Notify any listeners that the object has changed, + * and mark it dirty. + * dd_or_dds is used for DD_MEMBER_ADDED and + * DD_MEMBER_REMOVED events, and refers to the + * domain or domain set the object was added to or + * removed from. + */ +void +isns_mark_object(isns_object_t *obj, unsigned int how) +{ + obj->ie_flags |= ISNS_OBJECT_DIRTY; + obj->ie_mtime = time(NULL); + obj->ie_scn_bits |= (1 << how); + isns_object_event(obj, 0, NULL); +} + +static void +__isns_mark_object(isns_object_t *obj) +{ + obj->ie_flags |= ISNS_OBJECT_DIRTY; + obj->ie_mtime = time(NULL); +} + +/* + * Create an object given its object template + */ +isns_object_t * +isns_create_object(isns_object_template_t *tmpl, + const isns_attr_list_t *attrs, + isns_object_t *parent) +{ + isns_object_t *obj; + unsigned int i; + + /* Enforce containment rules. */ + if (parent) + isns_assert(tmpl->iot_container == parent->ie_template); + +#ifdef notdef + /* This check is somewhat costly: */ + if (attrs && tmpl != isns_object_template_for_key_attrs(attrs)) + return NULL; +#endif + + obj = isns_calloc(1, sizeof(*obj)); + + obj->ie_users = 1; + obj->ie_template = tmpl; + isns_attr_list_init(&obj->ie_attrs); + + if (parent) + isns_object_attach(obj, parent); + + if (attrs == NULL) { + /* Make sure that all key attrs are instantiated + * and in sequence. */ + for (i = 0; i < tmpl->iot_num_keys; ++i) + isns_attr_list_append_nil(&obj->ie_attrs, + tmpl->iot_keys[i]); + } else { + /* We rely on the caller to ensure that + * attributes are in proper sequence. */ + isns_attr_list_copy(&obj->ie_attrs, attrs); + } + + /* Just mark it dirty, but do not schedule a + * SCN event. */ + __isns_mark_object(obj); + + return obj; +} + +/* + * Obtain an additional reference on the object + */ +isns_object_t * +isns_object_get(isns_object_t *obj) +{ + if (obj) { + isns_assert(obj->ie_users); + obj->ie_users++; + } + return obj; +} + +/* + * Release a reference on the object + */ +void +isns_object_release(isns_object_t *obj) +{ + unsigned int i; + isns_object_t *child; + + if (!obj) + return; + + isns_assert(obj->ie_users); + if (--(obj)->ie_users != 0) + return; + + /* Must not have any live references to it */ + isns_assert(obj->ie_references == 0); + + /* Must be detached from parent */ + isns_assert(obj->ie_container == NULL); + + /* Release all children. We explicitly clear + * ie_container because the destructor + * checks for this (in order to catch + * refcounting bugs) */ + for (i = 0; i < obj->ie_children.iol_count; ++i) { + child = obj->ie_children.iol_data[i]; + child->ie_container = NULL; + } + isns_object_list_destroy(&obj->ie_children); + + isns_attr_list_destroy(&obj->ie_attrs); + + isns_bitvector_free(obj->ie_membership); + isns_free(obj); +} + +/* + * Get the topmost container (ie Network Entity) + * for the given object + */ +isns_object_t * +isns_object_get_entity(isns_object_t *obj) +{ + if (obj == NULL) + return NULL; + while (obj->ie_container) + obj = obj->ie_container; + if (!ISNS_IS_ENTITY(obj)) + return NULL; + return obj; +} + +int +isns_object_contains(const isns_object_t *ancestor, + const isns_object_t *descendant) +{ + while (descendant) { + if (descendant == ancestor) + return 1; + descendant = descendant->ie_container; + } + return 0; +} + +/* + * Get all children of the specified type + */ +void +isns_object_get_descendants(const isns_object_t *obj, + isns_object_template_t *tmpl, + isns_object_list_t *result) +{ + isns_object_t *child; + unsigned int i; + + for (i = 0; i < obj->ie_children.iol_count; ++i) { + child = obj->ie_children.iol_data[i]; + if (!tmpl || child->ie_template == tmpl) + isns_object_list_append(result, child); + } +} + +/* + * Attach an object to a new container + */ +int +isns_object_attach(isns_object_t *obj, isns_object_t *parent) +{ + isns_assert(obj->ie_container == NULL); + + if (parent) { + /* Copy the owner (ie source) from the parent + * object. + * Make sure the parent object type is a valid + * container for this object. + */ + if (parent->ie_template != obj->ie_template->iot_container) { + isns_error("You are not allowed to add a %s object " + "to a %s!\n", + obj->ie_template->iot_name, + parent->ie_template->iot_name); + return 0; + } + obj->ie_flags = parent->ie_flags & ISNS_OBJECT_PRIVATE; + isns_object_list_append(&parent->ie_children, obj); + } + obj->ie_container = parent; + return 1; +} + +int +isns_object_is_valid_container(const isns_object_t *container, + isns_object_template_t *child_type) +{ + return child_type->iot_container == container->ie_template; +} + +/* + * Detach an object from its container + */ +int +isns_object_detach(isns_object_t *obj) +{ + isns_object_t *parent; + + /* Detach from parent */ + if ((parent = obj->ie_container) != NULL) { + int removed; + + obj->ie_container = NULL; + removed = isns_object_list_remove( + &parent->ie_children, obj); + + isns_assert(removed != 0); + } + + return 0; +} + +/* + * Check the type of an object + */ +int +isns_object_is(const isns_object_t *obj, + isns_object_template_t *tmpl) +{ + return obj->ie_template == tmpl; +} + +int +isns_object_is_iscsi_node(const isns_object_t *obj) +{ + return ISNS_IS_ISCSI_NODE(obj); +} + +int +isns_object_is_fc_port(const isns_object_t *obj) +{ + return ISNS_IS_FC_PORT(obj); +} + +int +isns_object_is_fc_node(const isns_object_t *obj) +{ + return ISNS_IS_FC_NODE(obj); +} + +int +isns_object_is_portal(const isns_object_t *obj) +{ + return ISNS_IS_PORTAL(obj); +} + +int +isns_object_is_pg(const isns_object_t *obj) +{ + return ISNS_IS_PG(obj); +} + +int +isns_object_is_policy(const isns_object_t *obj) +{ + return ISNS_IS_POLICY(obj); +} + +/* + * Match an object against a list of attributes. + */ +int +isns_object_match(const isns_object_t *obj, + const isns_attr_list_t *attrs) +{ + isns_object_template_t *tmpl = obj->ie_template; + isns_attr_t *self, *match; + unsigned int i, j, from = 0; + uint32_t tag; + + /* Fast path: try to compare in-order */ + while (from < attrs->ial_count) { + match = attrs->ial_data[from]; + self = obj->ie_attrs.ial_data[from]; + + if (match->ia_tag_id != self->ia_tag_id) + goto slow_path; + + if (!isns_attr_match(self, match)) + return 0; + + from++; + } + + return 1; + +slow_path: + for (i = from; i < attrs->ial_count; ++i) { + isns_attr_t *found = NULL; + + match = attrs->ial_data[i]; + + /* + * 5.6.5.2 + * A Message Key with zero-length TLV(s) is scoped to + * every object of the type indicated by the zero-length + * TLV(s) + */ + if (match->ia_value.iv_type == &isns_attr_type_nil) { + tag = match->ia_tag_id; + if (isns_object_attr_valid(tmpl, tag)) + continue; + return 0; + } + + for (j = from; j < obj->ie_attrs.ial_count; ++j) { + self = obj->ie_attrs.ial_data[j]; + + if (match->ia_tag_id == self->ia_tag_id) { + found = self; + break; + } + } + + if (found == NULL) + return 0; + + if (!isns_attr_match(self, match)) + return 0; + } + return 1; +} + +/* + * Find descendant object matching the given key + */ +isns_object_t * +isns_object_find_descendant(isns_object_t *obj, const isns_attr_list_t *keys) +{ + isns_object_list_t list = ISNS_OBJECT_LIST_INIT; + isns_object_t *found; + + if (!isns_object_find_descendants(obj, NULL, keys, &list)) + return NULL; + + found = isns_object_get(list.iol_data[0]); + isns_object_list_destroy(&list); + + return found; +} + +int +isns_object_find_descendants(isns_object_t *obj, + isns_object_template_t *tmpl, + const isns_attr_list_t *keys, + isns_object_list_t *result) +{ + isns_object_t *child; + unsigned int i; + + if ((tmpl == NULL || tmpl == obj->ie_template) + && (keys == NULL || isns_object_match(obj, keys))) + isns_object_list_append(result, obj); + + for (i = 0; i < obj->ie_children.iol_count; ++i) { + child = obj->ie_children.iol_data[i]; + isns_object_find_descendants(child, tmpl, keys, result); + } + + return result->iol_count; +} + +/* + * Return the object's modification time stamp + */ +time_t +isns_object_last_modified(const isns_object_t *obj) +{ + return obj->ie_mtime; +} + +/* + * Set the SCN bitmap + */ +void +isns_object_set_scn_mask(isns_object_t *obj, uint32_t bitmap) +{ + obj->ie_scn_mask = bitmap; + __isns_mark_object(obj); +} + +/* + * Debugging utility: print the object + */ +void +isns_object_print(isns_object_t *obj, isns_print_fn_t *fn) +{ + isns_attr_list_print(&obj->ie_attrs, fn); +} + +/* + * Return a string representing the object state + */ +const char * +isns_object_state_string(unsigned int state) +{ + switch (state) { + case ISNS_OBJECT_STATE_LARVAL: + return "larval"; + case ISNS_OBJECT_STATE_MATURE: + return "mature"; + case ISNS_OBJECT_STATE_LIMBO: + return "limbo"; + case ISNS_OBJECT_STATE_DEAD: + return "dead"; + } + return "UNKNOWN"; +} + +/* + * This is needed when deregistering an object. + * Remove all attributes except the key and index attrs. + */ +void +isns_object_prune_attrs(isns_object_t *obj) +{ + isns_object_template_t *tmpl = obj->ie_template; + uint32_t tags[16]; + unsigned int i; + + isns_assert(tmpl->iot_num_keys + 1 <= 16); + for (i = 0; i < tmpl->iot_num_keys; ++i) + tags[i] = tmpl->iot_keys[i]; + if (tmpl->iot_index) + tags[i++] = tmpl->iot_index; + isns_attr_list_prune(&obj->ie_attrs, tags, i); +} + +/* + * Convenience functions + */ + +/* + * Create a portal object. + * For now, always assume TCP. + */ +isns_object_t * +isns_create_portal(const isns_portal_info_t *info, + isns_object_t *parent) +{ + isns_object_t *obj; + + obj = isns_create_object(&isns_portal_template, NULL, parent); + isns_portal_to_object(info, + ISNS_TAG_PORTAL_IP_ADDRESS, + ISNS_TAG_PORTAL_TCP_UDP_PORT, + obj); + return obj; +} + +/* + * Extract all key attrs and place them + * in the attribute list. + */ +int +isns_object_extract_keys(const isns_object_t *obj, + isns_attr_list_t *list) +{ + isns_object_template_t *tmpl = obj->ie_template; + const isns_attr_list_t *src = &obj->ie_attrs; + unsigned int i; + + for (i = 0; i < tmpl->iot_num_keys; ++i) { + isns_attr_t *attr; + + if (!isns_attr_list_get_attr(src, tmpl->iot_keys[i], &attr)) + return 0; + isns_attr_list_append_attr(list, attr); + } + + return 1; +} + +/* + * Extract all attributes we are permitted to overwrite and place them + * in the attribute list. + */ +int +isns_object_extract_writable(const isns_object_t *obj, + isns_attr_list_t *list) +{ + const isns_attr_list_t *src = &obj->ie_attrs; + unsigned int i; + + for (i = 0; i < src->ial_count; ++i) { + isns_attr_t *attr = src->ial_data[i]; + + if (attr->ia_tag->it_readonly) + continue; + isns_attr_list_append_attr(list, attr); + } + + return 1; +} + +/* + * Extract all attrs and place them + * in the attribute list. We copy the attributes + * as they appear inside the object; which allows + * duplicate attributes (eg inside a discovery domain). + */ +int +isns_object_extract_all(const isns_object_t *obj, isns_attr_list_t *list) +{ + isns_attr_list_append_list(list, &obj->ie_attrs); + return 1; +} + +/* + * Check if the given object is valid + */ +int +isns_object_attr_valid(isns_object_template_t *tmpl, uint32_t tag) +{ + const uint32_t *attr_tags = tmpl->iot_attrs; + unsigned int i; + + for (i = 0; i < tmpl->iot_num_attrs; ++i) { + if (*attr_tags == tag) + return 1; + ++attr_tags; + } + return 0; +} + +/* + * Set an object attribute + */ +static int +__isns_object_set_attr(isns_object_t *obj, uint32_t tag, + const isns_attr_type_t *type, + const isns_value_t *value) +{ + const isns_tag_type_t *tag_type; + + if (!isns_object_attr_valid(obj->ie_template, tag)) + return 0; + + tag_type = isns_tag_type_by_id(tag); + if (type != &isns_attr_type_nil + && type != tag_type->it_type) { + isns_warning("application bug: cannot set attr %s(id=%u, " + "type=%s) to a value of type %s\n", + tag_type->it_name, tag, + tag_type->it_type->it_name, + type->it_name); + return 0; + } + + isns_attr_list_update_value(&obj->ie_attrs, + tag, tag_type, value); + + /* Timestamp updates should just be written out, but we + * do not want to trigger SCN messages and such. */ + if (tag != ISNS_TAG_TIMESTAMP) + isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); + else + __isns_mark_object(obj); + return 1; +} + +/* + * Copy an attribute to the object + */ +int +isns_object_set_attr(isns_object_t *obj, isns_attr_t *attr) +{ + isns_attr_list_t *list = &obj->ie_attrs; + uint32_t tag = attr->ia_tag_id; + + /* If this attribute exists within the object, + * and it cannot occur multiple times, replace it. */ + if (!attr->ia_tag->it_multiple + && isns_attr_list_replace_attr(list, attr)) + goto done; + + /* It doesn't exist; make sure it's a valid + * attribute. */ + if (!isns_object_attr_valid(obj->ie_template, tag)) + return 0; + + isns_attr_list_append_attr(list, attr); + +done: + isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); + return 1; +} + +int +isns_object_set_attrlist(isns_object_t *obj, const isns_attr_list_t *attrs) +{ + unsigned int i; + + for (i = 0; i < attrs->ial_count; ++i) { + isns_attr_t *attr = attrs->ial_data[i]; + if (!isns_object_set_attr(obj, attr)) + return 0; + } + isns_mark_object(obj, ISNS_SCN_OBJECT_UPDATED); + return 1; +} + +/* + * Untyped version of isns_object_set. + * Any type checking must be done by the caller; + * failure to do so will result in the end of the world. + */ +int +isns_object_set_value(isns_object_t *obj, uint32_t tag, const void *data) +{ + return isns_attr_list_update(&obj->ie_attrs, tag, data); +} + +/* + * Typed versions of isns_object_set + */ +int +isns_object_set_nil(isns_object_t *obj, uint32_t tag) +{ + return __isns_object_set_attr(obj, tag, + &isns_attr_type_nil, NULL); +} + +int +isns_object_set_string(isns_object_t *obj, uint32_t tag, + const char *value) +{ + isns_value_t var = ISNS_VALUE_INIT(string, (char *) value); + int rc; + + rc = __isns_object_set_attr(obj, tag, + &isns_attr_type_string, &var); + return rc; +} + +int +isns_object_set_uint32(isns_object_t *obj, uint32_t tag, + uint32_t value) +{ + isns_value_t var = ISNS_VALUE_INIT(uint32, value); + + return __isns_object_set_attr(obj, tag, + &isns_attr_type_uint32, &var); +} + +int +isns_object_set_uint64(isns_object_t *obj, + uint32_t tag, + uint64_t value) +{ + isns_value_t var = ISNS_VALUE_INIT(uint64, value); + + return __isns_object_set_attr(obj, tag, + &isns_attr_type_uint64, &var); +} + +int +isns_object_set_ipaddr(isns_object_t *obj, uint32_t tag, + const struct in6_addr *value) +{ + isns_value_t var = ISNS_VALUE_INIT(ipaddr, *value); + + return __isns_object_set_attr(obj, tag, + &isns_attr_type_ipaddr, &var); +} + +/* + * Query object attributes + */ +int +isns_object_get_attr(const isns_object_t *obj, uint32_t tag, + isns_attr_t **result) +{ + return isns_attr_list_get_attr(&obj->ie_attrs, tag, result); +} + +int +isns_object_get_attrlist(isns_object_t *obj, + isns_attr_list_t *result, + const isns_attr_list_t *req_attrs) +{ + isns_attr_list_t *attrs = &obj->ie_attrs; + isns_attr_t *attr; + unsigned int i; + + if (req_attrs == NULL) { + /* Retrieve all attributes */ + isns_attr_list_append_list(result, attrs); + } else { + for (i = 0; i < req_attrs->ial_count; ++i) { + uint32_t tag = req_attrs->ial_data[i]->ia_tag_id; + + if (tag == obj->ie_template->iot_next_index) { + /* FIXME: for now, we fake this value. + * We need the DB object at this point + * to find out what the next unused + * index is. + */ + isns_attr_list_append_uint32(result, + tag, 0); + } else + if (isns_attr_list_get_attr(attrs, tag, &attr)) + isns_attr_list_append_attr(result, attr); + } + } + return 1; +} + +int +isns_object_get_key_attrs(isns_object_t *obj, + isns_attr_list_t *result) +{ + isns_object_template_t *tmpl = obj->ie_template; + isns_attr_list_t *attrs = &obj->ie_attrs; + isns_attr_t *attr; + unsigned int i; + + for (i = 0; i < tmpl->iot_num_keys; ++i) { + uint32_t tag = tmpl->iot_keys[i]; + + if (!isns_attr_list_get_attr(attrs, tag, &attr)) { + isns_error("%s: %s object is missing key attr %u\n", + __FUNCTION__, + tmpl->iot_name, + tag); + return 0; + } + isns_attr_list_append_attr(result, attr); + } + return 1; +} + +int +isns_object_get_string(const isns_object_t *obj, uint32_t tag, + const char **result) +{ + isns_attr_t *attr; + + if (!isns_object_get_attr(obj, tag, &attr) + || !ISNS_ATTR_IS_STRING(attr)) + return 0; + + *result = attr->ia_value.iv_string; + return 1; +} + +int +isns_object_get_ipaddr(const isns_object_t *obj, uint32_t tag, + struct in6_addr *result) +{ + isns_attr_t *attr; + + if (!isns_object_get_attr(obj, tag, &attr) + || !ISNS_ATTR_IS_IPADDR(attr)) + return 0; + + *result = attr->ia_value.iv_ipaddr; + return 1; +} + +int +isns_object_get_uint32(const isns_object_t *obj, uint32_t tag, + uint32_t *result) +{ + isns_attr_t *attr; + + if (!isns_object_get_attr(obj, tag, &attr) + || !ISNS_ATTR_IS_UINT32(attr)) + return 0; + + *result = attr->ia_value.iv_uint32; + return 1; +} + +int +isns_object_get_uint64(const isns_object_t *obj, uint32_t tag, + uint64_t *result) +{ + isns_attr_t *attr; + + if (!isns_object_get_attr(obj, tag, &attr) + || !ISNS_ATTR_IS_UINT64(attr)) + return 0; + + *result = attr->ia_value.iv_uint64; + return 1; +} + +int +isns_object_get_opaque(const isns_object_t *obj, uint32_t tag, + const void **ptr, size_t *len) +{ + isns_attr_t *attr; + + if (!isns_object_get_attr(obj, tag, &attr) + || !ISNS_ATTR_IS_OPAQUE(attr)) + return 0; + + *ptr = attr->ia_value.iv_opaque.ptr; + *len = attr->ia_value.iv_opaque.len; + return 1; +} + +int +isns_object_delete_attr(isns_object_t *obj, uint32_t tag) +{ + return isns_attr_list_remove_tag(&obj->ie_attrs, tag); +} + +int +isns_object_remove_member(isns_object_t *obj, + const isns_attr_t *attr, + const uint32_t *subordinate_tags) +{ + return isns_attr_list_remove_member(&obj->ie_attrs, + attr, subordinate_tags); +} + +/* + * Object list functions + */ +void +isns_object_list_init(isns_object_list_t *list) +{ + memset(list, 0, sizeof(*list)); +} + +static inline void +__isns_object_list_resize(isns_object_list_t *list, unsigned int count) +{ + unsigned int max; + + max = (list->iol_count + 15) & ~15; + if (count < max) + return; + + count = (count + 15) & ~15; + list->iol_data = isns_realloc(list->iol_data, count * sizeof(isns_object_t *)); + if (!list->iol_data) + isns_fatal("Out of memory!\n"); +} + +void +isns_object_list_append(isns_object_list_t *list, isns_object_t *obj) +{ + __isns_object_list_resize(list, list->iol_count + 1); + list->iol_data[list->iol_count++] = obj; + obj->ie_users++; +} + +void +isns_object_list_append_list(isns_object_list_t *dst, + const isns_object_list_t *src) +{ + unsigned int i, j; + + __isns_object_list_resize(dst, dst->iol_count + src->iol_count); + j = dst->iol_count; + for (i = 0; i < src->iol_count; ++i, ++j) { + isns_object_t *obj = src->iol_data[i]; + + dst->iol_data[j] = obj; + obj->ie_users++; + } + dst->iol_count = j; +} + +int +isns_object_list_contains(const isns_object_list_t *list, + isns_object_t *obj) +{ + unsigned int i; + + for (i = 0; i < list->iol_count; ++i) { + if (obj == list->iol_data[i]) + return 1; + } + return 0; +} + +isns_object_t * +isns_object_list_lookup(const isns_object_list_t *list, + isns_object_template_t *tmpl, + const isns_attr_list_t *keys) +{ + unsigned int i; + + if (!tmpl && !keys) + return NULL; + + if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) + return NULL; + + for (i = 0; i < list->iol_count; ++i) { + isns_object_t *obj = list->iol_data[i]; + + if (obj->ie_template != tmpl) + continue; + if (keys && !isns_object_match(obj, keys)) + continue; + + obj->ie_users++; + return obj; + } + + return NULL; +} + + +int +isns_object_list_gang_lookup(const isns_object_list_t *list, + isns_object_template_t *tmpl, + const isns_attr_list_t *keys, + isns_object_list_t *result) +{ + unsigned int i; + + if (!tmpl && !keys) + return ISNS_INVALID_QUERY; + + if (!tmpl && !(tmpl = isns_object_template_for_key_attrs(keys))) + return ISNS_INVALID_QUERY; + + for (i = 0; i < list->iol_count; ++i) { + isns_object_t *obj = list->iol_data[i]; + + if (obj->ie_template != tmpl) + continue; + if (keys && !isns_object_match(obj, keys)) + continue; + + isns_object_list_append(result, obj); + } + + return ISNS_SUCCESS; +} + + +void +isns_object_list_destroy(isns_object_list_t *list) +{ + unsigned int i; + + for (i = 0; i < list->iol_count; ++i) { + isns_object_t *obj = list->iol_data[i]; + + isns_object_release(obj); + } + + isns_free(list->iol_data); + memset(list, 0, sizeof(*list)); +} + +int +isns_object_list_remove(isns_object_list_t *list, isns_object_t *tbr) +{ + unsigned int i, last; + + last = list->iol_count - 1; + for (i = 0; i < list->iol_count; ++i) { + isns_object_t *obj = list->iol_data[i]; + + if (obj == tbr) { + list->iol_data[i] = list->iol_data[last]; + list->iol_count--; + isns_object_release(tbr); + return 1; + } + } + return 0; +} + +static int +isns_object_compare_id(const void *pa, const void *pb) +{ + const isns_object_t *a = *(const isns_object_t **) pa; + const isns_object_t *b = *(const isns_object_t **) pb; + + return (int) a->ie_index - (int) b->ie_index; +} + +void +isns_object_list_sort(isns_object_list_t *list) +{ + if (list->iol_count == 0) + return; + + qsort(list->iol_data, list->iol_count, + sizeof(void *), isns_object_compare_id); +} + +void +isns_object_list_uniq(isns_object_list_t *list) +{ + isns_object_t *prev = NULL, *this; + unsigned int i, j; + + isns_object_list_sort(list); + for (i = j = 0; i < list->iol_count; i++) { + this = list->iol_data[i]; + if (this != prev) + list->iol_data[j++] = this; + prev = this; + } + list->iol_count = j; +} + +void +isns_object_list_print(const isns_object_list_t *list, isns_print_fn_t *fn) +{ + unsigned int i; + + if (list->iol_count == 0) { + fn("(Object list empty)\n"); + return; + } + + for (i = 0; i < list->iol_count; ++i) { + isns_object_t *obj; + + obj = list->iol_data[i]; + fn("object[%u] = <%s>\n", i, + obj->ie_template->iot_name); + isns_object_print(obj, fn); + } +} + +/* + * Handle object references + */ +void +isns_object_reference_set(isns_object_ref_t *ref, isns_object_t *obj) +{ + isns_object_t *old; + + if (obj) { + isns_assert(obj->ie_users); + obj->ie_references++; + obj->ie_users++; + } + if ((old = ref->obj) != NULL) { + isns_assert(old->ie_references); + old->ie_references--; + isns_object_release(old); + } + ref->obj = obj; +} + +void +isns_object_reference_drop(isns_object_ref_t *ref) +{ + isns_object_reference_set(ref, NULL); +} + +/* + * Helper function for portal/object conversion + */ +int +isns_portal_from_object(isns_portal_info_t *portal, + uint32_t addr_tag, uint32_t port_tag, + const isns_object_t *obj) +{ + return isns_portal_from_attr_list(portal, + addr_tag, port_tag, &obj->ie_attrs); +} + +int +isns_portal_to_object(const isns_portal_info_t *portal, + uint32_t addr_tag, uint32_t port_tag, + isns_object_t *obj) +{ + return isns_portal_to_attr_list(portal, + addr_tag, port_tag, + &obj->ie_attrs); +} + +/* + * Portal + */ +static uint32_t portal_attrs[] = { + ISNS_TAG_PORTAL_IP_ADDRESS, + ISNS_TAG_PORTAL_TCP_UDP_PORT, + ISNS_TAG_PORTAL_SYMBOLIC_NAME, + ISNS_TAG_ESI_INTERVAL, + ISNS_TAG_ESI_PORT, + ISNS_TAG_PORTAL_INDEX, + ISNS_TAG_SCN_PORT, + ISNS_TAG_PORTAL_NEXT_INDEX, + ISNS_TAG_PORTAL_SECURITY_BITMAP, + ISNS_TAG_PORTAL_ISAKMP_PHASE_1, + ISNS_TAG_PORTAL_ISAKMP_PHASE_2, + ISNS_TAG_PORTAL_CERTIFICATE, +}; + +static uint32_t portal_key_attrs[] = { + ISNS_TAG_PORTAL_IP_ADDRESS, + ISNS_TAG_PORTAL_TCP_UDP_PORT, +}; + +isns_object_template_t isns_portal_template = { + .iot_name = "Portal", + .iot_handle = ISNS_OBJECT_TYPE_PORTAL, + .iot_attrs = portal_attrs, + .iot_num_attrs = array_num_elements(portal_attrs), + .iot_keys = portal_key_attrs, + .iot_num_keys = array_num_elements(portal_key_attrs), + .iot_index = ISNS_TAG_PORTAL_INDEX, + .iot_next_index = ISNS_TAG_PORTAL_NEXT_INDEX, + .iot_container = &isns_entity_template, +}; |