name_table.c 27.7 KB
Newer Older
P
Per Liden 已提交
1 2 3
/*
 * net/tipc/name_table.c: TIPC name table code
 * 
P
Per Liden 已提交
4
 * Copyright (c) 2000-2006, Ericsson AB
P
Per Liden 已提交
5 6 7
 * Copyright (c) 2004-2005, Wind River Systems
 * 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 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
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "dbg.h"
#include "name_table.h"
#include "name_distr.h"
#include "addr.h"
#include "node_subscr.h"
#include "subscr.h"
#include "port.h"
#include "cluster.h"
#include "bcast.h"

int tipc_nametbl_size = 1024;		/* must be a power of 2 */

/**
 * struct sub_seq - container for all published instances of a name sequence
 * @lower: name sequence lower bound
 * @upper: name sequence upper bound
 * @node_list: circular list of matching publications with >= node scope
 * @cluster_list: circular list of matching publications with >= cluster scope
 * @zone_list: circular list of matching publications with >= zone scope
 */

struct sub_seq {
	u32 lower;
	u32 upper;
	struct publication *node_list;
	struct publication *cluster_list;
	struct publication *zone_list;
};

/** 
 * 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
 * @first_free: upper bound of highest sub-sequence + 1
 * @ns_list: links to adjacent name sequences in hash chain
 * @subscriptions: list of subscriptions for this 'type'
 * @lock: spinlock controlling access to name sequence structure
 */

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
 * @types: pointer to fixed-sized array of name sequence lists, 
 *         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;
};

102
static struct name_table table = { NULL } ;
P
Per Liden 已提交
103
static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
104
rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED;
P
Per Liden 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123


static inline int hash(int x)
{
	return(x & (tipc_nametbl_size - 1));
}

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

static struct publication *publ_create(u32 type, u32 lower, u32 upper, 
				       u32 scope, u32 node, u32 port_ref,   
				       u32 key)
{
	struct publication *publ =
		(struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
	if (publ == NULL) {
		warn("Memory squeeze; failed to create publication\n");
124
		return NULL;
P
Per Liden 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	}

	memset(publ, 0, sizeof(*publ));
	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;
}

/**
142
 * tipc_subseq_alloc - allocate a specified number of sub-sequence structures
P
Per Liden 已提交
143 144
 */

145
struct sub_seq *tipc_subseq_alloc(u32 cnt)
P
Per Liden 已提交
146 147 148 149 150 151 152 153 154 155
{
	u32 sz = cnt * sizeof(struct sub_seq);
	struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);

	if (sseq)
		memset(sseq, 0, sz);
	return sseq;
}

/**
156
 * tipc_nameseq_create - create a name sequence structure for the specified 'type'
P
Per Liden 已提交
157 158 159 160
 * 
 * Allocates a single sub-sequence structure and sets it to all 0's.
 */

161
struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
P
Per Liden 已提交
162 163 164
{
	struct name_seq *nseq = 
		(struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
165
	struct sub_seq *sseq = tipc_subseq_alloc(1);
P
Per Liden 已提交
166 167 168 169 170

	if (!nseq || !sseq) {
		warn("Memory squeeze; failed to create name sequence\n");
		kfree(nseq);
		kfree(sseq);
171
		return NULL;
P
Per Liden 已提交
172 173 174 175 176 177
	}

	memset(nseq, 0, sizeof(*nseq));
	nseq->lock = SPIN_LOCK_UNLOCKED;
	nseq->type = type;
	nseq->sseqs = sseq;
178
	dbg("tipc_nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n",
P
Per Liden 已提交
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
	    nseq, type, nseq->sseqs, nseq->first_free);
	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
 *  
 * Very time-critical, so binary searches through sub-sequence array.
 */

static inline struct sub_seq *nameseq_find_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 &sseqs[mid];
	}
210
	return NULL;
P
Per Liden 已提交
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
}

