name_table.c 26.6 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/name_table.c: TIPC name table code
3
 *
P
Per Liden 已提交
4
 * Copyright (c) 2000-2006, Ericsson AB
5
 * Copyright (c) 2004-2008, Wind River Systems
P
Per Liden 已提交
6 7
 * All rights reserved.
 *
P
Per Liden 已提交
8
 * Redistribution and use in source and binary forms, with or without
P
Per Liden 已提交
9 10
 * modification, are permitted provided that the following conditions are met:
 *
P
Per Liden 已提交
11 12 13 14 15 16 17 18
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the names of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
P
Per Liden 已提交
19
 *
P
Per Liden 已提交
20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
P
Per Liden 已提交
34 35 36 37 38 39 40 41 42 43
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "name_table.h"
#include "name_distr.h"
#include "subscr.h"
#include "port.h"

A
Adrian Bunk 已提交
44
static int tipc_nametbl_size = 1024;		/* must be a power of 2 */
P
Per Liden 已提交
45 46

/**
47
 * struct name_info - name sequence publication info
48 49 50 51 52 53 54 55 56 57
 * @node_list: circular list of publications made by own node
 * @cluster_list: circular list of publications made by own cluster
 * @zone_list: circular list of publications made by own zone
 * @node_list_size: number of entries in "node_list"
 * @cluster_list_size: number of entries in "cluster_list"
 * @zone_list_size: number of entries in "zone_list"
 *
 * Note: The zone list always contains at least one entry, since all
 *       publications of the associated name sequence belong to it.
 *       (The cluster and node lists may be empty.)
P
Per Liden 已提交
58 59
 */

60
struct name_info {
P
Per Liden 已提交
61 62 63
	struct publication *node_list;
	struct publication *cluster_list;
	struct publication *zone_list;
64 65 66
	u32 node_list_size;
	u32 cluster_list_size;
	u32 zone_list_size;
P
Per Liden 已提交
67 68
};

69 70 71 72 73 74 75 76 77 78 79 80 81
/**
 * struct sub_seq - container for all published instances of a name sequence
 * @lower: name sequence lower bound
 * @upper: name sequence upper bound
 * @info: pointer to name sequence publication info
 */

struct sub_seq {
	u32 lower;
	u32 upper;
	struct name_info *info;
};

82
/**
P
Per Liden 已提交
83 84 85 86 87
 * struct name_seq - container for all published instances of a name type
 * @type: 32 bit 'type' value for name sequence
 * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
 *        sub-sequences are sorted in ascending order
 * @alloc: number of sub-sequences currently in array
88
 * @first_free: array index of first unused sub-sequence entry
P
Per Liden 已提交
89 90
 * @ns_list: links to adjacent name sequences in hash chain
 * @subscriptions: list of subscriptions for this 'type'
91
 * @lock: spinlock controlling access to publication lists of all sub-sequences
P
Per Liden 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105
 */

struct name_seq {
	u32 type;
	struct sub_seq *sseqs;
	u32 alloc;
	u32 first_free;
	struct hlist_node ns_list;
	struct list_head subscriptions;
	spinlock_t lock;
};

/**
 * struct name_table - table containing all existing port name publications
106
 * @types: pointer to fixed-sized array of name sequence lists,
P
Per Liden 已提交
107 108 109 110 111 112 113 114 115
 *         accessed via hashing on 'type'; name sequence lists are *not* sorted
 * @local_publ_count: number of publications issued by this node
 */

struct name_table {
	struct hlist_head *types;
	u32 local_publ_count;
};

116
static struct name_table table;
P
Per Liden 已提交
117
static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
I
Ingo Molnar 已提交
118
DEFINE_RWLOCK(tipc_nametbl_lock);
P
Per Liden 已提交
119 120


S
Sam Ravnborg 已提交
121
static int hash(int x)
P
Per Liden 已提交
122
{
E
Eric Dumazet 已提交
123
	return x & (tipc_nametbl_size - 1);
P
Per Liden 已提交
124 125 126 127 128 129
}

/**
 * publ_create - create a publication structure
 */

130 131
static struct publication *publ_create(u32 type, u32 lower, u32 upper,
				       u32 scope, u32 node, u32 port_ref,
P
Per Liden 已提交
132 133
				       u32 key)
{
134
	struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
P
Per Liden 已提交
135
	if (publ == NULL) {
136
		warn("Publication creation failure, no memory\n");
137
		return NULL;
P
Per Liden 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	}

	publ->type = type;
	publ->lower = lower;
	publ->upper = upper;
	publ->scope = scope;
	publ->node = node;
	publ->ref = port_ref;
	publ->key = key;
	INIT_LIST_HEAD(&publ->local_list);
	INIT_LIST_HEAD(&publ->pport_list);
	INIT_LIST_HEAD(&publ->subscr.nodesub_list);
	return publ;
}

