net.c 9.9 KB
Newer Older
P
Per Liden 已提交
1 2 3
/*
 * net/tipc/net.c: TIPC network routing code
 * 
P
Per Liden 已提交
4
 * Copyright (c) 1995-2006, Ericsson AB
P
Per Liden 已提交
5 6 7 8 9 10
 * Copyright (c) 2005, Wind River Systems
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
P
Per Liden 已提交
11 12 13 14 15 16 17 18 19 20 21 22
 * 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.
 *
 * 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.
P
Per Liden 已提交
23 24 25 26 27 28 29 30 31 32 33 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
 *
 * 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
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "bearer.h"
#include "net.h"
#include "zone.h"
#include "addr.h"
#include "name_table.h"
#include "name_distr.h"
#include "subscr.h"
#include "link.h"
#include "msg.h"
#include "port.h"
#include "bcast.h"
#include "discover.h"
#include "config.h"

/* 
 * The TIPC locking policy is designed to ensure a very fine locking
 * granularity, permitting complete parallel access to individual
 * port and node/link instances. The code consists of three major 
 * locking domains, each protected with their own disjunct set of locks.
 *
 * 1: The routing hierarchy.
 *    Comprises the structures 'zone', 'cluster', 'node', 'link' 
 *    and 'bearer'. The whole hierarchy is protected by a big 
61
 *    read/write lock, tipc_net_lock, to enssure that nothing is added 
P
Per Liden 已提交
62 63 64 65
 *    or removed while code is accessing any of these structures. 
 *    This layer must not be called from the two others while they 
 *    hold any of their own locks.
 *    Neither must it itself do any upcalls to the other two before
66
 *    it has released tipc_net_lock and other protective locks.
P
Per Liden 已提交
67
 *
68
 *   Within the tipc_net_lock domain there are two sub-domains;'node' and 
P
Per Liden 已提交
69 70
 *   'bearer', where local write operations are permitted,
 *   provided that those are protected by individual spin_locks
71
 *   per instance. Code holding tipc_net_lock(read) and a node spin_lock 
P
Per Liden 已提交
72 73 74 75 76 77
 *   is permitted to poke around in both the node itself and its
 *   subordinate links. I.e, it can update link counters and queues, 
 *   change link state, send protocol messages, and alter the 
 *   "active_links" array in the node; but it can _not_ remove a link 
 *   or a node from the overall structure.
 *   Correspondingly, individual bearers may change status within a 
78 79
 *   tipc_net_lock(read), protected by an individual spin_lock ber bearer 
 *   instance, but it needs tipc_net_lock(write) to remove/add any bearers.
P
Per Liden 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
 *     
 *
 *  2: The transport level of the protocol. 
 *     This consists of the structures port, (and its user level 
 *     representations, such as user_port and tipc_sock), reference and 
 *     tipc_user (port.c, reg.c, socket.c). 
 *
 *     This layer has four different locks:
 *     - The tipc_port spin_lock. This is protecting each port instance
 *       from parallel data access and removal. Since we can not place 
 *       this lock in the port itself, it has been placed in the 
 *       corresponding reference table entry, which has the same life
 *       cycle as the module. This entry is difficult to access from 
 *       outside the TIPC core, however, so a pointer to the lock has 
 *       been added in the port instance, -to be used for unlocking 
 *       only.
 *     - A read/write lock to protect the reference table itself (teg.c). 
 *       (Nobody is using read-only access to this, so it can just as 
 *       well be changed to a spin_lock)
 *     - A spin lock to protect the registry of kernel/driver users (reg.c)
100
 *     - A global spin_lock (tipc_port_lock), which only task is to ensure 
P
Per Liden 已提交
101 102 103 104 105 106
 *       consistency where more than one port is involved in an operation,
 *       i.e., whe a port is part of a linked list of ports.
 *       There are two such lists; 'port_list', which is used for management,
 *       and 'wait_list', which is used to queue ports during congestion.
 *     
 *  3: The name table (name_table.c, name_distr.c, subscription.c)
107
 *     - There is one big read/write-lock (tipc_nametbl_lock) protecting the 
P
Per Liden 已提交
108 109 110
 *       overall name table structure. Nothing must be added/removed to 
 *       this structure without holding write access to it.
 *     - There is one local spin_lock per sub_sequence, which can be seen
111
 *       as a sub-domain to the tipc_nametbl_lock domain. It is used only
P
Per Liden 已提交
112 113
 *       for translation operations, and is needed because a translation
 *       steps the root of the 'publication' linked list between each lookup.
114
 *       This is always used within the scope of a tipc_nametbl_lock(read).
P
Per Liden 已提交
115 116 117
 *     - A local spin_lock protecting the queue of subscriber events.
*/