/**
 * nameseq_locate_subseq - determine position of name instance in sub-sequence
 * 
 * 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;
}

/**
243
 * tipc_nameseq_insert_publ - 
P
Per Liden 已提交
244 245
 */

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

	assert(nseq->first_free <= nseq->alloc);
	sseq = nameseq_find_subseq(nseq, lower);
	dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n",
	    nseq, type, lower, sseq);
	if (sseq) {

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

		if ((sseq->lower != lower) || (sseq->upper != upper)) {
			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
266
			return NULL;
P
Per Liden 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280
		}
	} 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)) {
			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
281
			return NULL;
P
Per Liden 已提交
282 283 284 285 286 287
		}

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

		if (nseq->first_free == nseq->alloc) {
			struct sub_seq *sseqs = nseq->sseqs;
288
			nseq->sseqs = tipc_subseq_alloc(nseq->alloc * 2);
P
Per Liden 已提交
289 290 291 292 293 294 295 296
			if (nseq->sseqs != NULL) {
				memcpy(nseq->sseqs, sseqs,
				       nseq->alloc * sizeof (struct sub_seq));
				kfree(sseqs);
				dbg("Allocated %u sseqs\n", nseq->alloc);
				nseq->alloc *= 2;
			} else {
				warn("Memory squeeze; failed to create sub-sequence\n");
297
				return NULL;
P
Per Liden 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
			}
		}
		dbg("Have %u sseqs for type %u\n", nseq->alloc, type);

		/* Insert new sub-sequence */

		dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free);
		sseq = &nseq->sseqs[inspos];
		freesseq = &nseq->sseqs[nseq->first_free];
		memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq));
		memset(sseq, 0, sizeof (*sseq));
		nseq->first_free++;
		sseq->lower = lower;
		sseq->upper = upper;
		created_subseq = 1;
	}
	dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n",
	    type, lower, upper, node, port, sseq,
	    sseq->lower, sseq->upper, nseq);

	/* Insert a publication: */

	publ = publ_create(type, lower, upper, scope, node, port, key);
	if (!publ)
322
		return NULL;
P
Per Liden 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
	    publ, node, publ->node, publ->subscr.node);

	if (!sseq->zone_list)
		sseq->zone_list = publ->zone_list_next = publ;
	else {
		publ->zone_list_next = sseq->zone_list->zone_list_next;
		sseq->zone_list->zone_list_next = publ;
	}

	if (in_own_cluster(node)) {
		if (!sseq->cluster_list)
			sseq->cluster_list = publ->cluster_list_next = publ;
		else {
			publ->cluster_list_next =
			sseq->cluster_list->cluster_list_next;
			sseq->cluster_list->cluster_list_next = publ;
		}
	}

	if (node == tipc_own_addr) {
		if (!sseq->node_list)
			sseq->node_list = publ->node_list_next = publ;
		else {
			publ->node_list_next = sseq->node_list->node_list_next;
			sseq->node_list->node_list_next = publ;
		}
	}

	/* 
	 * Any subscriptions waiting for notification? 
	 */
	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
		dbg("calling report_overlap()\n");
357 358 359 360 361 362 363
		tipc_subscr_report_overlap(s,
					   publ->lower,
					   publ->upper,
					   TIPC_PUBLISHED,
					   publ->ref, 
					   publ->node,
					   created_subseq);
P
Per Liden 已提交
364 365 366 367 368
	}
	return publ;
}

/**
369
 * tipc_nameseq_remove_publ -
P
Per Liden 已提交
370 371
 */

372 373
struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
					     u32 node, u32 ref, u32 key)