/**
154
 * tipc_subseq_alloc - allocate a specified number of sub-sequence structures
P
Per Liden 已提交
155 156
 */

A
Adrian Bunk 已提交
157
static struct sub_seq *tipc_subseq_alloc(u32 cnt)
P
Per Liden 已提交
158
{
159
	struct sub_seq *sseq = kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC);
P
Per Liden 已提交
160 161 162 163
	return sseq;
}

/**
164
 * tipc_nameseq_create - create a name sequence structure for the specified 'type'
165
 *
P
Per Liden 已提交
166 167 168
 * Allocates a single sub-sequence structure and sets it to all 0's.
 */

A
Adrian Bunk 已提交
169
static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
P
Per Liden 已提交
170
{
171
	struct name_seq *nseq = kzalloc(sizeof(*nseq), GFP_ATOMIC);
172
	struct sub_seq *sseq = tipc_subseq_alloc(1);
P
Per Liden 已提交
173 174

	if (!nseq || !sseq) {
175
		warn("Name sequence creation failed, no memory\n");
P
Per Liden 已提交
176 177
		kfree(nseq);
		kfree(sseq);
178
		return NULL;
P
Per Liden 已提交
179 180
	}

I
Ingo Molnar 已提交
181
	spin_lock_init(&nseq->lock);
P
Per Liden 已提交
182 183 184 185 186 187 188 189 190 191 192
	nseq->type = type;
	nseq->sseqs = sseq;
	nseq->alloc = 1;
	INIT_HLIST_NODE(&nseq->ns_list);
	INIT_LIST_HEAD(&nseq->subscriptions);
	hlist_add_head(&nseq->ns_list, seq_head);
	return nseq;
}

/**
 * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
193
 *
P
Per Liden 已提交
194 195 196
 * Very time-critical, so binary searches through sub-sequence array.
 */

S
Sam Ravnborg 已提交
197 198
static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
					   u32 instance)
P
Per Liden 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
{
	struct sub_seq *sseqs = nseq->sseqs;
	int low = 0;
	int high = nseq->first_free - 1;
	int mid;

	while (low <= high) {
		mid = (low + high) / 2;
		if (instance < sseqs[mid].lower)
			high = mid - 1;
		else if (instance > sseqs[mid].upper)
			low = mid + 1;
		else
			return &sseqs[mid];
	}
214
	return NULL;
P
Per Liden 已提交
215 216 217 218
}

/**
 * nameseq_locate_subseq - determine position of name instance in sub-sequence
219
 *
P
Per Liden 已提交
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
 * Returns index in sub-sequence array of the entry that contains the specified
 * instance value; if no entry contains that value, returns the position
 * where a new entry for it would be inserted in the array.
 *
 * Note: Similar to binary search code for locating a sub-sequence.
 */

static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
{
	struct sub_seq *sseqs = nseq->sseqs;
	int low = 0;
	int high = nseq->first_free - 1;
	int mid;

	while (low <= high) {
		mid = (low + high) / 2;
		if (instance < sseqs[mid].lower)
			high = mid - 1;
		else if (instance > sseqs[mid].upper)
			low = mid + 1;
		else
			return mid;
	}
	return low;
}

/**
247
 * tipc_nameseq_insert_publ -
P
Per Liden 已提交
248 249
 */

A
Adrian Bunk 已提交
250 251 252
static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
						    u32 type, u32 lower, u32 upper,
						    u32 scope, u32 node, u32 port, u32 key)
