2006-01-02 21:04:38 +03:00
/*
* net / tipc / net . c : TIPC network routing code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 1995 - 2006 , Ericsson AB
2006-01-02 21:04:38 +03:00
* 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 :
*
2006-01-11 15:30:43 +03:00
* 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 .
2006-01-02 21:04:38 +03:00
*
* 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"
2007-02-09 17:25:21 +03:00
/*
2006-01-02 21:04:38 +03:00
* The TIPC locking policy is designed to ensure a very fine locking
* granularity , permitting complete parallel access to individual
2007-02-09 17:25:21 +03:00
* port and node / link instances . The code consists of three major
2006-01-02 21:04:38 +03:00
* locking domains , each protected with their own disjunct set of locks .
*
* 1 : The routing hierarchy .
2007-02-09 17:25:21 +03:00
* Comprises the structures ' zone ' , ' cluster ' , ' node ' , ' link '
* and ' bearer ' . The whole hierarchy is protected by a big
* read / write lock , tipc_net_lock , to enssure that nothing is added
* or removed while code is accessing any of these structures .
* This layer must not be called from the two others while they
2006-01-02 21:04:38 +03:00
* hold any of their own locks .
* Neither must it itself do any upcalls to the other two before
2006-01-18 02:38:21 +03:00
* it has released tipc_net_lock and other protective locks .
2006-01-02 21:04:38 +03:00
*
2007-02-09 17:25:21 +03:00
* Within the tipc_net_lock domain there are two sub - domains ; ' node ' and
2006-01-02 21:04:38 +03:00
* ' bearer ' , where local write operations are permitted ,
* provided that those are protected by individual spin_locks
2007-02-09 17:25:21 +03:00
* per instance . Code holding tipc_net_lock ( read ) and a node spin_lock
2006-01-02 21:04:38 +03:00
* is permitted to poke around in both the node itself and its
2007-02-09 17:25:21 +03:00
* 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
2006-01-02 21:04:38 +03:00
* or a node from the overall structure .
2007-02-09 17:25:21 +03:00
* Correspondingly , individual bearers may change status within a
* tipc_net_lock ( read ) , protected by an individual spin_lock ber bearer
2006-01-18 02:38:21 +03:00
* instance , but it needs tipc_net_lock ( write ) to remove / add any bearers .
2006-01-02 21:04:38 +03:00
*
2007-02-09 17:25:21 +03:00
*
* 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 ) .
2006-01-02 21:04:38 +03:00
*
* This layer has four different locks :
* - The tipc_port spin_lock . This is protecting each port instance
2007-02-09 17:25:21 +03:00
* from parallel data access and removal . Since we can not place
* this lock in the port itself , it has been placed in the
2006-01-02 21:04:38 +03:00
* corresponding reference table entry , which has the same life
2007-02-09 17:25:21 +03:00
* 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
2006-01-02 21:04:38 +03:00
* only .
2007-02-09 17:25:21 +03:00
* - 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
2006-01-02 21:04:38 +03:00
* well be changed to a spin_lock )
* - A spin lock to protect the registry of kernel / driver users ( reg . c )
2007-02-09 17:25:21 +03:00
* - A global spin_lock ( tipc_port_lock ) , which only task is to ensure
2006-01-02 21:04:38 +03:00
* 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 .
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* 3 : The name table ( name_table . c , name_distr . c , subscription . c )
2007-02-09 17:25:21 +03:00
* - There is one big read / write - lock ( tipc_nametbl_lock ) protecting the
* overall name table structure . Nothing must be added / removed to
2006-01-02 21:04:38 +03:00
* this structure without holding write access to it .
* - There is one local spin_lock per sub_sequence , which can be seen
2006-01-18 02:38:21 +03:00
* as a sub - domain to the tipc_nametbl_lock domain . It is used only
2006-01-02 21:04:38 +03:00
* for translation operations , and is needed because a translation
* steps the root of the ' publication ' linked list between each lookup .
2006-01-18 02:38:21 +03:00
* This is always used within the scope of a tipc_nametbl_lock ( read ) .
2006-01-02 21:04:38 +03:00
* - A local spin_lock protecting the queue of subscriber events .
*/
2006-06-27 13:53:55 +04:00
DEFINE_RWLOCK ( tipc_net_lock ) ;
2006-03-21 09:36:47 +03:00
struct network tipc_net = { NULL } ;
2006-01-02 21:04:38 +03:00
2008-09-03 10:38:32 +04:00
struct tipc_node * tipc_net_select_remote_node ( u32 addr , u32 ref )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
return tipc_zone_select_remote_node ( tipc_net . zones [ tipc_zone ( addr ) ] , addr , ref ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
u32 tipc_net_select_router ( u32 addr , u32 ref )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
return tipc_zone_select_router ( tipc_net . zones [ tipc_zone ( addr ) ] , addr , ref ) ;
2006-01-02 21:04:38 +03:00
}
2006-03-21 09:37:52 +03:00
#if 0
2006-01-18 02:38:21 +03:00
u32 tipc_net_next_node ( u32 a )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
if ( tipc_net . zones [ tipc_zone ( a ) ] )
return tipc_zone_next_node ( a ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
2006-03-21 09:37:52 +03:00
# endif
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
void tipc_net_remove_as_router ( u32 router )
2006-01-02 21:04:38 +03:00
{
u32 z_num ;
for ( z_num = 1 ; z_num < = tipc_max_zones ; z_num + + ) {
2006-01-18 02:38:21 +03:00
if ( ! tipc_net . zones [ z_num ] )
2006-01-02 21:04:38 +03:00
continue ;
2006-01-18 02:38:21 +03:00
tipc_zone_remove_as_router ( tipc_net . zones [ z_num ] , router ) ;
2006-01-02 21:04:38 +03:00
}
}
2006-01-18 02:38:21 +03:00
void tipc_net_send_external_routes ( u32 dest )
2006-01-02 21:04:38 +03:00
{
u32 z_num ;
for ( z_num = 1 ; z_num < = tipc_max_zones ; z_num + + ) {
2006-01-18 02:38:21 +03:00
if ( tipc_net . zones [ z_num ] )
tipc_zone_send_external_routes ( tipc_net . zones [ z_num ] , dest ) ;
2006-01-02 21:04:38 +03:00
}
}
2006-01-18 02:38:21 +03:00
static int net_init ( void )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
memset ( & tipc_net , 0 , sizeof ( tipc_net ) ) ;
2006-07-22 01:51:30 +04:00
tipc_net . zones = kcalloc ( tipc_max_zones + 1 , sizeof ( struct _zone * ) , GFP_ATOMIC ) ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_net . zones ) {
2006-01-02 21:04:38 +03:00
return - ENOMEM ;
}
2008-07-15 09:44:01 +04:00
return 0 ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
static void net_stop ( void )
2006-01-02 21:04:38 +03:00
{
u32 z_num ;
2006-01-18 02:38:21 +03:00
if ( ! tipc_net . zones )
2006-01-02 21:04:38 +03:00
return ;
for ( z_num = 1 ; z_num < = tipc_max_zones ; z_num + + ) {
2006-01-18 02:38:21 +03:00
tipc_zone_delete ( tipc_net . zones [ z_num ] ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
kfree ( tipc_net . zones ) ;
2006-03-21 09:36:47 +03:00
tipc_net . zones = NULL ;
2006-01-02 21:04:38 +03:00
}
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 ) ) {
2006-01-18 02:38:21 +03:00
msg_dbg ( msg , " tipc_net->drop_nam: " ) ;
2006-01-02 21:04:38 +03:00
buf_discard ( buf ) ;
return ;
}
dnode = addr_domain ( msg_lookup_scope ( msg ) ) ;
2006-01-18 02:38:21 +03:00
dport = tipc_nametbl_translate ( msg_nametype ( msg ) , msg_nameinst ( msg ) , & dnode ) ;
dbg ( " tipc_net->lookup<%u,%u>-><%u,%x> \n " ,
2006-01-02 21:04:38 +03:00
msg_nametype ( msg ) , msg_nameinst ( msg ) , dport , dnode ) ;
if ( dport ) {
msg_set_destnode ( msg , dnode ) ;
msg_set_destport ( msg , dport ) ;
2006-01-18 02:38:21 +03:00
tipc_net_route_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
return ;
}
2006-01-18 02:38:21 +03:00
msg_dbg ( msg , " tipc_net->rej:NO NAME: " ) ;
2006-01-02 21:04:38 +03:00
tipc_reject_msg ( buf , TIPC_ERR_NO_NAME ) ;
}
2006-01-18 02:38:21 +03:00
void tipc_net_route_msg ( struct sk_buff * buf )
2006-01-02 21:04:38 +03:00
{
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>: " ) ;
2007-02-09 17:25:21 +03:00
tipc_reject_msg ( buf , msg_destport ( msg ) ?
2006-01-02 21:04:38 +03:00
TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME ) ;
}
return ;
}
2006-01-18 02:38:21 +03:00
msg_dbg ( msg , " tipc_net->rout: " ) ;
2006-01-02 21:04:38 +03:00
/* 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 ) ) {
2007-02-09 17:25:21 +03:00
if ( msg_mcast ( msg ) )
2006-01-18 02:38:21 +03:00
tipc_port_recv_mcast ( buf , NULL ) ;
2006-01-02 21:04:38 +03:00
else if ( msg_destport ( msg ) )
2006-01-18 02:38:21 +03:00
tipc_port_recv_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
else
net_route_named_msg ( buf ) ;
return ;
}
switch ( msg_user ( msg ) ) {
case ROUTE_DISTRIBUTOR :
2006-01-18 02:38:21 +03:00
tipc_cltr_recv_routing_table ( buf ) ;
2006-01-02 21:04:38 +03:00
break ;
case NAME_DISTRIBUTOR :
2006-01-18 02:38:21 +03:00
tipc_named_recv ( buf ) ;
2006-01-02 21:04:38 +03:00
break ;
case CONN_MANAGER :
2006-01-18 02:38:21 +03:00
tipc_port_recv_proto_msg ( buf ) ;
2006-01-02 21:04:38 +03:00
break ;
default :
msg_dbg ( msg , " DROP/NET/<REC< " ) ;
buf_discard ( buf ) ;
}
return ;
}
/* Handle message for another node */
msg_dbg ( msg , " NET>SEND>: " ) ;
2006-01-18 02:38:21 +03:00
tipc_link_send ( buf , dnode , msg_link_selector ( msg ) ) ;
2006-01-02 21:04:38 +03:00
}
2008-05-22 01:55:04 +04:00
int tipc_net_start ( u32 addr )
2006-01-02 21:04:38 +03:00
{
char addr_string [ 16 ] ;
int res ;
if ( tipc_mode ! = TIPC_NODE_MODE )
return - ENOPROTOOPT ;
2008-05-22 01:55:04 +04:00
tipc_subscr_stop ( ) ;
tipc_cfg_stop ( ) ;
tipc_own_addr = addr ;
2006-01-02 21:04:38 +03:00
tipc_mode = TIPC_NET_MODE ;
2006-01-18 02:38:21 +03:00
tipc_named_reinit ( ) ;
tipc_port_reinit ( ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
if ( ( res = tipc_bearer_init ( ) ) | |
2006-01-02 21:04:38 +03:00
( res = net_init ( ) ) | |
2006-01-18 02:38:21 +03:00
( res = tipc_cltr_init ( ) ) | |
( res = tipc_bclink_init ( ) ) ) {
2006-01-02 21:04:38 +03:00
return res ;
}
2008-05-22 01:55:04 +04:00
2006-01-18 02:38:21 +03:00
tipc_k_signal ( ( Handler ) tipc_subscr_start , 0 ) ;
tipc_k_signal ( ( Handler ) tipc_cfg_init , 0 ) ;
2008-05-22 01:55:04 +04:00
2006-01-02 21:04:38 +03:00
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 ) ;
2008-07-15 09:44:01 +04:00
return 0 ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
void tipc_net_stop ( void )
2006-01-02 21:04:38 +03:00
{
if ( tipc_mode ! = TIPC_NET_MODE )
return ;
2007-02-09 17:25:21 +03:00
write_lock_bh ( & tipc_net_lock ) ;
2006-01-18 02:38:21 +03:00
tipc_bearer_stop ( ) ;
2006-01-02 21:04:38 +03:00
tipc_mode = TIPC_NODE_MODE ;
2006-01-18 02:38:21 +03:00
tipc_bclink_stop ( ) ;
2006-01-02 21:04:38 +03:00
net_stop ( ) ;
2007-02-09 17:25:21 +03:00
write_unlock_bh ( & tipc_net_lock ) ;
2006-01-02 21:04:38 +03:00
info ( " Left network mode \n " ) ;
}