node.c 19.9 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/node.c: TIPC node management routines
3
 *
P
Per Liden 已提交
4
 * Copyright (c) 2000-2006, Ericsson AB
5
 * Copyright (c) 2005-2006, 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 44 45 46 47 48
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "node.h"
#include "cluster.h"
#include "net.h"
#include "addr.h"
#include "node_subscr.h"
#include "link.h"
#include "port.h"
#include "bearer.h"
#include "name_distr.h"

49 50 51
void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str);
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
P
Per Liden 已提交
52

53
struct tipc_node *tipc_nodes = NULL;	/* sorted list of nodes within cluster */
P
Per Liden 已提交
54

55 56
static DEFINE_SPINLOCK(node_create_lock);

P
Per Liden 已提交
57 58
u32 tipc_own_tag = 0;

59 60 61 62 63 64 65 66 67 68
/**
 * tipc_node_create - create neighboring node
 *
 * Currently, this routine is called by neighbor discovery code, which holds
 * net_lock for reading only.  We must take node_create_lock to ensure a node
 * isn't created twice if two different bearers discover the node at the same
 * time.  (It would be preferable to switch to holding net_lock in write mode,
 * but this is a non-trivial change.)
 */

69
struct tipc_node *tipc_node_create(u32 addr)
P
Per Liden 已提交
70 71
{
	struct cluster *c_ptr;
72 73
	struct tipc_node *n_ptr;
	struct tipc_node **curr_node;
P
Per Liden 已提交
74

75 76 77 78 79 80 81 82 83 84 85
	spin_lock_bh(&node_create_lock);

	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
		if (addr < n_ptr->addr)
			break;
		if (addr == n_ptr->addr) {
			spin_unlock_bh(&node_create_lock);
			return n_ptr;
		}
	}

86
	n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
87
	if (!n_ptr) {
88
		spin_unlock_bh(&node_create_lock);
89 90 91 92 93 94 95 96 97
		warn("Node creation failed, no memory\n");
		return NULL;
	}

	c_ptr = tipc_cltr_find(addr);
	if (!c_ptr) {
		c_ptr = tipc_cltr_create(addr);
	}
	if (!c_ptr) {
98
		spin_unlock_bh(&node_create_lock);
99 100 101
		kfree(n_ptr);
		return NULL;
	}
102

103
	n_ptr->addr = addr;
104
		spin_lock_init(&n_ptr->lock);
105 106 107 108 109 110
	INIT_LIST_HEAD(&n_ptr->nsub);
	n_ptr->owner = c_ptr;
	tipc_cltr_attach_node(c_ptr, n_ptr);
	n_ptr->last_router = -1;

	/* Insert node into ordered list */
111
	for (curr_node = &tipc_nodes; *curr_node;
112 113 114 115 116 117 118
	     curr_node = &(*curr_node)->next) {
		if (addr < (*curr_node)->addr) {
			n_ptr->next = *curr_node;
			break;
		}
	}
	(*curr_node) = n_ptr;
119
	spin_unlock_bh(&node_create_lock);
P
Per Liden 已提交
120 121 122
	return n_ptr;
}

123
void tipc_node_delete(struct tipc_node *n_ptr)
P
Per Liden 已提交
124 125 126 127 128
{
	if (!n_ptr)
		return;

#if 0
129
	/* Not needed because links are already deleted via tipc_bearer_stop() */
P
Per Liden 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143

	u32 l_num;

	for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
		link_delete(n_ptr->links[l_num]);
	}
#endif

	dbg("node %x deleted\n", n_ptr->addr);
	kfree(n_ptr);
}


/**
144
 * tipc_node_link_up - handle addition of link
145
 *
P
Per Liden 已提交
146 147 148
 * Link becomes active (alone or shared) or standby, depending on its priority.
 */

149
void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
150 151 152
{
	struct link **active = &n_ptr->active_links[0];

153 154
	n_ptr->working_links++;

P
Per Liden 已提交
155 156
	info("Established link <%s> on network plane %c\n",
	     l_ptr->name, l_ptr->b_ptr->net_plane);
157

P
Per Liden 已提交
158 159 160 161 162 163
	if (!active[0]) {
		dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]);
		active[0] = active[1] = l_ptr;
		node_established_contact(n_ptr);
		return;
	}