P
Per Liden 已提交
253 254 255 256 257
{
	struct subscription *s;
	struct subscription *st;
	struct publication *publ;
	struct sub_seq *sseq;
258
	struct name_info *info;
P
Per Liden 已提交
259 260 261 262 263 264 265 266
	int created_subseq = 0;

	sseq = nameseq_find_subseq(nseq, lower);
	if (sseq) {

		/* Lower end overlaps existing entry => need an exact match */

		if ((sseq->lower != lower) || (sseq->upper != upper)) {
267 268
			warn("Cannot publish {%u,%u,%u}, overlap error\n",
			     type, lower, upper);
269
			return NULL;
P
Per Liden 已提交
270
		}
271 272

		info = sseq->info;
P
Per Liden 已提交
273 274 275 276 277 278 279 280 281 282 283 284
	} else {
		u32 inspos;
		struct sub_seq *freesseq;

		/* Find where lower end should be inserted */

		inspos = nameseq_locate_subseq(nseq, lower);

		/* Fail if upper end overlaps into an existing entry */

		if ((inspos < nseq->first_free) &&
		    (upper >= nseq->sseqs[inspos].lower)) {
285 286
			warn("Cannot publish {%u,%u,%u}, overlap error\n",
			     type, lower, upper);
287
			return NULL;
P
Per Liden 已提交
288 289 290 291 292
		}

		/* Ensure there is space for new sub-sequence */

		if (nseq->first_free == nseq->alloc) {
293 294 295
			struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);

			if (!sseqs) {
296 297
				warn("Cannot publish {%u,%u,%u}, no memory\n",
				     type, lower, upper);
298
				return NULL;
P
Per Liden 已提交
299
			}
300 301 302 303 304
			memcpy(sseqs, nseq->sseqs,
			       nseq->alloc * sizeof(struct sub_seq));
			kfree(nseq->sseqs);
			nseq->sseqs = sseqs;
			nseq->alloc *= 2;
P
Per Liden 已提交
305 306
		}

307 308 309 310 311 312 313
		info = kzalloc(sizeof(*info), GFP_ATOMIC);
		if (!info) {
			warn("Cannot publish {%u,%u,%u}, no memory\n",
			     type, lower, upper);
			return NULL;
		}

P
Per Liden 已提交
314 315 316 317
		/* Insert new sub-sequence */

		sseq = &nseq->sseqs[inspos];
		freesseq = &nseq->sseqs[nseq->first_free];
318 319
		memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq));
		memset(sseq, 0, sizeof(*sseq));
P
Per Liden 已提交
320 321 322
		nseq->first_free++;
		sseq->lower = lower;
		sseq->upper = upper;
323
		sseq->info = info;
P
Per Liden 已提交
324 325 326 327 328 329 330
		created_subseq = 1;
	}

	/* Insert a publication: */

	publ = publ_create(type, lower, upper, scope, node, port, key);
	if (!publ)
331
		return NULL;
P
Per Liden 已提交
332

333 334 335
	info->zone_list_size++;
	if (!info->zone_list)
		info->zone_list = publ->zone_list_next = publ;
P
Per Liden 已提交
336
	else {
337 338
		publ->zone_list_next = info->zone_list->zone_list_next;
		info->zone_list->zone_list_next = publ;
P
Per Liden 已提交
339 340 341
	}

	if (in_own_cluster(node)) {
342 343 344
		info->cluster_list_size++;
		if (!info->cluster_list)
			info->cluster_list = publ->cluster_list_next = publ;
P
Per Liden 已提交
345 346
		else {
			publ->cluster_list_next =
347 348
			info->cluster_list->cluster_list_next;
			info->cluster_list->cluster_list_next = publ;
P
Per Liden 已提交
349 350 351 352
		}
	}

	if (node == tipc_own_addr) {
353 354 355
		info->node_list_size++;
		if (!info->node_list)
			info->node_list = publ->node_list_next = publ;
P
Per Liden 已提交
356
		else {
357 358
			publ->node_list_next = info->node_list->node_list_next;
			info->node_list->node_list_next = publ;
P
Per Liden 已提交
359 360 361
		}
	}

362 363
	/*
	 * Any subscriptions waiting for notification?
P
Per Liden 已提交
364 365
	 */
	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
366 367 368 369
		tipc_subscr_report_overlap(s,
					   publ->lower,
					   publ->upper,
					   TIPC_PUBLISHED,
370
					   publ->ref,
371 372
					   publ->node,
					   created_subseq);
P
Per Liden 已提交
373 374 375 376 377
	}
	return publ;
}

/**
378
 * tipc_nameseq_remove_publ -
379
 *
380 381 382 383 384 385 386
 * NOTE: There may be cases where TIPC is asked to remove a publication
 * that is not in the name table.  For example, if another node issues a
 * publication for a name sequence that overlaps an existing name sequence
 * the publication will not be recorded, which means the publication won't
 * be found when the name sequence is later withdrawn by that node.
 * A failed withdraw request simply returns a failure indication and lets the
 * caller issue any error or warning messages associated with such a problem.
P
Per Liden 已提交
387 388
 */

A
Adrian Bunk 已提交
389 390
static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
						    u32 node, u32 ref, u32 key)