118
rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED;
119
struct network tipc_net = { NULL };
P
Per Liden 已提交
120

121
struct node *tipc_net_select_remote_node(u32 addr, u32 ref) 
P
Per Liden 已提交
122
{
123
	return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref);
P
Per Liden 已提交
124 125
}

126
u32 tipc_net_select_router(u32 addr, u32 ref)
P
Per Liden 已提交
127
{
128
	return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref);
P
Per Liden 已提交
129 130
}

A
Adrian Bunk 已提交
131
#if 0
132
u32 tipc_net_next_node(u32 a)
P
Per Liden 已提交
133
{
134 135
	if (tipc_net.zones[tipc_zone(a)])
		return tipc_zone_next_node(a);
P
Per Liden 已提交
136 137
	return 0;
}
A
Adrian Bunk 已提交
138
#endif
P
Per Liden 已提交
139

140
void tipc_net_remove_as_router(u32 router)
P
Per Liden 已提交
141 142 143 144
{
	u32 z_num;

	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
145
		if (!tipc_net.zones[z_num])
P
Per Liden 已提交
146
			continue;
147
		tipc_zone_remove_as_router(tipc_net.zones[z_num], router);
P
Per Liden 已提交
148 149 150
	}
}

151
void tipc_net_send_external_routes(u32 dest)
P
Per Liden 已提交
152 153 154 155
{
	u32 z_num;

	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
156 157
		if (tipc_net.zones[z_num])
			tipc_zone_send_external_routes(tipc_net.zones[z_num], dest);
P
Per Liden 已提交
158 159 160
	}
}

161
static int net_init(void)
P
Per Liden 已提交
162 163 164
{
	u32 sz = sizeof(struct _zone *) * (tipc_max_zones + 1);

165 166 167
	memset(&tipc_net, 0, sizeof(tipc_net));
	tipc_net.zones = (struct _zone **)kmalloc(sz, GFP_ATOMIC);
	if (!tipc_net.zones) {
P
Per Liden 已提交
168 169
		return -ENOMEM;
	}
170
	memset(tipc_net.zones, 0, sz);
P
Per Liden 已提交
171 172 173
	return TIPC_OK;
}

174
static void net_stop(void)
P
Per Liden 已提交
175 176 177
{
	u32 z_num;

178
	if (!tipc_net.zones)
P
Per Liden 已提交
179 180 181
		return;

	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
182
		tipc_zone_delete(tipc_net.zones[z_num]);
P
Per Liden 已提交
183
	}
184
	kfree(tipc_net.zones);
185
	tipc_net.zones = NULL;
P
Per Liden 已提交
186 187 188 189 190 191 192 193 194
}

static void net_route_named_msg(struct sk_buff *buf)
{
	struct tipc_msg *msg = buf_msg(buf);
	u32 dnode;
	u32 dport;

	if (!msg_named(msg)) {
195
		msg_dbg(msg, "tipc_net->drop_nam:");
P
Per Liden 已提交
196 197 198 199 200
		buf_discard(buf);
		return;
	}

	dnode = addr_domain(msg_lookup_scope(msg));
201 202
	dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode);
	dbg("tipc_net->lookup<%u,%u>-><%u,%x>\n",
P
Per Liden 已提交
203 204 205 206
	    msg_nametype(msg), msg_nameinst(msg), dport, dnode);
	if (dport) {
		msg_set_destnode(msg, dnode);
		msg_set_destport(msg, dport);
207
		tipc_net_route_msg(buf);
P
Per Liden 已提交
208 209
		return;
	}
