Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/*
 * Get the key object given in this message
 *
 * It doesn't say anywhere explicitly in the RFC, but
 * the message key can contain both key and non-key
 * attributes. For instance, you can search by
 * Portal Group Index (section 3.4).
 */
static int
isns_registration_get_key(isns_simple_t *reg, isns_db_t *db, isns_object_t **key_obj)
{
	isns_attr_list_t *keys = &reg->is_message_attrs;
	isns_attr_list_t dummy_keys = ISNS_ATTR_LIST_INIT;
	isns_attr_t	*attr;
	isns_object_t	*obj = NULL;
	const char	*eid = NULL;
	char		eidbuf[128];
	int		status = ISNS_SUCCESS;
	int		obj_must_exist = 0;

	/*
	 * 5.6.5.1
	 * If the Message Key is not present, then the DevAttrReg message
	 * implicitly registers a new Network Entity.  In this case,
	 * the replace bit SHALL be ignored; a new Network Entity SHALL
	 * be created.
	 *
	 * Note that some clients seem to leave the message key
	 * empty, but hide the entity identifier in the operating
	 * attrs.
	 */
	if (keys->ial_count != 0) {
		attr = keys->ial_data[0];

		/*
		 * 5.6.5.1
		 * If the Message Key does not contain an EID, and no
		 * pre-existing objects match the Message Key, then the
		 * DevAttrReg message SHALL be rejected with a status
		 * code of 3 (Invalid Registration).
		 */
		if (keys->ial_count != 1
		 || attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER)
			obj_must_exist = 1;
	} else {
		/* Empty message key. But the client may have hidden
		 * the EID in the operating attrs :-/
		 */
		if (reg->is_operating_attrs.ial_count == 0)
			goto create_entity;

		attr = reg->is_operating_attrs.ial_data[0];
		if (attr->ia_tag_id != ISNS_TAG_ENTITY_IDENTIFIER)
			goto create_entity;

		isns_attr_list_append_attr(&dummy_keys, attr);
		keys = &dummy_keys;
	}

	/* If the caller specifies an EID, extract it while
	 * we know what we're doing :-) */
	if (attr->ia_tag_id == ISNS_TAG_ENTITY_IDENTIFIER
	 && ISNS_ATTR_IS_STRING(attr))
		eid = attr->ia_value.iv_string;

	/* Look up the object identified by the keys.
	 * We do not scope the lookup, as the client
	 * may want to add nodes to an entity that's
	 * currently empty - and hence not visible to
	 * any DD. */
	if (!ISNS_ATTR_IS_NIL(attr))
		obj = isns_db_lookup(db, NULL, keys);

	if (obj == NULL && obj_must_exist)
		goto err_invalid;

	if (obj != NULL) {
		/*
		 * Policy: verify that the client is permitted
		 * to access this object.
		 *
		 * This includes
		 *  -	the client node must be the object owner,
		 *	or a control node.
		 *  -	the policy must allow modification of
		 *	this object type.
		 */
		if (!isns_policy_validate_object_access(reg->is_policy,
					reg->is_source,
					obj, reg->is_function))
			goto err_unauthorized;

found_object:
		if (reg->is_replace) {
			isns_object_t *container = NULL;

			if (!ISNS_IS_ENTITY(obj)) {
				container = isns_object_get_entity(obj);
				if (container == NULL) {
					isns_error("Trying to replace %s (id %u) "
						   "which has no container\n",
						obj->ie_template->iot_name,
						obj->ie_index);
					goto err_invalid;
				}
			}

			isns_debug_state("Replacing %s (id %u)\n",
				obj->ie_template->iot_name,
				obj->ie_index);
			isns_db_remove(db, obj);
			isns_object_release(obj);

			/* Purge the deleted objects from the database now */
			isns_db_purge(db);

			/* We need to flush pending SCNs because the
			 * objects may be resurrected from limbo,
			 * and we might be looking at stale data. */
			isns_scn_transmit_all();

			/* It's an entity. Nuke it and create
			 * a new one. */
			if (container == NULL) {
				isns_source_set_entity(reg->is_source, NULL);
				goto create_entity;
			}

			obj = isns_object_get(container);
		}

		goto out;
	}

	/*
	 * If the Message Key contains an EID and no pre-existing objects
	 * match the Message Key, then the DevAttrReg message SHALL create a
	 * new Entity with the specified EID and any new object(s) specified
	 * by the Operating Attributes.  The replace bit SHALL be ignored.
	 *
	 * Implementer's note: the EID attribute may be empty, in which case
	 * we also create a new entity.
	 */

create_entity:
	if (!isns_policy_validate_object_creation(reg->is_policy,
				reg->is_source,
				&isns_entity_template, keys, NULL,
				reg->is_function))
		goto err_unauthorized;

	/*
	 * 5.6.5.1
	 * A registration message that creates a new Network Entity object
	 * MUST contain at least one Portal or one Storage Node.  If the
	 * message does not, then it SHALL be considered invalid and result
	 * in a response with Status Code of 3 (Invalid Registration).
	 */
	/* FIXME: Implement this check */

	/* We try to play nice with lazy clients and attempt to
	 * look up the network entity given the source name.
	 * But we don't do this if a non-NULL EID was given,
	 * because the client may explicitly want to specify more
	 * than one Network Entity.
	 */
	if (eid == NULL) {
		obj = reg->is_source->is_entity;
		if (obj != NULL) {
			isns_object_get(obj);
			goto found_object;
		}

		/* The policy may define a default entity name.
		 * If that is the case, use it.
		 */
		eid = isns_policy_default_entity(reg->is_policy);
		if (eid) {
			obj = isns_db_vlookup(db, &isns_entity_template,
					ISNS_TAG_ENTITY_IDENTIFIER, eid,
					0);
			if (obj) {
				reg->is_source->is_entity = isns_object_get(obj);
				goto found_object;
			}
		}
	}

	/*
	 * 5.6.5.1
	 * If the Message Key and Operating Attributes do not contain
	 * an EID attribute, or if the EID attribute has a length of 0,
	 * then a new Network Entity object SHALL be created and the iSNS
	 * server SHALL supply a unique EID value for it.
	 */
	if (eid == NULL)
		eid = isns_db_generate_eid(db, eidbuf, sizeof(eidbuf));

	/*
	 * 6.2.2.  Entity Protocol
	 *
	 * This attribute is required during initial registration of
	 * the Network Entity.
	 *
	 * Implementer's note: we don't rely on this. Instead, the
	 * Entity Protocol is selected based on the source type.
	 * If the client specifies the protocol, the auto-selected
	 * value is overwritten.
	 */
	obj = isns_create_entity_for_source(reg->is_source, eid);
	if (obj == NULL)
		goto err_invalid;

	isns_source_set_entity(reg->is_source, obj);

	/*
	 * 6.2.6
	 * If a Registration Period is not requested by the iSNS
	 * client and Entity Status Inquiry (ESI) messages are not
	 * enabled for that client, then the Registration Period
	 * SHALL be set to a non-zero value by the iSNS server.
	 * This implementation-specific value for the Registration
	 * Period SHALL be returned in the registration response to the
	 * iSNS client.  The Registration Period may be set to zero,
	 * indicating its non-use, only if ESI messages are enabled for
	 * that Network Entity.
	 *
	 * Implementer's note: we diverge from this in two ways:
	 *  -	the admin may choose to disable registration timeout,
	 *	by setting RegistrationPeriod=0 in the config file
	 *
	 *  -	When a new entity is created, we always set the
	 *	registration interval because we cannot know yet
	 *	whether the client will subsequently enable ESI or
	 *	not.
	 *
	 *  -	The control entity (holding policy objects) will
	 *	not expire.
	 */
	if (isns_config.ic_registration_period
	 && strcasecmp(eid, ISNS_ENTITY_CONTROL)) {
		isns_object_set_uint32(obj,
				ISNS_TAG_REGISTRATION_PERIOD,
				isns_config.ic_registration_period);
		isns_object_set_uint64(obj,
				ISNS_TAG_TIMESTAMP,
				time(NULL));
	}

	/* Insert into database, and set the object's owner */
	isns_db_insert(db, obj);

	reg->is_replace = 0;

out:
	*key_obj = obj;
	isns_attr_list_destroy(&dummy_keys);
	return ISNS_SUCCESS;

error:
	if (obj)
		isns_object_release(obj);
	isns_attr_list_destroy(&dummy_keys);
	return status;

err_unauthorized:
	status = ISNS_SOURCE_UNAUTHORIZED;
	goto error;

err_invalid:
	status = ISNS_INVALID_REGISTRATION;
	goto error;
}
Beispiel #4
0
/*
 * This function is invoked whenever someone changes the
 * database.
 *
 * SCNs are another area where the RFC is fabulously wishy washy.
 * It is not entirely clear when DD/DDS information should be
 * included in a management SCN - one *reasonable* interpretation
 * would be that this happens for DDReg/DDDereg/DDSReg/DDSDereg
 * events only. But some sections make it sound as if DD
 * information is included for all management SCNs.
 */