P
Per Liden 已提交
391 392
{
	struct publication *publ;
393
	struct publication *curr;
P
Per Liden 已提交
394 395
	struct publication *prev;
	struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
396
	struct name_info *info;
P
Per Liden 已提交
397 398 399 400
	struct sub_seq *free;
	struct subscription *s, *st;
	int removed_subseq = 0;

401
	if (!sseq)
402
		return NULL;
403

404 405
	info = sseq->info;

406 407
	/* Remove publication from zone scope list */

408 409
	prev = info->zone_list;
	publ = info->zone_list->zone_list_next;
410
	while ((publ->key != key) || (publ->ref != ref) ||
P
Per Liden 已提交
411 412 413
	       (publ->node && (publ->node != node))) {
		prev = publ;
		publ = publ->zone_list_next;
414
		if (prev == info->zone_list) {
415

416 417 418 419
			/* Prevent endless loop if publication not found */

			return NULL;
		}
P
Per Liden 已提交
420
	}
421
	if (publ != info->zone_list)
P
Per Liden 已提交
422 423 424
		prev->zone_list_next = publ->zone_list_next;
	else if (publ->zone_list_next != publ) {
		prev->zone_list_next = publ->zone_list_next;
425
		info->zone_list = publ->zone_list_next;
P
Per Liden 已提交
426
	} else {
427
		info->zone_list = NULL;
P
Per Liden 已提交
428
	}
429
	info->zone_list_size--;
P
Per Liden 已提交
430

431 432
	/* Remove publication from cluster scope list, if present */

P
Per Liden 已提交
433
	if (in_own_cluster(node)) {
434 435
		prev = info->cluster_list;
		curr = info->cluster_list->cluster_list_next;
436 437 438
		while (curr != publ) {
			prev = curr;
			curr = curr->cluster_list_next;
439
			if (prev == info->cluster_list) {
440 441 442 443 444

				/* Prevent endless loop for malformed list */

				err("Unable to de-list cluster publication\n"
				    "{%u%u}, node=0x%x, ref=%u, key=%u)\n",
445
				    publ->type, publ->lower, publ->node,
446 447 448
				    publ->ref, publ->key);
				goto end_cluster;
			}
P
Per Liden 已提交
449
		}
450
		if (publ != info->cluster_list)
P
Per Liden 已提交
451 452 453
			prev->cluster_list_next = publ->cluster_list_next;
		else if (publ->cluster_list_next != publ) {
			prev->cluster_list_next = publ->cluster_list_next;
454
			info->cluster_list = publ->cluster_list_next;
P
Per Liden 已提交
455
		} else {
456
			info->cluster_list = NULL;
P
Per Liden 已提交
457
		}
458
		info->cluster_list_size--;
P
Per Liden 已提交
459
	}
460 461 462
end_cluster:

	/* Remove publication from node scope list, if present */
P
Per Liden 已提交
463 464

	if (node == tipc_own_addr) {
465 466
		prev = info->node_list;
		curr = info->node_list->node_list_next;
467 468 469
		while (curr != publ) {
			prev = curr;
			curr = curr->node_list_next;
470
			if (prev == info->node_list) {
471 472 473 474 475

				/* Prevent endless loop for malformed list */

				err("Unable to de-list node publication\n"
				    "{%u%u}, node=0x%x, ref=%u, key=%u)\n",
476
				    publ->type, publ->lower, publ->node,
477 478 479
				    publ->ref, publ->key);
				goto end_node;
			}
P
Per Liden 已提交
480
		}
481
		if (publ != info->node_list)
P
Per Liden 已提交
482 483 484
			prev->node_list_next = publ->node_list_next;
		else if (publ->node_list_next != publ) {
			prev->node_list_next = publ->node_list_next;
485
			info->node_list = publ->node_list_next;
P
Per Liden 已提交
486
		} else {
487
			info->node_list = NULL;
P
Per Liden 已提交
488
		}
489
		info->node_list_size--;
P
Per Liden 已提交
490
	}
491
end_node:
P
Per Liden 已提交
492

493 494
	/* Contract subseq list if no more publications for that subseq */

495 496
	if (!info->zone_list) {
		kfree(info);
P
Per Liden 已提交
497
		free = &nseq->sseqs[nseq->first_free--];
498
		memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq));
P
Per Liden 已提交
499 500 501
		removed_subseq = 1;
	}

502 503
	/* Notify any waiting subscriptions */

P
Per Liden 已提交
504
	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
505 506 507
		tipc_subscr_report_overlap(s,
					   publ->lower,
					   publ->upper,
508 509
					   TIPC_WITHDRAWN,
					   publ->ref,
510 511
					   publ->node,
					   removed_subseq);
P
Per Liden 已提交
512
	}
513

P
Per Liden 已提交
514 515 516 517
	return publ;
}