P
Per Liden 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
{
	struct publication *publ;
	struct publication *prev;
	struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
	struct sub_seq *free;
	struct subscription *s, *st;
	int removed_subseq = 0;

	assert(nseq);

	if (!sseq) {
		int i;

		warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
		assert(nseq->sseqs);
		dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
		    nseq->sseqs, nseq, nseq->alloc, 
		    nseq->first_free);
		for (i = 0; i < nseq->first_free; i++) {
			dbg("Subseq %u(%x): lower = %u,upper = %u\n",
			    i, &nseq->sseqs[i], nseq->sseqs[i].lower,
			    nseq->sseqs[i].upper);
		}
397
		return NULL;
P
Per Liden 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
	}
	dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
	    nseq, sseq, nseq->type, inst, key);

	prev = sseq->zone_list;
	publ = sseq->zone_list->zone_list_next;
	while ((publ->key != key) || (publ->ref != ref) || 
	       (publ->node && (publ->node != node))) {
		prev = publ;
		publ = publ->zone_list_next;
		assert(prev != sseq->zone_list);
	}
	if (publ != sseq->zone_list)
		prev->zone_list_next = publ->zone_list_next;
	else if (publ->zone_list_next != publ) {
		prev->zone_list_next = publ->zone_list_next;
		sseq->zone_list = publ->zone_list_next;
	} else {
416
		sseq->zone_list = NULL;
P
Per Liden 已提交
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	}

	if (in_own_cluster(node)) {
		prev = sseq->cluster_list;
		publ = sseq->cluster_list->cluster_list_next;
		while ((publ->key != key) || (publ->ref != ref) || 
		       (publ->node && (publ->node != node))) {
			prev = publ;
			publ = publ->cluster_list_next;
			assert(prev != sseq->cluster_list);
		}
		if (publ != sseq->cluster_list)
			prev->cluster_list_next = publ->cluster_list_next;
		else if (publ->cluster_list_next != publ) {
			prev->cluster_list_next = publ->cluster_list_next;
			sseq->cluster_list = publ->cluster_list_next;
		} else {
434
			sseq->cluster_list = NULL;
P
Per Liden 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
		}
	}

	if (node == tipc_own_addr) {
		prev = sseq->node_list;
		publ = sseq->node_list->node_list_next;
		while ((publ->key != key) || (publ->ref != ref) || 
		       (publ->node && (publ->node != node))) {
			prev = publ;
			publ = publ->node_list_next;
			assert(prev != sseq->node_list);
		}
		if (publ != sseq->node_list)
			prev->node_list_next = publ->node_list_next;
		else if (publ->node_list_next != publ) {
			prev->node_list_next = publ->node_list_next;
			sseq->node_list = publ->node_list_next;
		} else {
453
			sseq->node_list = NULL;
P
Per Liden 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
		}
	}
	assert(!publ->node || (publ->node == node));
	assert(publ->ref == ref);
	assert(publ->key == key);

	/* 
	 * Contract subseq list if no more publications:
	 */
	if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
		free = &nseq->sseqs[nseq->first_free--];
		memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
		removed_subseq = 1;
	}

	/* 
	 * Any subscriptions waiting ? 
	 */
	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
473 474 475 476 477 478 479
		tipc_subscr_report_overlap(s,
					   publ->lower,
					   publ->upper,
					   TIPC_WITHDRAWN, 
					   publ->ref, 
					   publ->node,
					   removed_subseq);
P
Per Liden 已提交
480 481 482 483 484
	}
	return publ;
}

/**
485
 * tipc_nameseq_subscribe: attach a subscription, and issue
P
Per Liden 已提交
486 487 488 489
 * the prescribed number of events if there is any sub-
 * sequence overlapping with the requested sequence
 */

490
void tipc_nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
P
Per Liden 已提交
491 492 493 494 495 496 497 498 499 500
{
	struct sub_seq *sseq = nseq->sseqs;

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

	if (!sseq)
		return;

	while (sseq != &nseq->sseqs[nseq->first_free]) {
		struct publication *zl = sseq->zone_list;
501
		if (zl && tipc_subscr_overlap(s,sseq->lower,sseq->upper)) {
P
Per Liden 已提交
502 503 504 505
			struct publication *crs = zl;
			int must_report = 1;

			do {
506 507 508 509 510 511 512
				tipc_subscr_report_overlap(s, 
							   sseq->lower, 
							   sseq->upper,
							   TIPC_PUBLISHED,
							   crs->ref,
							   crs->node,
							   must_report);
P
Per Liden 已提交
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
				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;

	dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n",
	    type, ntohl(type), type, table.types, hash(type));

	seq_head = &table.types[hash(type)];
	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
		if (ns->type == type) {
			dbg("found %x\n", ns);
			return ns;
		}
	}

538
	return NULL;
P
Per Liden 已提交
539 540
};

541 542
struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
					     u32 scope, u32 node, u32 port, u32 key)