164
	if (l_ptr->priority < active[0]->priority) {
165
		info("New link <%s> becomes standby\n", l_ptr->name);
P
Per Liden 已提交
166 167
		return;
	}
168
	tipc_link_send_duplicate(active[0], l_ptr);
169
	if (l_ptr->priority == active[0]->priority) {
P
Per Liden 已提交
170 171 172
		active[0] = l_ptr;
		return;
	}
173 174 175
	info("Old link <%s> becomes standby\n", active[0]->name);
	if (active[1] != active[0])
		info("Old link <%s> becomes standby\n", active[1]->name);
P
Per Liden 已提交
176 177 178 179 180 181 182
	active[0] = active[1] = l_ptr;
}

/**
 * node_select_active_links - select active link
 */

183
static void node_select_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
184 185 186 187 188
{
	struct link **active = &n_ptr->active_links[0];
	u32 i;
	u32 highest_prio = 0;

189
	active[0] = active[1] = NULL;
P
Per Liden 已提交
190 191

	for (i = 0; i < MAX_BEARERS; i++) {
192
		struct link *l_ptr = n_ptr->links[i];
P
Per Liden 已提交
193

194
		if (!l_ptr || !tipc_link_is_up(l_ptr) ||
P
Per Liden 已提交
195 196 197 198
		    (l_ptr->priority < highest_prio))
			continue;

		if (l_ptr->priority > highest_prio) {
199
			highest_prio = l_ptr->priority;
P
Per Liden 已提交
200 201 202 203 204 205 206 207
			active[0] = active[1] = l_ptr;
		} else {
			active[1] = l_ptr;
		}
	}
}

/**
208
 * tipc_node_link_down - handle loss of link
P
Per Liden 已提交
209 210
 */

211
void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
212 213 214
{
	struct link **active;

215 216
	n_ptr->working_links--;

217
	if (!tipc_link_is_active(l_ptr)) {
P
Per Liden 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231
		info("Lost standby link <%s> on network plane %c\n",
		     l_ptr->name, l_ptr->b_ptr->net_plane);
		return;
	}
	info("Lost link <%s> on network plane %c\n",
		l_ptr->name, l_ptr->b_ptr->net_plane);

	active = &n_ptr->active_links[0];
	if (active[0] == l_ptr)
		active[0] = active[1];
	if (active[1] == l_ptr)
		active[1] = active[0];
	if (active[0] == l_ptr)
		node_select_active_links(n_ptr);
232
	if (tipc_node_is_up(n_ptr))
233
		tipc_link_changeover(l_ptr);
234
	else
P
Per Liden 已提交
235 236 237
		node_lost_contact(n_ptr);
}