/**
518
 * tipc_nameseq_subscribe: attach a subscription, and issue
P
Per Liden 已提交
519 520 521 522
 * the prescribed number of events if there is any sub-
 * sequence overlapping with the requested sequence
 */

523
static void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
P
Per Liden 已提交
524 525 526 527 528 529 530 531 532
{
	struct sub_seq *sseq = nseq->sseqs;

	list_add(&s->nameseq_list, &nseq->subscriptions);

	if (!sseq)
		return;

	while (sseq != &nseq->sseqs[nseq->first_free]) {
533
		struct publication *zl = sseq->info->zone_list;
534
		if (zl && tipc_subscr_overlap(s, sseq->lower, sseq->upper)) {
P
Per Liden 已提交
535 536 537 538
			struct publication *crs = zl;
			int must_report = 1;

			do {
539 540
				tipc_subscr_report_overlap(s,
							   sseq->lower,
541 542 543 544 545
							   sseq->upper,
							   TIPC_PUBLISHED,
							   crs->ref,
							   crs->node,
							   must_report);
P
Per Liden 已提交
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
				must_report = 0;
				crs = crs->zone_list_next;
			} while (crs != zl);
		}
		sseq++;
	}
}

static struct name_seq *nametbl_find_seq(u32 type)
{
	struct hlist_head *seq_head;
	struct hlist_node *seq_node;
	struct name_seq *ns;

	seq_head = &table.types[hash(type)];
	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
562
		if (ns->type == type)
P
Per Liden 已提交
563 564 565
			return ns;
	}

566
	return NULL;
P
Per Liden 已提交
567 568
};

569 570
struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
					     u32 scope, u32 node, u32 port, u32 key)
P
Per Liden 已提交
571 572 573 574
{
	struct name_seq *seq = nametbl_find_seq(type);

	if (lower > upper) {
575
		warn("Failed to publish illegal {%u,%u,%u}\n",
P
Per Liden 已提交
576
		     type, lower, upper);
577
		return NULL;
P
Per Liden 已提交
578 579
	}

580
	if (!seq)
581
		seq = tipc_nameseq_create(type, &table.types[hash(type)]);
P
Per Liden 已提交
582
	if (!seq)
583
		return NULL;
P
Per Liden 已提交
584

585 586
	return tipc_nameseq_insert_publ(seq, type, lower, upper,
					scope, node, port, key);
P
Per Liden 已提交
587 588
}

589
struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
590
					     u32 node, u32 ref, u32 key)
P
Per Liden 已提交
591 592 593 594 595
{
	struct publication *publ;
	struct name_seq *seq = nametbl_find_seq(type);

	if (!seq)
596
		return NULL;
P
Per Liden 已提交
597

598
	publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
P
Per Liden 已提交
599 600 601 602 603 604 605 606 607 608

	if (!seq->first_free && list_empty(&seq->subscriptions)) {
		hlist_del_init(&seq->ns_list);
		kfree(seq->sseqs);
		kfree(seq);
	}
	return publ;
}

/*
609
 * tipc_nametbl_translate - translate name to port id
P
Per Liden 已提交
610 611 612 613 614
 *
 * Note: on entry 'destnode' is the search domain used during translation;
 *       on exit it passes back the node address of the matching port (if any)
 */

615
u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
P
Per Liden 已提交
616 617
{
	struct sub_seq *sseq;
618
	struct name_info *info;
619
	struct publication *publ = NULL;
P
Per Liden 已提交
620 621 622
	struct name_seq *seq;
	u32 ref;

623
	if (!tipc_in_scope(*destnode, tipc_own_addr))
P
Per Liden 已提交
624 625
		return 0;

626
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
627 628 629 630 631 632 633
	seq = nametbl_find_seq(type);
	if (unlikely(!seq))
		goto not_found;
	sseq = nameseq_find_subseq(seq, instance);
	if (unlikely(!sseq))
		goto not_found;
	spin_lock_bh(&seq->lock);
634
	info = sseq->info;
P
Per Liden 已提交
635 636 637

	/* Closest-First Algorithm: */
	if (likely(!*destnode)) {
638
		publ = info->node_list;
P
Per Liden 已提交
639
		if (publ) {
640
			info->node_list = publ->node_list_next;
P
Per Liden 已提交
641 642 643 644
found:
			ref = publ->ref;
			*destnode = publ->node;
			spin_unlock_bh(&seq->lock);
645
			read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
646 647
			return ref;
		}
648
		publ = info->cluster_list;
P
Per Liden 已提交
649
		if (publ) {
650
			info->cluster_list = publ->cluster_list_next;
P
Per Liden 已提交
651 652
			goto found;
		}
653
		publ = info->zone_list;
P
Per Liden 已提交
654
		if (publ) {
655
			info->zone_list = publ->zone_list_next;
P
Per Liden 已提交
656 657 658 659 660 661
			goto found;
		}
	}

	/* Round-Robin Algorithm: */
	else if (*destnode == tipc_own_addr) {
662
		publ = info->node_list;
P
Per Liden 已提交
663
		if (publ) {
664
			info->node_list = publ->node_list_next;
P
Per Liden 已提交
665 666 667
			goto found;
		}
	} else if (in_own_cluster(*destnode)) {
668
		publ = info->cluster_list;
P
Per Liden 已提交
669
		if (publ) {
670
			info->cluster_list = publ->cluster_list_next;
P
Per Liden 已提交
671 672 673
			goto found;
		}
	} else {
674
		publ = info->zone_list;
P
Per Liden 已提交
675
		if (publ) {
676
			info->zone_list = publ->zone_list_next;
P
Per Liden 已提交
677 678 679 680 681
			goto found;
		}
	}
	spin_unlock_bh(&seq->lock);
not_found:
682
	read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
683 684 685 686
	return 0;
}