void
isns_scn_callback(const isns_db_event_t *ev, void *ptr)
{
	isns_object_t	*obj = ev->ie_object;
	isns_scn_t	*scn, **pos;
	isns_attr_t	*timestamp;
	uint32_t	node_type;

	/* Never send out notifications for policy objects and the like. */
	if (obj->ie_flags & ISNS_OBJECT_PRIVATE)
		return;

	/* When an entity is nuked, remove all SCNs to nodes
	 * that registered from there */
	if (ISNS_IS_ENTITY(obj) && (ev->ie_bits & ISNS_SCN_OBJECT_REMOVED_MASK)) {
		pos = &isns_scn_list;
		while ((scn = *pos) != NULL) {
			if (scn->scn_entity != obj) {
				pos = &scn->scn_next;
				continue;
			}
			isns_debug_scn("Deleting SCN registration for %s\n",
					scn->scn_name);
			*pos = scn->scn_next;
			isns_scn_free(scn);
		}
		return;
	}

	/* For now we handle iSCSI nodes only. Maybe later we'll
	 * do iFC nodes as well. */
	if (!ISNS_IS_ISCSI_NODE(obj))
		return;
	if (!isns_object_get_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, &node_type))
		return;

	if (ev->ie_recipient) {
		isns_object_t *dst = ev->ie_recipient;

		isns_debug_scn("SCN unicast <%s %u, %s> -> %s %u\n",
				obj->ie_template->iot_name, obj->ie_index,
				isns_event_string(ev->ie_bits),
				dst->ie_template->iot_name, dst->ie_index);
	} else {
		isns_debug_scn("SCN multicast <%s %u, %s>\n",
				obj->ie_template->iot_name, obj->ie_index,
				isns_event_string(ev->ie_bits));
	}
	timestamp = isns_create_timestamp_attr();

	pos = &isns_scn_list;
	while ((scn = *pos) != NULL) {
		unsigned int	scn_bits, management;
		isns_object_t	*recipient, *dd = NULL;
		isns_simple_t	*call;

		recipient = scn->scn_owner;

		/* Check if the node has gone away completely. */
		if (recipient->ie_scn_mask == 0) {
			*pos = scn->scn_next;
			isns_scn_free(scn);
			continue;
		}

		if (recipient->ie_container == NULL) {
			isns_warning("Internal bug - SCN recipient without container\n");
			/* Clear the bitmask and loop over - this will remove it */
			recipient->ie_scn_mask = 0;
			continue;
		}

		/* See if portals were added/removed.
		 * This does not catch updates that modified *just*
		 * the SCN port */
		if (recipient->ie_container->ie_mtime != scn->scn_last_update) {
			/* Rebuild the list of SCN portals */
			isns_scn_release_funnels(scn);
			scn->scn_last_update = 0;
		}
		pos = &scn->scn_next;

		/* Check for unicast events (triggered for DD addition/removal).
		 * For unicast events, we do not mask the SCN bits, so that
		 * clients who have registered for non-management events
		 * will see the membership events for their DDs nevertheless. */
		if (ev->ie_recipient == NULL) {
			scn_bits = ev->ie_bits & recipient->ie_scn_mask;
			if (scn_bits == 0)
				continue;
			/* Management SCNs should not be delivered to nodes
			 * that have not registered for them. */
			if ((ev->ie_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)
			 && !(recipient->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK))
				continue;
		} else if (recipient == ev->ie_recipient) {
			scn_bits = ev->ie_bits;
		} else {
			/* No match, skip this recipient */
			continue;
		}

		if (scn->scn_last_update == 0) {
			scn->scn_last_update = recipient->ie_container->ie_mtime;
			isns_scn_setup(scn, recipient);
		}

		/* We check for SCN capable portals when processing
		 * the SCN registration. But the portals may go away
		 * in the meantime. */
		if (scn->scn_funnels == NULL)
			continue;

		/* Check SCN bitmask. This will modify the event bits. */
		scn_bits = isns_scn_match(scn, scn_bits, obj, node_type);
		if (scn_bits == 0)
			continue;
		management = !!(scn_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK);

		/*
		 * 2.2.3
		 * A regular SCN registration indicates that the
		 * Discovery Domain Service SHALL be used to control the
		 * distribution of SCN messages.  Receipt of regular
		 * SCNs is limited to the discovery domains in which
		 * the SCN-triggering event takes place.  Regular SCNs
		 * do not contain information about discovery domains.
		 *
		 * Implementer's note: We override check for unicast events.
		 * The reason is that DDDereg will sever the
		 * relationship, and we would never send an SCN for that
		 * event.
		 */
		if (!management && !ev->ie_recipient) {
			if (!isns_object_test_visibility(obj, recipient))
				continue;
		}

		isns_debug_scn("preparing to send SCN to %s\n",
				scn->scn_name);

		if ((call = scn->scn_message) == NULL) {
			call = isns_create_scn(isns_scn_server->is_source,
					scn->scn_attr,
					timestamp);
			if (call == NULL)
				continue;
			scn->scn_message = call;
		}

		/*
		 * If the SCN is a Management SCN, then the SCN message
		 * SHALL also list the DD_ID and/or DDS_ID of the
		 * Discovery Domains and Discovery Domain Sets (if any)
		 * that caused the change in state for that Storage Node.
		 * These additional attributes (i.e., DD_ID and/or DDS_ID)
		 * shall immediately follow the iSCSI Name or FC Port
		 * Name and precede the next SCN bitmap for the next
		 * notification message (if any).
		 */
		if (management && ev->ie_trigger)
			dd = ev->ie_trigger;

		isns_scn_add_event(call, scn_bits, obj, dd);

	}

	isns_attr_release(timestamp);
}