summaryrefslogtreecommitdiff
path: root/utils/open-isns/portal-group.c
blob: 647bbde5434fa31916b940cece22f70d7e1df1b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/*
 * iSNS object model - portal group specific code
 *
 * Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com>
 */

#include <stdlib.h>
#include <string.h>
#include "isns.h"
#include "objects.h"
#include "vendor.h"
#include "attrs.h"
#include "util.h"

/* For relationship stuff - should go */
#include "db.h"


/*
 * Retrieve attribute @old_tag from object @obj, create a copy with
 * tag @new_tag, and append it to list @dst.
 * (Helper function for the portal group stuff)
 */
static int
__isns_object_translate_attr(isns_object_t *obj,
		uint32_t old_tag, uint32_t new_tag,
		isns_attr_list_t *dst)
{
	isns_value_t	value;

	if (!isns_attr_list_get_value(&obj->ie_attrs, old_tag, &value))
		return 0;
	isns_attr_list_append_value(dst, new_tag, NULL, &value);
	return 1;
}


/*
 * 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;
}

/*
 * Find the portal for a given portal group
 */
static isns_object_t *
__isns_pg_find_portal(isns_db_t *db, isns_object_t *pg,
		const isns_object_list_t *extra_objs)
{
	isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
	isns_object_t	*obj = NULL;

	/* FIXME: ISNS_TAG_PG_PORTAL_IP_ADDR -> ...ADDRESS */
	if (!__isns_object_translate_attr(pg,
				ISNS_TAG_PG_PORTAL_IP_ADDR,
				ISNS_TAG_PORTAL_IP_ADDRESS,
				&key_attrs))
		goto out;
	if (!__isns_object_translate_attr(pg,
				ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
				ISNS_TAG_PORTAL_TCP_UDP_PORT,
				&key_attrs))
		goto out;

	obj = isns_db_lookup(db, &isns_portal_template, &key_attrs);
	if (!obj && extra_objs)
		obj = isns_object_list_lookup(extra_objs,
				&isns_portal_template, &key_attrs);

out:
	isns_attr_list_destroy(&key_attrs);
	return obj;
}

/*
 * Find the node for a given portal group
 */
static isns_object_t *
__isns_pg_find_node(isns_db_t *db, isns_object_t *pg,
		const isns_object_list_t *extra_objs)
{
	isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
	isns_object_t	*obj = NULL;

	if (!__isns_object_translate_attr(pg,
				ISNS_TAG_PG_ISCSI_NAME,
				ISNS_TAG_ISCSI_NAME,
				&key_attrs))
		goto out;

	obj = isns_db_lookup(db, &isns_iscsi_node_template, &key_attrs);
	if (!obj && extra_objs)
		obj = isns_object_list_lookup(extra_objs,
				&isns_iscsi_node_template, &key_attrs);

out:
	isns_attr_list_destroy(&key_attrs);
	return obj;
}

/*
 * When creating a portal group, it must not connect nodes and
 * portals from other entities. However, it is perfectly fine to
 * link objects in limbo.
 */
static inline int
__isns_pg_may_relate(isns_object_t *entity, isns_object_t *subordinate)
{
	isns_object_t *other;

	other = isns_object_get_entity(subordinate);
	return other == NULL || other == entity;
}

/*
 * Given a portal group object, create the relationship
 */
isns_relation_t *
isns_db_build_pg_relation(isns_db_t *db, isns_object_t *pg,
		const isns_object_list_t *extra_objs)
{
	isns_object_t   *entity, *node = NULL, *portal = NULL;

	entity = isns_object_get_entity(pg);

	node = __isns_pg_find_node(db, pg, extra_objs);
	if (node == NULL) {
		isns_error("Trying to register PG for non-existant node\n");
		goto failed;
	}
	if (!__isns_pg_may_relate(entity, node)) {
		isns_error("Trying to register PG for node in other entity\n");
		goto failed;
	}

	portal = __isns_pg_find_portal(db, pg, extra_objs);
	if (portal == NULL) {
		isns_error("Trying to register PG for non-existant portal\n");
		goto failed;
	}
	if (!__isns_pg_may_relate(entity, portal)) {
		isns_error("Trying to register PG for portal in other entity\n");
		goto failed;
	}

	pg->ie_relation = isns_create_relation(pg,
				ISNS_RELATION_PORTAL_GROUP,
				node, portal);
	isns_object_release(portal);
	isns_object_release(node);

	return pg->ie_relation;

failed:
	if (portal)
		isns_object_release(portal);
	if (node)
		isns_object_release(node);
	return NULL;
}