/**
687
 * tipc_nametbl_mc_translate - find multicast destinations
688
 *
P
Per Liden 已提交
689 690 691 692 693 694
 * Creates list of all local ports that overlap the given multicast address;
 * also determines if any off-node ports overlap.
 *
 * Note: Publications with a scope narrower than 'limit' are ignored.
 * (i.e. local node-scope publications mustn't receive messages arriving
 * from another node, even if the multcast link brought it here)
695
 *
P
Per Liden 已提交
696 697 698
 * Returns non-zero if any off-node ports overlap
 */

699 700
int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
			      struct port_list *dports)
P
Per Liden 已提交
701 702 703 704
{
	struct name_seq *seq;
	struct sub_seq *sseq;
	struct sub_seq *sseq_stop;
705
	struct name_info *info;
P
Per Liden 已提交
706 707
	int res = 0;

708
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
709 710 711 712 713 714 715 716 717 718 719 720 721
	seq = nametbl_find_seq(type);
	if (!seq)
		goto exit;

	spin_lock_bh(&seq->lock);

	sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
	sseq_stop = seq->sseqs + seq->first_free;
	for (; sseq != sseq_stop; sseq++) {
		struct publication *publ;

		if (sseq->lower > upper)
			break;
722

723 724
		info = sseq->info;
		publ = info->node_list;
725
		if (publ) {
P
Per Liden 已提交
726
			do {
727
				if (publ->scope <= limit)
728
					tipc_port_list_add(dports, publ->ref);
729
				publ = publ->node_list_next;
730
			} while (publ != info->node_list);
731 732
		}

733
		if (info->cluster_list_size != info->node_list_size)
734
			res = 1;
P
Per Liden 已提交
735 736 737 738
	}

	spin_unlock_bh(&seq->lock);
exit:
739
	read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
740 741 742 743
	return res;
}

/**
744
 * tipc_nametbl_publish_rsv - publish port name using a reserved name type
P
Per Liden 已提交
745 746
 */

747
int tipc_nametbl_publish_rsv(u32 ref, unsigned int scope,
P
Per Liden 已提交
748 749 750 751 752 753 754 755 756 757 758
			struct tipc_name_seq const *seq)
{
	int res;

	atomic_inc(&rsv_publ_ok);
	res = tipc_publish(ref, scope, seq);
	atomic_dec(&rsv_publ_ok);
	return res;
}

/**
759
 * tipc_nametbl_publish - add name publication to network name tables
P
Per Liden 已提交
760 761
 */

762
struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
P
Per Liden 已提交
763 764 765 766 767
				    u32 scope, u32 port_ref, u32 key)
{
	struct publication *publ;

	if (table.local_publ_count >= tipc_max_publications) {
768
		warn("Publication failed, local publication limit reached (%u)\n",
P
Per Liden 已提交
769
		     tipc_max_publications);
770
		return NULL;
P
Per Liden 已提交
771 772
	}
	if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
773
		warn("Publication failed, reserved name {%u,%u,%u}\n",
P
Per Liden 已提交
774
		     type, lower, upper);
775
		return NULL;
P
Per Liden 已提交
776 777
	}

778
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
779
	table.local_publ_count++;
780
	publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
P
Per Liden 已提交
781
				   tipc_own_addr, port_ref, key);
782
	if (publ && (scope != TIPC_NODE_SCOPE))