P
Per Liden 已提交
543 544 545 546 547 548 549
{
	struct name_seq *seq = nametbl_find_seq(type);

	dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq);
	if (lower > upper) {
		warn("Failed to publish illegal <%u,%u,%u>\n",
		     type, lower, upper);
550
		return NULL;
P
Per Liden 已提交
551 552 553 554
	}

	dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
	if (!seq) {
555 556
		seq = tipc_nameseq_create(type, &table.types[hash(type)]);
		dbg("tipc_nametbl_insert_publ: created %x\n", seq);
P
Per Liden 已提交
557 558
	}
	if (!seq)
559
		return NULL;
P
Per Liden 已提交
560 561

	assert(seq->type == type);
562 563
	return tipc_nameseq_insert_publ(seq, type, lower, upper,
					scope, node, port, key);
P
Per Liden 已提交
564 565
}

566 567
struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, 
					     u32 node, u32 ref, u32 key)
P
Per Liden 已提交
568 569 570 571 572
{
	struct publication *publ;
	struct name_seq *seq = nametbl_find_seq(type);

	if (!seq)
573
		return NULL;
P
Per Liden 已提交
574 575

	dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
576
	publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
P
Per Liden 已提交
577 578 579 580 581 582 583 584 585 586

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

/*
587
 * tipc_nametbl_translate(): Translate tipc_name -> tipc_portid.
P
Per Liden 已提交
588 589 590 591 592 593
 *                      Very time-critical.
 *
 * 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)
 */

594
u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
P
Per Liden 已提交
595 596
{
	struct sub_seq *sseq;
597
	struct publication *publ = NULL;
P
Per Liden 已提交
598 599 600 601 602 603
	struct name_seq *seq;
	u32 ref;

	if (!in_scope(*destnode, tipc_own_addr))
		return 0;

604
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
	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);

	/* Closest-First Algorithm: */
	if (likely(!*destnode)) {
		publ = sseq->node_list;
		if (publ) {
			sseq->node_list = publ->node_list_next;
found:
			ref = publ->ref;
			*destnode = publ->node;
			spin_unlock_bh(&seq->lock);
622
			read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
			return ref;
		}
		publ = sseq->cluster_list;
		if (publ) {
			sseq->cluster_list = publ->cluster_list_next;
			goto found;
		}
		publ = sseq->zone_list;
		if (publ) {
			sseq->zone_list = publ->zone_list_next;
			goto found;
		}
	}

	/* Round-Robin Algorithm: */
	else if (*destnode == tipc_own_addr) {
		publ = sseq->node_list;
		if (publ) {
			sseq->node_list = publ->node_list_next;
			goto found;
		}
	} else if (in_own_cluster(*destnode)) {
		publ = sseq->cluster_list;
		if (publ) {
			sseq->cluster_list = publ->cluster_list_next;
			goto found;
		}
	} else {
		publ = sseq->zone_list;
		if (publ) {
			sseq->zone_list = publ->zone_list_next;
			goto found;
		}
	}
	spin_unlock_bh(&seq->lock);
not_found:
	*destnode = 0;
660
	read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
661 662 663 664
	return 0;
}

/**
665
 * tipc_nametbl_mc_translate - find multicast destinations
P
Per Liden 已提交
666 667 668 669 670 671 672 673 674 675 676
 * 
 * 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)
 * 
 * Returns non-zero if any off-node ports overlap
 */

677 678
int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
			      struct port_list *dports)
P
Per Liden 已提交
679 680 681 682 683 684
{
	struct name_seq *seq;
	struct sub_seq *sseq;
	struct sub_seq *sseq_stop;
	int res = 0;

685
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
	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;
		publ = sseq->cluster_list;
		if (publ && (publ->scope <= limit))
			do {
				if (publ->node == tipc_own_addr)
703
					tipc_port_list_add(dports, publ->ref);
P
Per Liden 已提交
704 705 706 707 708 709 710 711
				else
					res = 1;
				publ = publ->cluster_list_next;
			} while (publ != sseq->cluster_list);
	}

	spin_unlock_bh(&seq->lock);
