node.c 19.5 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 63
{
	struct cluster *c_ptr;
	struct node *n_ptr;
        struct node **curr_node;

	n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	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;
	}
		
	memset(n_ptr, 0, sizeof(*n_ptr));
	n_ptr->addr = addr;
I
Ingo Molnar 已提交
80
                spin_lock_init(&n_ptr->lock);
81 82 83 84 85 86 87 88 89 90 91 92 93 94
	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 已提交
95 96 97
	return n_ptr;
}

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

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

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


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

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

128 129
	n_ptr->working_links++;

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

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

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

169
		if (!l_ptr || !tipc_link_is_up(l_ptr) ||
P
Per Liden 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182
		    (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;
		}
	}
}

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

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

190 191
	n_ptr->working_links--;

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

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

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

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

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

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

	if (!n_ptr)
239
		n_ptr = tipc_node_create(l_ptr->addr);
P
Per Liden 已提交
240 241 242 243 244 245 246 247 248
        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));
249
                        return NULL;
P
Per Liden 已提交
250 251 252 253
                }

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

265
void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr)
P
Per Liden 已提交
266
{
267
	n_ptr->links[l_ptr->b_ptr->identity] = NULL;
268
	tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
P
Per Liden 已提交
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 322
	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);
323
	if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) { 
324
		tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
P
Per Liden 已提交
325 326 327
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	/* 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))
471
		return NULL;
P
Per Liden 已提交
472 473 474

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

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

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

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

493
u32 tipc_node_select_router(struct node *n_ptr, u32 ref)
P
Per Liden 已提交
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 530
{
	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);
}

531
void tipc_node_add_router(struct node *n_ptr, u32 router)
P
Per Liden 已提交
532 533 534 535 536 537 538 539 540 541
{
	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]);
}

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

555
	if (!tipc_node_is_up(n_ptr))
P
Per Liden 已提交
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
		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;

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

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

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

	domain = *(u32 *)TLV_DATA(req_tlv_area);
	domain = ntohl(domain);
602 603 604
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
605

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

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

612 613 614 615 616
	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 已提交
617 618 619 620 621
	if (!buf)
		return NULL;

	/* Add TLVs for all nodes in scope */

622
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
623 624 625
		if (!in_scope(domain, n_ptr->addr))
			continue;
                node_info.addr = htonl(n_ptr->addr);
626 627 628
                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 已提交
629 630 631 632 633
	}

	return buf;
}

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

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
643
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
P
Per Liden 已提交
644 645 646

	domain = *(u32 *)TLV_DATA(req_tlv_area);
	domain = ntohl(domain);
647 648 649
	if (!tipc_addr_domain_valid(domain))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network address)");
P
Per Liden 已提交
650

651 652
        if (!tipc_nodes)
                return tipc_cfg_reply_none();
653 654 655 656 657 658 659 660 661
	
	/* 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 已提交
662 663 664 665 666 667 668 669
	if (!buf)
		return NULL;

	/* Add TLV for broadcast link */

        link_info.dest = tipc_own_addr & 0xfffff00;
	link_info.dest = htonl(link_info.dest);
        link_info.up = htonl(1);
670 671
        sprintf(link_info.str, tipc_bclink_name);
	tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
P
Per Liden 已提交
672 673 674

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

675
	for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
P
Per Liden 已提交
676 677 678 679 680 681 682 683
                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);
684
                        link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
P
Per Liden 已提交
685
                        strcpy(link_info.str, n_ptr->links[i]->name);
686 687
			tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, 
					    &link_info, sizeof(link_info));
P
Per Liden 已提交
688 689 690 691 692
                }
	}

	return buf;
}