783 784
		tipc_named_publish(publ);
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
785 786 787 788
	return publ;
}

/**
789
 * tipc_nametbl_withdraw - withdraw name publication from network name tables
P
Per Liden 已提交
790 791
 */

792
int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
P
Per Liden 已提交
793 794 795
{
	struct publication *publ;

796 797
	write_lock_bh(&tipc_nametbl_lock);
	publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
798
	if (likely(publ)) {
P
Per Liden 已提交
799 800
		table.local_publ_count--;
		if (publ->scope != TIPC_NODE_SCOPE)
801 802
			tipc_named_withdraw(publ);
		write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
803 804 805 806
		list_del_init(&publ->pport_list);
		kfree(publ);
		return 1;
	}
807
	write_unlock_bh(&tipc_nametbl_lock);
808 809 810
	err("Unable to remove local publication\n"
	    "(type=%u, lower=%u, ref=%u, key=%u)\n",
	    type, lower, ref, key);
P
Per Liden 已提交
811 812 813 814
	return 0;
}

/**
815
 * tipc_nametbl_subscribe - add a subscription object to the name table
P
Per Liden 已提交
816 817
 */

818
void tipc_nametbl_subscribe(struct subscription *s)
P
Per Liden 已提交
819 820 821 822
{
	u32 type = s->seq.type;
	struct name_seq *seq;

823
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
824
	seq = nametbl_find_seq(type);
825
	if (!seq)
826
		seq = tipc_nameseq_create(type, &table.types[hash(type)]);
827
	if (seq) {
828 829 830 831
		spin_lock_bh(&seq->lock);
		tipc_nameseq_subscribe(seq, s);
		spin_unlock_bh(&seq->lock);
	} else {
832 833
		warn("Failed to create subscription for {%u,%u,%u}\n",
		     s->seq.type, s->seq.lower, s->seq.upper);
834 835
	}
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
836 837 838
}

/**
839
 * tipc_nametbl_unsubscribe - remove a subscription object from name table
P
Per Liden 已提交
840 841
 */

842
void tipc_nametbl_unsubscribe(struct subscription *s)
P
Per Liden 已提交
843 844 845
{
	struct name_seq *seq;

846 847
	write_lock_bh(&tipc_nametbl_lock);
	seq = nametbl_find_seq(s->seq.type);
848
	if (seq != NULL) {
849 850 851 852 853 854 855 856 857 858
		spin_lock_bh(&seq->lock);
		list_del_init(&s->nameseq_list);
		spin_unlock_bh(&seq->lock);
		if ((seq->first_free == 0) && list_empty(&seq->subscriptions)) {
			hlist_del_init(&seq->ns_list);
			kfree(seq->sseqs);
			kfree(seq);
		}
	}
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
859 860 861 862 863 864 865 866 867 868 869
}


/**
 * subseq_list: print specified sub-sequence contents into the given buffer
 */

static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
			u32 index)
{
	char portIdStr[27];
870
	const char *scope_str[] = {"", " zone", " cluster", " node"};
871
	struct publication *publ = sseq->info->zone_list;
P
Per Liden 已提交
872 873 874 875 876 877 878 879 880

	tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);

	if (depth == 2 || !publ) {
		tipc_printf(buf, "\n");
		return;
	}

	do {
881
		sprintf(portIdStr, "<%u.%u.%u:%u>",
P
Per Liden 已提交
882 883 884 885
			 tipc_zone(publ->node), tipc_cluster(publ->node),
			 tipc_node(publ->node), publ->ref);
		tipc_printf(buf, "%-26s ", portIdStr);
		if (depth > 3) {
886 887
			tipc_printf(buf, "%-10u %s", publ->key,
				    scope_str[publ->scope]);
P
Per Liden 已提交
888 889 890
		}

		publ = publ->zone_list_next;
891
		if (publ == sseq->info->zone_list)
P
Per Liden 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
			break;

		tipc_printf(buf, "\n%33s", " ");
	} while (1);

	tipc_printf(buf, "\n");
}

/**
 * nameseq_list: print specified name sequence contents into the given buffer
 */

static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
			 u32 type, u32 lowbound, u32 upbound, u32 index)
{
	struct sub_seq *sseq;
	char typearea[11];

910 911 912
	if (seq->first_free == 0)
		return;

P
Per Liden 已提交
913 914 915 916 917 918 919 920 921 922
	sprintf(typearea, "%-10u", seq->type);

	if (depth == 1) {
		tipc_printf(buf, "%s\n", typearea);
		return;
	}

	for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
		if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
			tipc_printf(buf, "%s ", typearea);
923
			spin_lock_bh(&seq->lock);
P
Per Liden 已提交
924
			subseq_list(sseq, buf, depth, index);
925
			spin_unlock_bh(&seq->lock);
P
Per Liden 已提交
926 927 928 929 930 931 932 933 934 935 936
			sprintf(typearea, "%10s", " ");
		}
	}
}

