node.c 19.4 KB
Newer Older
P
Per Liden 已提交
1 2 3
/*
 * net/tipc/node.c: TIPC node management routines
 * 
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 49 50 51 52
 * 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"

void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
static void node_lost_contact(struct node *n_ptr);
static void node_established_contact(struct node *n_ptr);

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

u32 tipc_own_tag = 0;

57
struct node *tipc_node_create(u32 addr)
P
Per Liden 已提交
58 59 60 61 62
{
	struct cluster *c_ptr;
	struct node *n_ptr;
        struct node **curr_node;

63
	n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	if (!n_ptr) {
		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) {
		kfree(n_ptr);
		return NULL;
	}
		
	n_ptr->addr = addr;
I
Ingo Molnar 已提交
79
                spin_lock_init(&n_ptr->lock);
80 81 82 83 84 85 86 87 88 89 90 91 92 93
	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 */
	for (curr_node = &tipc_nodes; *curr_node; 
	     curr_node = &(*curr_node)->next) {
		if (addr < (*curr_node)->addr) {
			n_ptr->next = *curr_node;
			break;
		}
	}
	(*curr_node) = n_ptr;
P
Per Liden 已提交
94 95 96
	return n_ptr;
}

97
void tipc_node_delete(struct node *n_ptr)
P
Per Liden 已提交
98 99 100 101 102
{
	if (!n_ptr)
		return;

#if 0
103
	/* Not needed because links are already deleted via tipc_bearer_stop() */
P
Per Liden 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117

	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);
}


/**
118
 * tipc_node_link_up - handle addition of link
P
Per Liden 已提交
119 120 121 122
 * 
 * Link becomes active (alone or shared) or standby, depending on its priority.
 */

123
void tipc_node_link_up(struct node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
124 125 126
{
	struct link **active = &n_ptr->active_links[0];

127 128
	n_ptr->working_links++;

P
Per Liden 已提交
129 130 131 132 133 134 135 136 137 138
	info("Established link <%s> on network plane %c\n",
	     l_ptr->name, l_ptr->b_ptr->net_plane);
	
	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;
	}
	if (l_ptr->priority < active[0]->priority) { 
139
		info("New link <%s> becomes standby\n", l_ptr->name);
P
Per Liden 已提交
140 141
		return;
	}
142
	tipc_link_send_duplicate(active[0], l_ptr);
P
Per Liden 已提交
143 144 145 146
	if (l_ptr->priority == active[0]->priority) { 
		active[0] = l_ptr;
		return;
	}
147 148 149
	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 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162
	active[0] = active[1] = l_ptr;
}

/**
 * node_select_active_links - select active link
 */

static void node_select_active_links(struct node *n_ptr)
{
	struct link **active = &n_ptr->active_links[0];
	u32 i;
	u32 highest_prio = 0;

163
        active[0] = active[1] = NULL;
P
Per Liden 已提交
164 165 166 167

	for (i = 0; i < MAX_BEARERS; i++) {
                struct link *l_ptr = n_ptr->links[i];

168
		if (!l_ptr || !tipc_link_is_up(l_ptr) ||
P
Per Liden 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181
		    (l_ptr->priority < highest_prio))
			continue;

		if (l_ptr->priority > highest_prio) {
                        highest_prio = l_ptr->priority;
			active[0] = active[1] = l_ptr;
		} else {
			active[1] = l_ptr;
		}
	}
}

/**
182
 * tipc_node_link_down - handle loss of link
P
Per Liden 已提交
183 184
 */