238
int tipc_node_has_active_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
239
{
240
	return (n_ptr &&
P
Per Liden 已提交
241 242 243
		((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
}

244
int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
P
Per Liden 已提交
245
{
246
	return (n_ptr->working_links > 1);
P
Per Liden 已提交
247 248
}

249
static int tipc_node_has_active_routes(struct tipc_node *n_ptr)
P
Per Liden 已提交
250 251 252 253
{
	return (n_ptr && (n_ptr->last_router >= 0));
}

254
int tipc_node_is_up(struct tipc_node *n_ptr)
P
Per Liden 已提交
255
{
256
	return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
P
Per Liden 已提交
257 258
}

259
struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
P
Per Liden 已提交
260
{
261
	struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr);
P
Per Liden 已提交
262 263

	if (!n_ptr)
264
		n_ptr = tipc_node_create(l_ptr->addr);
265
	if (n_ptr) {
P
Per Liden 已提交
266 267 268
		u32 bearer_id = l_ptr->b_ptr->identity;
		char addr_string[16];

269 270
		if (n_ptr->link_cnt >= 2) {
			err("Attempt to create third link to %s\n",
P
Per Liden 已提交
271
			    addr_string_fill(addr_string, n_ptr->addr));
272 273 274 275 276 277 278 279 280
			return NULL;
		}

		if (!n_ptr->links[bearer_id]) {
			n_ptr->links[bearer_id] = l_ptr;
			tipc_net.zones[tipc_zone(l_ptr->addr)]->links++;
			n_ptr->link_cnt++;
			return n_ptr;
		}
281
		err("Attempt to establish second link on <%s> to %s\n",
282
		    l_ptr->b_ptr->publ.name,
P
Per Liden 已提交
283
		    addr_string_fill(addr_string, l_ptr->addr));
284
	}
285
	return NULL;
P
Per Liden 已提交
286 287
}

288
void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
289
{
290
	n_ptr->links[l_ptr->b_ptr->identity] = NULL;
291
	tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
P
Per Liden 已提交
292 293 294 295 296 297 298
	n_ptr->link_cnt--;
}

/*
 * Routing table management - five cases to handle:
 *
 * 1: A link towards a zone/cluster external node comes up.
299 300 301
 *    => Send a multicast message updating routing tables of all
 *    system nodes within own cluster that the new destination
 *    can be reached via this node.
P
Per Liden 已提交
302 303 304
 *    (node.establishedContact()=>cluster.multicastNewRoute())
 *
 * 2: A link towards a slave node comes up.
305 306 307
 *    => Send a multicast message updating routing tables of all
 *    system nodes within own cluster that the new destination
 *    can be reached via this node.
P
Per Liden 已提交
308
 *    (node.establishedContact()=>cluster.multicastNewRoute())
309
 *    => Send a  message to the slave node about existence
P
Per Liden 已提交
310 311 312 313 314 315 316 317 318
 *    of all system nodes within cluster:
 *    (node.establishedContact()=>cluster.sendLocalRoutes())
 *
 * 3: A new cluster local system node becomes available.
 *    => Send message(s) to this particular node containing
 *    information about all cluster external and slave
 *     nodes which can be reached via this node.
 *    (node.establishedContact()==>network.sendExternalRoutes())
 *    (node.establishedContact()==>network.sendSlaveRoutes())
319
 *    => Send messages to all directly connected slave nodes
P
Per Liden 已提交
320 321
 *    containing information about the existence of the new node
 *    (node.establishedContact()=>cluster.multicastNewRoute())
322
 *
P
Per Liden 已提交
323 324
 * 4: The link towards a zone/cluster external node or slave
 *    node goes down.
325
 *    => Send a multcast message updating routing tables of all
P
Per Liden 已提交
326 327 328 329 330 331 332 333 334
 *    nodes within cluster that the new destination can not any
 *    longer be reached via this node.
 *    (node.lostAllLinks()=>cluster.bcastLostRoute())
 *
 * 5: A cluster local system node becomes unavailable.
 *    => Remove all references to this node from the local
 *    routing tables. Note: This is a completely node
 *    local operation.
 *    (node.lostAllLinks()=>network.removeAsRouter())
335
 *    => Send messages to all directly connected slave nodes
P
Per Liden 已提交
336 337 338 339 340
 *    containing information about loss of the node
 *    (node.establishedContact()=>cluster.multicastLostRoute())
 *
 */

341
static void node_established_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
342 343 344 345
{
	struct cluster *c_ptr;

	dbg("node_established_contact:-> %x\n", n_ptr->addr);
346
	if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) {
347
		tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
P
Per Liden 已提交
348 349
	}

350 351
	/* Syncronize broadcast acks */
	n_ptr->bclink.acked = tipc_bclink_get_last_sent();
P
Per Liden 已提交
352 353 354 355 356

	if (is_slave(tipc_own_addr))
		return;
	if (!in_own_cluster(n_ptr->addr)) {
		/* Usage case 1 (see above) */
357
		c_ptr = tipc_cltr_find(tipc_own_addr);
P
Per Liden 已提交
358
		if (!c_ptr)
359
			c_ptr = tipc_cltr_create(tipc_own_addr);
360 361
		if (c_ptr)
			tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1,
362
						  tipc_max_nodes);
P
Per Liden 已提交
363
		return;
364
	}
P
Per Liden 已提交
365 366 367 368

	c_ptr = n_ptr->owner;
	if (is_slave(n_ptr->addr)) {
		/* Usage case 2 (see above) */
369 370
		tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes);
		tipc_cltr_send_local_routes(c_ptr, n_ptr->addr);
P
Per Liden 已提交
371 372 373 374
		return;
	}

	if (n_ptr->bclink.supported) {
375
		tipc_nmap_add(&tipc_cltr_bcast_nodes, n_ptr->addr);
P
Per Liden 已提交
376 377 378 379 380
		if (n_ptr->addr < tipc_own_addr)
			tipc_own_tag++;
	}

	/* Case 3 (see above) */