/**
 * nametbl_header - print name table header into the given buffer
 */

static void nametbl_header(struct print_buf *buf, u32 depth)
{
937 938 939 940 941 942 943 944 945 946 947 948 949
	const char *header[] = {
		"Type       ",
		"Lower      Upper      ",
		"Port Identity              ",
		"Publication Scope"
	};

	int i;

	if (depth > 4)
		depth = 4;
	for (i = 0; i < depth; i++)
		tipc_printf(buf, header[i]);
P
Per Liden 已提交
950 951 952 953 954 955 956
	tipc_printf(buf, "\n");
}

/**
 * nametbl_list - print specified name table contents into the given buffer
 */

957
static void nametbl_list(struct print_buf *buf, u32 depth_info,
P
Per Liden 已提交
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
			 u32 type, u32 lowbound, u32 upbound)
{
	struct hlist_head *seq_head;
	struct hlist_node *seq_node;
	struct name_seq *seq;
	int all_types;
	u32 depth;
	u32 i;

	all_types = (depth_info & TIPC_NTQ_ALLTYPES);
	depth = (depth_info & ~TIPC_NTQ_ALLTYPES);

	if (depth == 0)
		return;

	if (all_types) {
		/* display all entries in name table to specified depth */
		nametbl_header(buf, depth);
		lowbound = 0;
		upbound = ~0;
		for (i = 0; i < tipc_nametbl_size; i++) {
			seq_head = &table.types[i];
			hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
981
				nameseq_list(seq, buf, depth, seq->type,
P
Per Liden 已提交
982 983 984 985 986 987 988 989 990 991 992 993 994 995
					     lowbound, upbound, i);
			}
		}
	} else {
		/* display only the sequence that matches the specified type */
		if (upbound < lowbound) {
			tipc_printf(buf, "invalid name sequence specified\n");
			return;
		}
		nametbl_header(buf, depth);
		i = hash(type);
		seq_head = &table.types[i];
		hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
			if (seq->type == type) {
996
				nameseq_list(seq, buf, depth, type,
P
Per Liden 已提交
997 998 999 1000 1001 1002 1003 1004 1005
					     lowbound, upbound, i);
				break;
			}
		}
	}
}

#define MAX_NAME_TBL_QUERY 32768

1006
struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
1007 1008 1009 1010 1011 1012 1013 1014
{
	struct sk_buff *buf;
	struct tipc_name_table_query *argv;
	struct tlv_desc *rep_tlv;
	struct print_buf b;
	int str_len;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
1015
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
1016

1017
	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY));
P
Per Liden 已提交
1018 1019 1020 1021
	if (!buf)
		return NULL;

	rep_tlv = (struct tlv_desc *)buf->data;
1022
	tipc_printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY);
P
Per Liden 已提交
1023
	argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
1024
	read_lock_bh(&tipc_nametbl_lock);
1025
	nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type),
P
Per Liden 已提交
1026
		     ntohl(argv->lowbound), ntohl(argv->upbound));
1027 1028
	read_unlock_bh(&tipc_nametbl_lock);
	str_len = tipc_printbuf_validate(&b);
P
Per Liden 已提交
1029 1030 1031 1032 1033 1034 1035

	skb_put(buf, TLV_SPACE(str_len));
	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);

	return buf;
}

1036
int tipc_nametbl_init(void)
P
Per Liden 已提交
1037
{
1038 1039
	table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head),
			      GFP_ATOMIC);
P
Per Liden 已提交
1040 1041 1042 1043 1044 1045 1046
	if (!table.types)
		return -ENOMEM;

	table.local_publ_count = 0;
	return 0;
}

1047
void tipc_nametbl_stop(void)
P
Per Liden 已提交
1048 1049 1050 1051 1052 1053
{
	u32 i;

	if (!table.types)
		return;

1054 1055
	/* Verify name table is empty, then release it */

1056
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1057
	for (i = 0; i < tipc_nametbl_size; i++) {
1058 1059
		if (!hlist_empty(&table.types[i]))
			err("tipc_nametbl_stop(): hash chain %u is non-null\n", i);
P
Per Liden 已提交
1060 1061 1062
	}
	kfree(table.types);
	table.types = NULL;
1063
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1064
}
1065