isns_object_t * isns_create_storage_node2(const isns_source_t *source, uint32_t type, isns_object_t *parent) { isns_attr_t *name_attr; isns_object_t *obj; if (parent && !ISNS_IS_ENTITY(parent)) { isns_warning("Invalid container type \"%s\" for storage node: " "should be \"%s\"\n", parent->ie_template->iot_name, isns_entity_template.iot_name); return NULL; } if ((name_attr = isns_source_attr(source)) == NULL) { isns_warning("No source attribute\n"); return NULL; } if (name_attr->ia_tag_id == ISNS_TAG_ISCSI_NAME) { obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); isns_attr_list_update_attr(&obj->ie_attrs, name_attr); isns_object_set_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, type); } else { /* No iFCP yet, sorry */ isns_warning("%s: source tag type %u not supported\n", __FUNCTION__); return NULL; } return obj; }
/* * Callback function which builds an iSNS object from the * list of attr=tag values. */ static int __isns_local_registry_load_object(const char *line, int argc, char **argv, void *user_data) { isns_attr_list_t attrs = ISNS_ATTR_LIST_INIT; struct isns_attr_list_parser state; isns_object_list_t *list = user_data; isns_object_t *obj, *entity = NULL; for (; argc > 0; --argc) { char *attr = argv[argc-1]; if (!strncasecmp(attr, "owner=", 6)) { char *eid = __isns_local_registry_entity_name(attr + 6); ISNS_QUICK_ATTR_LIST_DECLARE(key_attrs, ISNS_TAG_ENTITY_IDENTIFIER, string, eid); if (entity) { isns_error("Duplicate owner entry in registry\n"); continue; } isns_attr_print(&key_attrs.iqa_attr, isns_print_stdout); entity = isns_object_list_lookup(list, &isns_entity_template, &key_attrs.iqa_list); if (entity != NULL) continue; isns_debug_state("Creating fake entity %s\n", eid); entity = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, eid); isns_object_list_append(list, entity); } else { break; } } isns_attr_list_parser_init(&state, NULL); if (!isns_parse_attrs(argc, argv, &attrs, &state)) { isns_error("Unable to parse attrs\n"); isns_attr_list_destroy(&attrs); return 0; } obj = isns_create_object(isns_attr_list_parser_context(&state), &attrs, entity); isns_attr_list_destroy(&attrs); if (obj == NULL) { isns_error("Unable to create object\n"); return 0; } isns_object_list_append(list, obj); return 1; }
static int __create_policy(isns_client_t *clnt, const isns_attr_list_t *attrs) { isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; isns_object_t *obj; int status; obj = isns_create_object(&isns_policy_template, attrs, NULL); if (!obj) isns_fatal("Cannot create policy object\n"); isns_object_list_append(&objects, obj); status = __register_objects(clnt, NULL, &objects); isns_object_list_destroy(&objects); return status; }
int register_objects(isns_client_t *clnt, int argc, char **argv) { isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; isns_object_t *key_obj = NULL; uint32_t status; if (opt_key != NULL) { isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT; struct isns_attr_list_parser state; isns_attr_list_parser_init(&state, NULL); if (!isns_parse_attrs(1, &opt_key, &key_attrs, &state)) { isns_error("Cannot parse registration key \"%s\"\n", opt_key); return 0; } key_obj = isns_create_object(isns_attr_list_parser_context(&state), &key_attrs, NULL); isns_attr_list_destroy(&key_attrs); if (!key_obj) { isns_error("Cannot create registration key object\n"); return 0; } } else { /* If the user does not provide a key object, * create/update an entity. */ key_obj = isns_create_entity(ISNS_ENTITY_PROTOCOL_ISCSI, NULL); } if (!parse_registration(argv, argc, &objects, key_obj)) isns_fatal("Unable to parse registration\n"); status = __register_objects(clnt, key_obj, &objects); isns_object_list_destroy(&objects); isns_object_release(key_obj); return status; }
/* * Portal Group */ static isns_object_t * __isns_pg_create(const isns_attr_list_t *attrs, uint32_t pg_tag, isns_object_t *portal, isns_object_t *node) { isns_object_t *obj; obj = isns_create_object(&isns_iscsi_pg_template, attrs, isns_object_get_entity(portal)); /* * 3.4 * * Each Portal and iSCSI Storage Node registered in an Entity can * be associated using a Portal Group (PG) object. The PG Tag * (PGT), if non-NULL, indicates that the associated Portal * provides access to the associated iSCSI Storage Node in * the Entity. All Portals that have the same PGT value for * a specific iSCSI Storage Node allow coordinated access to * that node. * * 5.6.5.2 * * If the PGT of the Portal Group is not NULL, then a relationship * exists between the indicated Storage Node and Portal; if the * PGT is NULL, then no relationship exists. */ if (pg_tag != 0) { isns_object_set_uint32(obj, ISNS_TAG_PG_TAG, pg_tag); } else { /* A NULL PGT indicates that the * storage node cannot be accessed through * this portal. */ isns_object_set_nil(obj, ISNS_TAG_PG_TAG); } /* This object represents a relationship between portal and storage node. Create a relation. */ obj->ie_relation = isns_create_relation(obj, ISNS_RELATION_PORTAL_GROUP, portal, node); return obj; }
isns_object_t * isns_create_storage_node(const char *name, uint32_t type, isns_object_t *parent) { isns_object_t *obj; if (parent && !ISNS_IS_ENTITY(parent)) { isns_warning("Invalid container type \"%s\" for storage node: " "should be \"%s\"\n", parent->ie_template->iot_name, isns_entity_template.iot_name); return NULL; } obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); isns_object_set_string(obj, ISNS_TAG_ISCSI_NAME, name); isns_object_set_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, type); return obj; }
static int isns_registration_get_next_object(isns_db_t *db, struct isns_attr_list_scanner *st, isns_object_list_t *result) { isns_object_t *current; int status, esi = 0; status = isns_attr_list_scanner_next(st); /* We get here if the registration has a trailing PGT */ if (status == ISNS_NO_SUCH_ENTRY) return ISNS_SUCCESS; if (status) return status; /* * Validate the attrlist. * This makes sure the client does not include * duplicate attributes, readonly attributes * such as Registration Timestamp, Index and Next Index, * or privileged data (such as marking a storage node as * control node). */ status = isns_attr_list_validate(&st->attrs, st->policy, ISNS_DEVICE_ATTRIBUTE_REGISTER); if (status) { isns_debug_protocol("invalid attr in message\n"); return status; } /* * 6.3.4. Entity Status Inquiry Interval * * If the iSNS server is unable to support ESI messages * or the ESI Interval requested, it SHALL [...] reject * the ESI request by returning an "ESI Not Available" * Status Code [...] * * Implementer's note: In section 5.7.5.1, the RFC talks * about modifying the requested ESI interval; so it seems * it's okay to be liberal about the ESI intervals we accept, * and update them quietly. */ if (isns_attr_list_contains(&st->attrs, ISNS_TAG_ESI_PORT)) { if (!isns_esi_enabled) { isns_debug_esi("Refusing to accept portal " "registration with ESI port\n"); return ISNS_ESI_NOT_AVAILABLE; } esi = 1; } /* * Override any registration period specified by the client. */ if (isns_attr_list_contains(&st->attrs, ISNS_TAG_REGISTRATION_PERIOD)) { isns_value_t value = ISNS_VALUE_INIT(uint32, isns_config.ic_registration_period); isns_attr_list_update_value(&st->attrs, ISNS_TAG_REGISTRATION_PERIOD, NULL, &value); } if (st->tmpl == &isns_entity_template) { /* * 5.6.5.1. * A maximum of one Network Entity object can be * created or updated with a single DevAttrReg * message. Consequently, the Operating Attributes * MUST NOT contain more than one Network Entity * object. */ if (st->entities++) { isns_debug_protocol("More than one entity in DevAttrReg msg\n"); return ISNS_INVALID_REGISTRATION; } /* This should be the key object. * The EID specified by by the client may be * empty, so don't overwrite the value we * assigned with something else. */ if (!isns_object_match(st->key_obj, &st->keys)) { isns_debug_protocol("Entity mismatch in message vs. operating attrs\n"); return ISNS_INVALID_REGISTRATION; } current = isns_object_get(st->key_obj); } else if (st->tmpl == &isns_dd_template || st->tmpl == &isns_ddset_template) { isns_debug_protocol("DevAttrReg of type %s not allowed\n", st->tmpl->iot_name); return ISNS_INVALID_REGISTRATION; } else { /* This will also catch objects in limbo. */ current = isns_db_lookup(db, st->tmpl, &st->keys); } if (current != NULL) { /* * If the replace bit is not set, then the message updates * the attributes of the object identified by the Message Key * and its subordinate objects. Existing object containment * relationships MUST NOT be changed. For existing objects, * key attributes MUST NOT be modified, but new subordinate * objects MAY be added. */ /* * [...] * If the Node identified by the Source Attribute is * not a Control Node, then the objects in the operating * attributes MUST be members of the same Network Entity * as the Source Node. */ if (!isns_policy_validate_object_update(st->policy, st->source, current, &st->attrs, ISNS_DEVICE_ATTRIBUTE_REGISTER)) { isns_object_release(current); return ISNS_SOURCE_UNAUTHORIZED; } /* We shouldn't allow messages affecting one Entity * to modify objects owned by a different Entity. * * However, there may be orphan objects (created * while populating discovery domains). These will * not be associated with any Network Entity, so * they're up for grabs. */ if (st->key_obj == current || st->key_obj == current->ie_container) { /* All is well. The current object is the * key object itself, or a direct descendant of the * key object. */ /* FIXME: with FC we can get deeper nesting; * this needs work. */ } else if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", st->tmpl->iot_name, st->key_obj->ie_template->iot_name); goto invalid_registration; } else if (current->ie_container) { /* We shouldn't get here in authenticated mode, * but in insecure mode we still may. */ isns_error("Client attempts to move %s %u to a different %s\n", current->ie_template->iot_name, current->ie_index, st->key_obj->ie_template->iot_name); goto invalid_registration; } } else { if (!isns_object_is_valid_container(st->key_obj, st->tmpl)) { isns_error("Client attempts to add %s object to a %s - tsk tsk.\n", st->tmpl->iot_name, st->key_obj->ie_template->iot_name); goto invalid_registration; } if (!isns_policy_validate_object_creation(st->policy, st->source, st->tmpl, &st->keys, &st->attrs, ISNS_DEVICE_ATTRIBUTE_REGISTER)) { return ISNS_SOURCE_UNAUTHORIZED; } current = isns_create_object(st->tmpl, &st->keys, isns_object_get_entity(st->key_obj)); /* We do not insert the new object into the database yet. * That happens after we're done with parsing *all* * objects. */ } if (!isns_object_set_attrlist(current, &st->attrs)) { isns_debug_state("Error updating object's attrlist\n"); isns_object_release(current); return ISNS_INTERNAL_ERROR; } /* If the client specifies an ESI port, make sure the * ESI interval is set and within bounds. */ if (esi) { uint32_t esi_interval; if (!isns_object_get_uint32(current, ISNS_TAG_ESI_INTERVAL, &esi_interval)) { esi_interval = isns_config.ic_esi_min_interval; } else if (esi_interval < isns_config.ic_esi_min_interval) { esi_interval = isns_config.ic_esi_min_interval; } else if (esi_interval > isns_config.ic_esi_max_interval) { esi_interval = isns_config.ic_esi_max_interval; } else { esi_interval = 0; } if (esi_interval) isns_object_set_uint32(current, ISNS_TAG_ESI_INTERVAL, esi_interval); } /* Append it to the result list. * We do not return the key object, otherwise * we end up putting it into the response twice. */ if (current != st->key_obj) isns_object_list_append(result, current); /* * When a Portal is registered, the Portal attributes MAY immediately be * followed by a PGT attribute. * [...] * When an iSCSI Storage Node is registered, the Storage Node attributes * MAY immediately be followed by a PGT attribute. */ if (st->tmpl == &isns_portal_template || st->tmpl == &isns_iscsi_node_template) { st->pgt_next_attr = ISNS_TAG_PG_TAG; st->pgt_base_object = current; } else if (st->tmpl != &isns_iscsi_pg_template) { st->pgt_next_attr = 0; st->pgt_base_object = NULL; } isns_object_release(current); return ISNS_SUCCESS; invalid_registration: if (current) isns_object_release(current); return ISNS_INVALID_REGISTRATION; }