381 382 383 384
	tipc_net_send_external_routes(n_ptr->addr);
	tipc_cltr_send_slave_routes(c_ptr, n_ptr->addr);
	tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE,
				  tipc_highest_allowed_slave);
P
Per Liden 已提交
385 386
}

387
static void node_lost_contact(struct tipc_node *n_ptr)
P
Per Liden 已提交
388 389
{
	struct cluster *c_ptr;
390
	struct tipc_node_subscr *ns, *tns;
P
Per Liden 已提交
391 392 393
	char addr_string[16];
	u32 i;

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	/* Clean up broadcast reception remains */
	n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
	while (n_ptr->bclink.deferred_head) {
		struct sk_buff* buf = n_ptr->bclink.deferred_head;
		n_ptr->bclink.deferred_head = buf->next;
		buf_discard(buf);
	}
	if (n_ptr->bclink.defragm) {
		buf_discard(n_ptr->bclink.defragm);
		n_ptr->bclink.defragm = NULL;
	}
	if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) {
		tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
	}

	/* Update routing tables */
P
Per Liden 已提交
410
	if (is_slave(tipc_own_addr)) {
411
		tipc_net_remove_as_router(n_ptr->addr);
P
Per Liden 已提交
412
	} else {
413
		if (!in_own_cluster(n_ptr->addr)) {
P
Per Liden 已提交
414
			/* Case 4 (see above) */
415 416 417
			c_ptr = tipc_cltr_find(tipc_own_addr);
			tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1,
						   tipc_max_nodes);
P
Per Liden 已提交
418 419
		} else {
			/* Case 5 (see above) */
420
			c_ptr = tipc_cltr_find(n_ptr->addr);
P
Per Liden 已提交
421
			if (is_slave(n_ptr->addr)) {
422 423
				tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1,
							   tipc_max_nodes);
P
Per Liden 已提交
424 425
			} else {
				if (n_ptr->bclink.supported) {
426
					tipc_nmap_remove(&tipc_cltr_bcast_nodes,
427
							 n_ptr->addr);
P
Per Liden 已提交
428 429 430
					if (n_ptr->addr < tipc_own_addr)
						tipc_own_tag--;
				}
431 432 433 434
				tipc_net_remove_as_router(n_ptr->addr);
				tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr,
							   LOWEST_SLAVE,
							   tipc_highest_allowed_slave);
P
Per Liden 已提交
435 436 437
			}
		}
	}
438
	if (tipc_node_has_active_routes(n_ptr))
P
Per Liden 已提交
439 440
		return;

441
	info("Lost contact with %s\n",
P
Per Liden 已提交
442 443 444 445 446
	     addr_string_fill(addr_string, n_ptr->addr));

	/* Abort link changeover */
	for (i = 0; i < MAX_BEARERS; i++) {
		struct link *l_ptr = n_ptr->links[i];
447
		if (!l_ptr)
P
Per Liden 已提交
448 449 450
			continue;
		l_ptr->reset_checkpoint = l_ptr->next_in_no;
		l_ptr->exp_msg_count = 0;
451
		tipc_link_reset_fragments(l_ptr);
P
Per Liden 已提交
452 453 454 455
	}

	/* Notify subscribers */
	list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
456
		ns->node = NULL;
P
Per Liden 已提交
457
		list_del_init(&ns->nodesub_list);
458 459
		tipc_k_signal((Handler)ns->handle_node_down,
			      (unsigned long)ns->usr_handle);
P
Per Liden 已提交
460 461 462 463
	}
}

/**
464
 * tipc_node_select_next_hop - find the next-hop node for a message
465
 *
P
Per Liden 已提交
466 467 468
 * Called by when cluster local lookup has failed.
 */