210
	msg_dbg(msg, "tipc_net->rej:NO NAME: ");
P
Per Liden 已提交
211 212 213
	tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
}

214
void tipc_net_route_msg(struct sk_buff *buf)
P
Per Liden 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
{
	struct tipc_msg *msg;
	u32 dnode;

	if (!buf)
		return;
	msg = buf_msg(buf);

	msg_incr_reroute_cnt(msg);
	if (msg_reroute_cnt(msg) > 6) {
		if (msg_errcode(msg)) {
			msg_dbg(msg, "NET>DISC>:");
			buf_discard(buf);
		} else {
			msg_dbg(msg, "NET>REJ>:");
			tipc_reject_msg(buf, msg_destport(msg) ? 
					TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
		}
		return;
	}

236
	msg_dbg(msg, "tipc_net->rout: ");
P
Per Liden 已提交
237 238 239 240 241 242

	/* Handle message for this node */
	dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
	if (in_scope(dnode, tipc_own_addr)) {
		if (msg_isdata(msg)) {
			if (msg_mcast(msg)) 
243
				tipc_port_recv_mcast(buf, NULL);
P
Per Liden 已提交
244
			else if (msg_destport(msg))
245
				tipc_port_recv_msg(buf);
P
Per Liden 已提交
246 247 248 249 250 251
			else
				net_route_named_msg(buf);
			return;
		}
		switch (msg_user(msg)) {
		case ROUTE_DISTRIBUTOR:
252
			tipc_cltr_recv_routing_table(buf);
P
Per Liden 已提交
253 254
			break;
		case NAME_DISTRIBUTOR:
255
			tipc_named_recv(buf);
P
Per Liden 已提交
256 257
			break;
		case CONN_MANAGER:
258
			tipc_port_recv_proto_msg(buf);
P
Per Liden 已提交
259 260 261 262 263 264 265 266 267 268
			break;
		default:
			msg_dbg(msg,"DROP/NET/<REC<");
			buf_discard(buf);
		}
		return;
	}

	/* Handle message for another node */
	msg_dbg(msg, "NET>SEND>: ");
269
	tipc_link_send(buf, dnode, msg_link_selector(msg));
P
Per Liden 已提交
270 271
}

272
int tipc_net_start(void)
P
Per Liden 已提交
273 274 275 276 277 278 279 280
{
	char addr_string[16];
	int res;

	if (tipc_mode != TIPC_NODE_MODE)
		return -ENOPROTOOPT;

	tipc_mode = TIPC_NET_MODE;
281 282
	tipc_named_reinit();
	tipc_port_reinit();
P
Per Liden 已提交
283

284
	if ((res = tipc_bearer_init()) ||
P
Per Liden 已提交
285
	    (res = net_init()) ||
286 287
	    (res = tipc_cltr_init()) ||
	    (res = tipc_bclink_init())) {
P
Per Liden 已提交
288 289
		return res;
	}
290 291 292 293
        tipc_subscr_stop();
	tipc_cfg_stop();
	tipc_k_signal((Handler)tipc_subscr_start, 0);
	tipc_k_signal((Handler)tipc_cfg_init, 0);
P
Per Liden 已提交
294 295 296 297 298 299
	info("Started in network mode\n");
	info("Own node address %s, network identity %u\n",
	     addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
	return TIPC_OK;
}

300
void tipc_net_stop(void)
P
Per Liden 已提交
301 302 303
{
	if (tipc_mode != TIPC_NET_MODE)
		return;
304 305
        write_lock_bh(&tipc_net_lock);
	tipc_bearer_stop();
P
Per Liden 已提交
306
	tipc_mode = TIPC_NODE_MODE;
307
	tipc_bclink_stop();
P
Per Liden 已提交
308
	net_stop();
309
        write_unlock_bh(&tipc_net_lock);
P
Per Liden 已提交
310 311 312
	info("Left network mode \n");
}