exit:
712
	read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
713 714 715 716
	return res;
}

/**
717
 * tipc_nametbl_publish_rsv - publish port name using a reserved name type
P
Per Liden 已提交
718 719
 */

720
int tipc_nametbl_publish_rsv(u32 ref, unsigned int scope, 
P
Per Liden 已提交
721 722 723 724 725 726 727 728 729 730 731
			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;
}

/**
732
 * tipc_nametbl_publish - add name publication to network name tables
P
Per Liden 已提交
733 734
 */

735
struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, 
P
Per Liden 已提交
736 737 738 739 740 741 742
				    u32 scope, u32 port_ref, u32 key)
{
	struct publication *publ;

	if (table.local_publ_count >= tipc_max_publications) {
		warn("Failed publish: max %u local publication\n", 
		     tipc_max_publications);
743
		return NULL;
P
Per Liden 已提交
744 745 746 747
	}
	if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
		warn("Failed to publish reserved name <%u,%u,%u>\n",
		     type, lower, upper);
748
		return NULL;
P
Per Liden 已提交
749 750
	}

751
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
752
	table.local_publ_count++;
753
	publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
P
Per Liden 已提交
754 755
				   tipc_own_addr, port_ref, key);
	if (publ && (scope != TIPC_NODE_SCOPE)) {
756
		tipc_named_publish(publ);
P
Per Liden 已提交
757
	}
758
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
759 760 761 762
	return publ;
}

/**
763
 * tipc_nametbl_withdraw - withdraw name publication from network name tables
P
Per Liden 已提交
764 765
 */

766
int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
P
Per Liden 已提交
767 768 769
{
	struct publication *publ;

770 771 772
	dbg("tipc_nametbl_withdraw:<%d,%d,%d>\n", type, lower, key);
	write_lock_bh(&tipc_nametbl_lock);
	publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
P
Per Liden 已提交
773 774 775
	if (publ) {
		table.local_publ_count--;
		if (publ->scope != TIPC_NODE_SCOPE)
776 777
			tipc_named_withdraw(publ);
		write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
778 779 780 781
		list_del_init(&publ->pport_list);
		kfree(publ);
		return 1;
	}
782
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
783 784 785 786
	return 0;
}

/**
787
 * tipc_nametbl_subscribe - add a subscription object to the name table
P
Per Liden 已提交
788 789 790
 */

void
791
tipc_nametbl_subscribe(struct subscription *s)
P
Per Liden 已提交
792 793 794 795
{
	u32 type = s->seq.type;
	struct name_seq *seq;

796
        write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
797 798
	seq = nametbl_find_seq(type);
	if (!seq) {
799
		seq = tipc_nameseq_create(type, &table.types[hash(type)]);
P
Per Liden 已提交
800 801 802
	}
        if (seq){
                spin_lock_bh(&seq->lock);
803
                dbg("tipc_nametbl_subscribe:found %x for <%u,%u,%u>\n",
P
Per Liden 已提交
804 805
                    seq, type, s->seq.lower, s->seq.upper);
                assert(seq->type == type);
806
                tipc_nameseq_subscribe(seq, s);
P
Per Liden 已提交
807 808
                spin_unlock_bh(&seq->lock);
        }
809
        write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
810 811 812
}

/**
813
 * tipc_nametbl_unsubscribe - remove a subscription object from name table
P
Per Liden 已提交
814 815 816
 */

void
817
tipc_nametbl_unsubscribe(struct subscription *s)
P
Per Liden 已提交
818 819 820
{
	struct name_seq *seq;

821
        write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
822 823 824 825 826 827 828 829 830 831 832
        seq = nametbl_find_seq(s->seq.type);
	if (seq != NULL){
                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);
                }
        }
833
        write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
}