469
struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector)
P
Per Liden 已提交
470
{
471
	struct tipc_node *n_ptr;
P
Per Liden 已提交
472 473
	u32 router_addr;

474 475
	if (!tipc_addr_domain_valid(addr))
		return NULL;
P
Per Liden 已提交
476 477

	/* Look for direct link to destination processsor */
478 479
	n_ptr = tipc_node_find(addr);
	if (n_ptr && tipc_node_has_active_links(n_ptr))
480
		return n_ptr;
P
Per Liden 已提交
481 482 483

	/* Cluster local system nodes *must* have direct links */
	if (!is_slave(addr) && in_own_cluster(addr))
484
		return NULL;
P
Per Liden 已提交
485 486

	/* Look for cluster local router with direct link to node */
487
	router_addr = tipc_node_select_router(n_ptr, selector);
488 489
	if (router_addr)
		return tipc_node_select(router_addr, selector);
P
Per Liden 已提交
490

491
	/* Slave nodes can only be accessed within own cluster via a
P
Per Liden 已提交
492 493
	   known router with direct link -- if no router was found,give up */
	if (is_slave(addr))
494
		return NULL;
P
Per Liden 已提交
495 496 497

	/* Inter zone/cluster -- find any direct link to remote cluster */
	addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
498 499
	n_ptr = tipc_net_select_remote_node(addr, selector);
	if (n_ptr && tipc_node_has_active_links(n_ptr))
500
		return n_ptr;
P
Per Liden 已提交
501 502

	/* Last resort -- look for any router to anywhere in remote zone */
503
	router_addr =  tipc_net_select_router(addr, selector);
504 505
	if (router_addr)
		return tipc_node_select(router_addr, selector);
P
Per Liden 已提交
506

507
	return NULL;
P
Per Liden 已提交
508 509 510
}

/**
511
 * tipc_node_select_router - select router to reach specified node
512 513
 *
 * Uses a deterministic and fair algorithm for selecting router node.
P
Per Liden 已提交
514 515
 */

516
u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref)
P
Per Liden 已提交
517 518 519 520 521 522
{
	u32 ulim;
	u32 mask;
	u32 start;
	u32 r;

523 524
	if (!n_ptr)
		return 0;
P
Per Liden 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

	if (n_ptr->last_router < 0)
		return 0;
	ulim = ((n_ptr->last_router + 1) * 32) - 1;

	/* Start entry must be random */
	mask = tipc_max_nodes;
	while (mask > ulim)
		mask >>= 1;
	start = ref & mask;
	r = start;

	/* Lookup upwards with wrap-around */
	do {
		if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
			break;
	} while (++r <= ulim);
	if (r > ulim) {
		r = 1;
		do {
			if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
				break;
		} while (++r < start);
		assert(r != start);
	}
	assert(r && (r <= ulim));
	return tipc_addr(own_zone(), own_cluster(), r);
}

554
void tipc_node_add_router(struct tipc_node *n_ptr, u32 router)
P
Per Liden 已提交
555 556 557
{
	u32 r_num = tipc_node(router);

558
	n_ptr->routers[r_num / 32] =
P
Per Liden 已提交
559 560
		((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
	n_ptr->last_router = tipc_max_nodes / 32;
561
	while ((--n_ptr->last_router >= 0) &&
P
Per Liden 已提交
562 563 564
	       !n_ptr->routers[n_ptr->last_router]);
}

565
void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router)
P
Per Liden 已提交
566 567 568 569 570 571 572 573 574
{
	u32 r_num = tipc_node(router);

	if (n_ptr->last_router < 0)
		return;		/* No routes */

	n_ptr->routers[r_num / 32] =
		((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32]));
	n_ptr->last_router = tipc_max_nodes / 32;
575
	while ((--n_ptr->last_router >= 0) &&
P
Per Liden 已提交
576 577
	       !n_ptr->routers[n_ptr->last_router]);

578
	if (!tipc_node_is_up(n_ptr))
P
Per Liden 已提交
579 580 581 582
		node_lost_contact(n_ptr);
}

#if 0
583
void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str)
P
Per Liden 已提交
584 585 586 587 588
{
	u32 i;

	tipc_printf(buf, "\n\n%s", str);
	for (i = 0; i < MAX_BEARERS; i++) {
589
		if (!n_ptr->links[i])
P
Per Liden 已提交
590 591 592 593 594 595 596 597 598 599
			continue;
		tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
	}
	tipc_printf(buf, "Active links: [%x,%x]\n",
		    n_ptr->active_links[0], n_ptr->active_links[1]);
}
#endif