185
void tipc_node_link_down(struct node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
186 187 188
{
	struct link **active;

189 190
	n_ptr->working_links--;

191
	if (!tipc_link_is_active(l_ptr)) {
P
Per Liden 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205
		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);
206 207
	if (tipc_node_is_up(n_ptr)) 
		tipc_link_changeover(l_ptr);
P
Per Liden 已提交
208 209 210 211
	else 
		node_lost_contact(n_ptr);
}

212
int tipc_node_has_active_links(struct node *n_ptr)
P
Per Liden 已提交
213 214 215 216 217
{
	return (n_ptr && 
		((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
}

218
int tipc_node_has_redundant_links(struct node *n_ptr)
P
Per Liden 已提交
219
{
220
	return (n_ptr->working_links > 1);
P
Per Liden 已提交
221 222
}

A
Adrian Bunk 已提交
223
static int tipc_node_has_active_routes(struct node *n_ptr)
P
Per Liden 已提交
224 225 226 227
{
	return (n_ptr && (n_ptr->last_router >= 0));
}

228
int tipc_node_is_up(struct node *n_ptr)
P
Per Liden 已提交
229
{
230
	return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
P
Per Liden 已提交
231 232
}

233
struct node *tipc_node_attach_link(struct link *l_ptr)
P
Per Liden 已提交
234
{
235
	struct node *n_ptr = tipc_node_find(l_ptr->addr);
P
Per Liden 已提交
236 237

	if (!n_ptr)
238
		n_ptr = tipc_node_create(l_ptr->addr);
P
Per Liden 已提交
239 240 241 242 243 244 245 246 247
        if (n_ptr) {
		u32 bearer_id = l_ptr->b_ptr->identity;
		char addr_string[16];

                if (n_ptr->link_cnt >= 2) {
			char addr_string[16];

                        err("Attempt to create third link to %s\n",
			    addr_string_fill(addr_string, n_ptr->addr));
248
                        return NULL;
P
Per Liden 已提交
249 250 251 252
                }

                if (!n_ptr->links[bearer_id]) {
                        n_ptr->links[bearer_id] = l_ptr;
253
                        tipc_net.zones[tipc_zone(l_ptr->addr)]->links++;
P
Per Liden 已提交
254 255 256
                        n_ptr->link_cnt++;
                        return n_ptr;
                }
257
                err("Attempt to establish second link on <%s> to %s \n",
P
Per Liden 已提交
258 259 260
                    l_ptr->b_ptr->publ.name, 
		    addr_string_fill(addr_string, l_ptr->addr));
        }
261
	return NULL;
P
Per Liden 已提交
262 263
}

264
void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
265
{
266
	n_ptr->links[l_ptr->b_ptr->identity] = NULL;
267
	tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
P
Per Liden 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	n_ptr->link_cnt--;
}

/*
 * Routing table management - five cases to handle:
 *
 * 1: A link towards a zone/cluster external node comes up.
 *    => Send a multicast message updating routing tables of all 
 *    system nodes within own cluster that the new destination 
 *    can be reached via this node. 
 *    (node.establishedContact()=>cluster.multicastNewRoute())
 *
 * 2: A link towards a slave node comes up.
 *    => Send a multicast message updating routing tables of all 
 *    system nodes within own cluster that the new destination 
 *    can be reached via this node. 
 *    (node.establishedContact()=>cluster.multicastNewRoute())
 *    => Send a  message to the slave node about existence 
 *    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())
 *    => Send messages to all directly connected slave nodes 
 *    containing information about the existence of the new node
 *    (node.establishedContact()=>cluster.multicastNewRoute())
 *    
 * 4: The link towards a zone/cluster external node or slave
 *    node goes down.
 *    => Send a multcast message updating routing tables of all 
 *    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())
 *    => Send messages to all directly connected slave nodes 
 *    containing information about loss of the node
 *    (node.establishedContact()=>cluster.multicastLostRoute())
 *
 */

static void node_established_contact(struct node *n_ptr)
{
	struct cluster *c_ptr;

	dbg("node_established_contact:-> %x\n", n_ptr->addr);
322
	if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) { 
323
		tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
P
Per Liden 已提交
324 325 326
	}

        /* Syncronize broadcast acks */
327
        n_ptr->bclink.acked = tipc_bclink_get_last_sent();
P
Per Liden 已提交
328 329 330 331 332

	if (is_slave(tipc_own_addr))
		return;
	if (!in_own_cluster(n_ptr->addr)) {
		/* Usage case 1 (see above) */
333
		c_ptr = tipc_cltr_find(tipc_own_addr);
P
Per Liden 已提交
334
		if (!c_ptr)
335
			c_ptr = tipc_cltr_create(tipc_own_addr);
P
Per Liden 已提交
336
                if (c_ptr)
337 338
                        tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1, 
						  tipc_max_nodes);
P
Per Liden 已提交
339 340 341 342 343 344
		return;
	} 

	c_ptr = n_ptr->owner;
	if (is_slave(n_ptr->addr)) {
		/* Usage case 2 (see above) */
345 346
		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 已提交
347 348 349 350
		return;
	}

	if (n_ptr->bclink.supported) {
351
		tipc_nmap_add(&tipc_cltr_bcast_nodes, n_ptr->addr);
P
Per Liden 已提交
352 353 354 355 356
		if (n_ptr->addr < tipc_own_addr)
			tipc_own_tag++;
	}

	/* Case 3 (see above) */
357 358 359 360
	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 已提交
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
}

static void node_lost_contact(struct node *n_ptr)
{
	struct cluster *c_ptr;
	struct node_subscr *ns, *tns;
	char addr_string[16];
	u32 i;

        /* 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) { 
382
                tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
P
Per Liden 已提交
383 384 385 386
        }

        /* Update routing tables */
	if (is_slave(tipc_own_addr)) {
387
		tipc_net_remove_as_router(n_ptr->addr);
P
Per Liden 已提交
388 389 390
	} else {
		if (!in_own_cluster(n_ptr->addr)) { 
			/* Case 4 (see above) */
391 392 393
			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 已提交
394 395
		} else {
			/* Case 5 (see above) */
396
			c_ptr = tipc_cltr_find(n_ptr->addr);
P
Per Liden 已提交
397
			if (is_slave(n_ptr->addr)) {
398 399
				tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1,
							   tipc_max_nodes);
P
Per Liden 已提交
400 401
			} else {
				if (n_ptr->bclink.supported) {
402 403
					tipc_nmap_remove(&tipc_cltr_bcast_nodes, 
							 n_ptr->addr);
P
Per Liden 已提交
404 405 406
					if (n_ptr->addr < tipc_own_addr)
						tipc_own_tag--;
				}
407 408 409 410
				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 已提交
411 412 413
			}
		}
	}
414
	if (tipc_node_has_active_routes(n_ptr))
P
Per Liden 已提交
415 416 417 418 419 420 421 422 423 424 425 426
		return;

	info("Lost contact with %s\n", 
	     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];
		if (!l_ptr) 
			continue;
		l_ptr->reset_checkpoint = l_ptr->next_in_no;
		l_ptr->exp_msg_count = 0;
427
		tipc_link_reset_fragments(l_ptr);
P
Per Liden 已提交
428 429 430 431
	}

	/* Notify subscribers */
	list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
432
                ns->node = NULL;
P
Per Liden 已提交
433
		list_del_init(&ns->nodesub_list);
434 435
		tipc_k_signal((Handler)ns->handle_node_down,
			      (unsigned long)ns->usr_handle);
P
Per Liden 已提交
436 437 438 439
	}
}