/**
 * 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];
	char *scopeStr;
	struct publication *publ = sseq->zone_list;

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

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

	do {
		sprintf (portIdStr, "<%u.%u.%u:%u>",
			 tipc_zone(publ->node), tipc_cluster(publ->node),
			 tipc_node(publ->node), publ->ref);
		tipc_printf(buf, "%-26s ", portIdStr);
		if (depth > 3) {
			if (publ->node != tipc_own_addr)
				scopeStr = "";
			else if (publ->scope == TIPC_NODE_SCOPE)
				scopeStr = "node";
			else if (publ->scope == TIPC_CLUSTER_SCOPE)
				scopeStr = "cluster";
			else
				scopeStr = "zone";
			tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
		}

		publ = publ->zone_list_next;
		if (publ == sseq->zone_list)
			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];

	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);
			subseq_list(sseq, buf, depth, index);
			sprintf(typearea, "%10s", " ");
		}
	}
}

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

static void nametbl_header(struct print_buf *buf, u32 depth)
{
	tipc_printf(buf, "Type       ");

	if (depth > 1)
		tipc_printf(buf, "Lower      Upper      ");
	if (depth > 2)
		tipc_printf(buf, "Port Identity              ");
	if (depth > 3)
		tipc_printf(buf, "Publication");

	tipc_printf(buf, "\n-----------");

	if (depth > 1)
		tipc_printf(buf, "--------------------- ");
	if (depth > 2)
		tipc_printf(buf, "-------------------------- ");
	if (depth > 3)
		tipc_printf(buf, "------------------");

	tipc_printf(buf, "\n");
}

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

static void nametbl_list(struct print_buf *buf, u32 depth_info, 
			 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) {
				nameseq_list(seq, buf, depth, seq->type, 
					     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) {
				nameseq_list(seq, buf, depth, type, 
					     lowbound, upbound, i);
				break;
			}
		}
	}
}

986
void tipc_nametbl_print(struct print_buf *buf, const char *str)
P
Per Liden 已提交
987 988
{
	tipc_printf(buf, str);
989
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
990
	nametbl_list(buf, 0, 0, 0, 0);
991
	read_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
992 993 994 995
}

#define MAX_NAME_TBL_QUERY 32768

996
struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
997 998 999 1000 1001 1002 1003 1004
{
	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))
1005
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
1006

1007
	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY));
P
Per Liden 已提交
1008 1009 1010 1011
	if (!buf)
		return NULL;

	rep_tlv = (struct tlv_desc *)buf->data;
1012
	tipc_printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY);
P
Per Liden 已提交
1013
	argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
1014
	read_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1015 1016
	nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type), 
		     ntohl(argv->lowbound), ntohl(argv->upbound));
1017 1018
	read_unlock_bh(&tipc_nametbl_lock);
	str_len = tipc_printbuf_validate(&b);
P
Per Liden 已提交
1019 1020 1021 1022 1023 1024 1025

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

	return buf;
}

1026
void tipc_nametbl_dump(void)
P
Per Liden 已提交
1027
{
1028
	nametbl_list(TIPC_CONS, 0, 0, 0, 0);
P
Per Liden 已提交
1029 1030
}

1031
int tipc_nametbl_init(void)
P
Per Liden 已提交
1032 1033 1034 1035 1036 1037 1038
{
	int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;

	table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC);
	if (!table.types)
		return -ENOMEM;

1039
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1040 1041
	memset(table.types, 0, array_size);
	table.local_publ_count = 0;
1042
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1043 1044 1045
	return 0;
}

1046
void tipc_nametbl_stop(void)
P
Per Liden 已提交
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
{
	struct hlist_head *seq_head;
	struct hlist_node *seq_node;
	struct hlist_node *tmp;
	struct name_seq *seq;
	u32 i;

	if (!table.types)
		return;

1057
	write_lock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
	for (i = 0; i < tipc_nametbl_size; i++) {
		seq_head = &table.types[i];
		hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) {
			struct sub_seq *sseq = seq->sseqs;

			for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
				struct publication *publ = sseq->zone_list;
				assert(publ);
				do {
					struct publication *next =
						publ->zone_list_next;
					kfree(publ);
					publ = next;
				}
				while (publ != sseq->zone_list);
			}
		}
	}
	kfree(table.types);
	table.types = NULL;
1078
	write_unlock_bh(&tipc_nametbl_lock);
P
Per Liden 已提交
1079
}