/*
 * Create a portal group given node, portal and PGT
 */
isns_object_t *
isns_create_portal_group(isns_object_t *portal,
		isns_object_t *node, uint32_t pg_tag)
{
	isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
	isns_object_t	*obj = NULL;

	if (portal == NULL || node == NULL)
		return NULL;

	if (node->ie_container != portal->ie_container) {
		isns_error("Refusing to create portal group "
			   "linking objects from different entities\n");
		return NULL;
	}

	if (__isns_object_translate_attr(node,
				ISNS_TAG_ISCSI_NAME,
				ISNS_TAG_PG_ISCSI_NAME,
				&key_attrs)
	 && __isns_object_translate_attr(portal,
		 		ISNS_TAG_PORTAL_IP_ADDRESS,
				ISNS_TAG_PG_PORTAL_IP_ADDR,
				&key_attrs)
	 && __isns_object_translate_attr(portal,
		 		ISNS_TAG_PORTAL_TCP_UDP_PORT,
				ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
				&key_attrs)) {
		obj = __isns_pg_create(&key_attrs, pg_tag, portal, node);
	}

	isns_attr_list_destroy(&key_attrs);
	return obj;
}

/*
 * 5.6.5.1
 * New PG objects are registered when an associated Portal or
 * iSCSI Node object is registered.  An explicit PG object
 * registration MAY follow a Portal or iSCSI Node object
 * registration in a DevAttrReg message.
 * [...]
 * If the PGT value is not included in the Storage Node or
 * Portal object registration, and if a PGT value was not
 * previously registered for the relationship, then the PGT for
 * the corresponding PG object SHALL be registered with a value
 * of 0x00000001.
 *
 * We return non-NULL if the object was created.
 */
isns_object_t *
isns_create_default_portal_group(isns_db_t *db,
		isns_object_t *portal, isns_object_t *node)
{
	isns_object_t	*obj;

	if (portal == NULL || node == NULL)
		return 0;

	/* See if there is a PG already */
	obj = isns_db_get_relationship_object(db, node, portal,
			ISNS_RELATION_PORTAL_GROUP);
	if (obj != NULL) {
		isns_object_release(obj);
		return NULL;
	}

	return isns_create_portal_group(portal, node, 1);
}

static uint32_t	iscsi_pg_attrs[] = {
	ISNS_TAG_PG_ISCSI_NAME,
	ISNS_TAG_PG_PORTAL_IP_ADDR,
	ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
	ISNS_TAG_PG_TAG,
	ISNS_TAG_PG_INDEX,
};

static uint32_t	iscsi_pg_key_attrs[] = {
	ISNS_TAG_PG_ISCSI_NAME,
	ISNS_TAG_PG_PORTAL_IP_ADDR,
	ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
};

isns_object_template_t		isns_iscsi_pg_template = {
	.iot_name	= "iSCSI Portal Group",
	.iot_handle	= ISNS_OBJECT_TYPE_PG,
	.iot_attrs	= iscsi_pg_attrs,
	.iot_num_attrs	= array_num_elements(iscsi_pg_attrs),
	.iot_keys	= iscsi_pg_key_attrs,
	.iot_num_keys	= array_num_elements(iscsi_pg_key_attrs),
	.iot_attrs	= iscsi_pg_attrs,
	.iot_keys	= iscsi_pg_key_attrs,
	.iot_index	= ISNS_TAG_PG_INDEX,
	.iot_next_index	= ISNS_TAG_PG_NEXT_INDEX,
	.iot_container	= &isns_entity_template,
	.iot_relation_type = ISNS_RELATION_PORTAL_GROUP,
	.iot_build_relation = isns_db_build_pg_relation,
};