/**
440
 * tipc_node_select_next_hop - find the next-hop node for a message
P
Per Liden 已提交
441 442 443 444
 * 
 * Called by when cluster local lookup has failed.
 */

445
struct node *tipc_node_select_next_hop(u32 addr, u32 selector)
P
Per Liden 已提交
446 447 448 449
{
	struct node *n_ptr;
	u32 router_addr;

450
        if (!tipc_addr_domain_valid(addr))
451
                return NULL;
P
Per Liden 已提交
452 453

	/* Look for direct link to destination processsor */
454 455
	n_ptr = tipc_node_find(addr);
	if (n_ptr && tipc_node_has_active_links(n_ptr))
P
Per Liden 已提交
456 457 458 459
                return n_ptr;

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

	/* Look for cluster local router with direct link to node */
463
	router_addr = tipc_node_select_router(n_ptr, selector);
P
Per Liden 已提交
464
	if (router_addr) 
465
                return tipc_node_select(router_addr, selector);
P
Per Liden 已提交
466 467 468 469

	/* Slave nodes can only be accessed within own cluster via a 
	   known router with direct link -- if no router was found,give up */
	if (is_slave(addr))
470
		return NULL;
P
Per Liden 已提交
471 472 473

	/* Inter zone/cluster -- find any direct link to remote cluster */
	addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
474 475
	n_ptr = tipc_net_select_remote_node(addr, selector);
	if (n_ptr && tipc_node_has_active_links(n_ptr))
P
Per Liden 已提交
476 477 478
                return n_ptr;

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

483
        return NULL;
P
Per Liden 已提交
484 485 486
}

/**
487
 * tipc_node_select_router - select router to reach specified node
P
Per Liden 已提交
488 489 490 491
 * 
 * Uses a deterministic and fair algorithm for selecting router node. 
 */

492
u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
P
Per Liden 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
{
	u32 ulim;
	u32 mask;
	u32 start;
	u32 r;

        if (!n_ptr)
                return 0;

	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);
}