u32 tipc_available_nodes(const u32 domain)
{
600
	struct tipc_node *n_ptr;
P
Per Liden 已提交
601 602
	u32 cnt = 0;

603
	read_lock_bh(&tipc_net_lock);
604
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
605 606
		if (!in_scope(domain, n_ptr->addr))
			continue;
607
		if (tipc_node_is_up(n_ptr))
P
Per Liden 已提交
608 609
			cnt++;
	}
610
	read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
611 612 613
	return cnt;
}

614
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
615 616 617
{
	u32 domain;
	struct sk_buff *buf;
618
	struct tipc_node *n_ptr;
619
	struct tipc_node_info node_info;
620
	u32 payload_size;
P
Per Liden 已提交
621 622

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
623
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
624

A
Al Viro 已提交
625
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
626 627 628
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
629

630 631 632
	read_lock_bh(&tipc_net_lock);
	if (!tipc_nodes) {
		read_unlock_bh(&tipc_net_lock);
633
		return tipc_cfg_reply_none();
634
	}
P
Per Liden 已提交
635

636
	/* For now, get space for all other nodes
P
Per Liden 已提交
637 638
	   (will need to modify this when slave nodes are supported */

639
	payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1);
640 641
	if (payload_size > 32768u) {
		read_unlock_bh(&tipc_net_lock);
642 643
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many nodes)");
644
	}
645
	buf = tipc_cfg_reply_alloc(payload_size);
646 647
	if (!buf) {
		read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
648
		return NULL;
649
	}
P
Per Liden 已提交
650 651 652

	/* Add TLVs for all nodes in scope */

653
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
654 655
		if (!in_scope(domain, n_ptr->addr))
			continue;
656 657 658
		node_info.addr = htonl(n_ptr->addr);
		node_info.up = htonl(tipc_node_is_up(n_ptr));
		tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
659
				    &node_info, sizeof(node_info));
P
Per Liden 已提交
660 661
	}

662
	read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
663 664 665
	return buf;
}

666
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
667 668 669
{
	u32 domain;
	struct sk_buff *buf;
670
	struct tipc_node *n_ptr;
671
	struct tipc_link_info link_info;
672
	u32 payload_size;
P
Per Liden 已提交
673 674

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
675
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
676

A
Al Viro 已提交
677
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
678 679 680
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
681

682 683 684
	if (tipc_mode != TIPC_NET_MODE)
		return tipc_cfg_reply_none();

685 686
	read_lock_bh(&tipc_net_lock);

687 688 689 690
	/* Get space for all unicast links + multicast link */

	payload_size = TLV_SPACE(sizeof(link_info)) *
		(tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1);
691 692
	if (payload_size > 32768u) {
		read_unlock_bh(&tipc_net_lock);
693 694
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many links)");
695
	}
696
	buf = tipc_cfg_reply_alloc(payload_size);
697 698
	if (!buf) {
		read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
699
		return NULL;
700
	}
P
Per Liden 已提交
701 702 703

	/* Add TLV for broadcast link */

704 705
	link_info.dest = htonl(tipc_own_addr & 0xfffff00);
	link_info.up = htonl(1);
706
	strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
707
	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
P
Per Liden 已提交
708 709 710

	/* Add TLVs for any other links in scope */

711
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
712
		u32 i;
P
Per Liden 已提交
713 714 715

		if (!in_scope(domain, n_ptr->addr))
			continue;
716
		tipc_node_lock(n_ptr);
717 718 719 720 721 722 723
		for (i = 0; i < MAX_BEARERS; i++) {
			if (!n_ptr->links[i])
				continue;
			link_info.dest = htonl(n_ptr->addr);
			link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
			strcpy(link_info.str, n_ptr->links[i]->name);
			tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
724
					    &link_info, sizeof(link_info));
725
		}
726
		tipc_node_unlock(n_ptr);
P
Per Liden 已提交
727 728
	}

729
	read_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
730 731
	return buf;
}