530
void tipc_node_add_router(struct node *n_ptr, u32 router)
P
Per Liden 已提交
531 532 533 534 535 536 537 538 539 540
{
	u32 r_num = tipc_node(router);

	n_ptr->routers[r_num / 32] = 
		((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
	n_ptr->last_router = tipc_max_nodes / 32;
	while ((--n_ptr->last_router >= 0) && 
	       !n_ptr->routers[n_ptr->last_router]);
}

541
void tipc_node_remove_router(struct node *n_ptr, u32 router)
P
Per Liden 已提交
542 543 544 545 546 547 548 549 550 551 552 553
{
	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;
	while ((--n_ptr->last_router >= 0) && 
	       !n_ptr->routers[n_ptr->last_router]);

554
	if (!tipc_node_is_up(n_ptr))
P
Per Liden 已提交
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
		node_lost_contact(n_ptr);
}

#if 0
void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
{
	u32 i;

	tipc_printf(buf, "\n\n%s", str);
	for (i = 0; i < MAX_BEARERS; i++) {
		if (!n_ptr->links[i]) 
			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)
{
	struct node *n_ptr;
	u32 cnt = 0;

579
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
580 581
		if (!in_scope(domain, n_ptr->addr))
			continue;
582
		if (tipc_node_is_up(n_ptr))
P
Per Liden 已提交
583 584 585 586 587
			cnt++;
	}
	return cnt;
}

588
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
589 590 591 592 593
{
	u32 domain;
	struct sk_buff *buf;
	struct node *n_ptr;
        struct tipc_node_info node_info;
594
	u32 payload_size;
P
Per Liden 已提交
595 596

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

A
Al Viro 已提交
599
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
600 601 602
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
603

604 605
        if (!tipc_nodes)
                return tipc_cfg_reply_none();
P
Per Liden 已提交
606 607 608 609

	/* For now, get space for all other nodes 
	   (will need to modify this when slave nodes are supported */

610 611 612 613 614
	payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1);
	if (payload_size > 32768u)
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many nodes)");
	buf = tipc_cfg_reply_alloc(payload_size);
P
Per Liden 已提交
615 616 617 618 619
	if (!buf)
		return NULL;

	/* Add TLVs for all nodes in scope */

620
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
621 622 623
		if (!in_scope(domain, n_ptr->addr))
			continue;
                node_info.addr = htonl(n_ptr->addr);
624 625 626
                node_info.up = htonl(tipc_node_is_up(n_ptr));
		tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO, 
				    &node_info, sizeof(node_info));
P
Per Liden 已提交
627 628 629 630 631
	}

	return buf;
}

632
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
P
Per Liden 已提交
633 634 635 636 637
{
	u32 domain;
	struct sk_buff *buf;
	struct node *n_ptr;
        struct tipc_link_info link_info;
638
	u32 payload_size;
P
Per Liden 已提交
639 640

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

A
Al Viro 已提交
643
	domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
644 645 646
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
647

648
        if (tipc_mode != TIPC_NET_MODE)
649
                return tipc_cfg_reply_none();
650 651 652 653 654 655 656 657 658
	
	/* 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);
	if (payload_size > 32768u)
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (too many links)");
	buf = tipc_cfg_reply_alloc(payload_size);
P
Per Liden 已提交
659 660 661 662 663
	if (!buf)
		return NULL;

	/* Add TLV for broadcast link */

A
Al Viro 已提交
664
        link_info.dest = htonl(tipc_own_addr & 0xfffff00);
P
Per Liden 已提交
665
        link_info.up = htonl(1);
666 667
        sprintf(link_info.str, tipc_bclink_name);
	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
P
Per Liden 已提交
668 669 670

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

671
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
672 673 674 675 676 677 678 679
                u32 i;

		if (!in_scope(domain, n_ptr->addr))
			continue;
                for (i = 0; i < MAX_BEARERS; i++) {
                        if (!n_ptr->links[i]) 
                                continue;
                        link_info.dest = htonl(n_ptr->addr);
680
                        link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
P
Per Liden 已提交
681
                        strcpy(link_info.str, n_ptr->links[i]->name);
682 683
			tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, 
					    &link_info, sizeof(link_info));
P
Per Liden 已提交
684 685 686 687 688
                }
	}

	return buf;
}