2006-01-02 19:04:38 +01:00
/*
* net / tipc / name_distr . c : TIPC name distribution code
2007-02-09 23:25:21 +09:00
*
2006-01-11 19:14:19 +01:00
* Copyright ( c ) 2000 - 2006 , Ericsson AB
2011-02-23 13:51:15 -05:00
* Copyright ( c ) 2005 , 2010 - 2011 , Wind River Systems
2006-01-02 19:04:38 +01:00
* All rights reserved .
*
2006-01-11 13:30:43 +01:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 19:04:38 +01:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 13:30:43 +01: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 .
2006-01-02 19:04:38 +01:00
*
2006-01-11 13:30:43 +01:00
* 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
2006-01-02 19:04:38 +01:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "link.h"
# include "name_distr.h"
/**
2012-04-17 17:57:52 -04:00
* struct publ_list - list of publications made by this node
* @ list : circular list of publications
* @ list_size : number of entries in list
2006-01-02 19:04:38 +01:00
*/
2012-04-17 17:57:52 -04:00
struct publ_list {
struct list_head list ;
u32 size ;
} ;
2006-01-02 19:04:38 +01:00
2012-04-17 17:57:52 -04:00
static struct publ_list publ_zone = {
. list = LIST_HEAD_INIT ( publ_zone . list ) ,
. size = 0 ,
} ;
2012-04-17 17:57:52 -04:00
static struct publ_list publ_cluster = {
. list = LIST_HEAD_INIT ( publ_cluster . list ) ,
. size = 0 ,
} ;
2006-01-02 19:04:38 +01:00
2012-04-17 17:57:52 -04:00
static struct publ_list publ_node = {
. list = LIST_HEAD_INIT ( publ_node . list ) ,
. size = 0 ,
} ;
static struct publ_list * publ_lists [ ] = {
NULL ,
& publ_zone , /* publ_lists[TIPC_ZONE_SCOPE] */
& publ_cluster , /* publ_lists[TIPC_CLUSTER_SCOPE] */
& publ_node /* publ_lists[TIPC_NODE_SCOPE] */
} ;
2006-01-02 19:04:38 +01:00
/**
* publ_to_item - add publication info to a publication message
*/
static void publ_to_item ( struct distr_item * i , struct publication * p )
{
i - > type = htonl ( p - > type ) ;
i - > lower = htonl ( p - > lower ) ;
i - > upper = htonl ( p - > upper ) ;
i - > ref = htonl ( p - > ref ) ;
i - > key = htonl ( p - > key ) ;
}
/**
* named_prepare_buf - allocate & initialize a publication message
*/
static struct sk_buff * named_prepare_buf ( u32 type , u32 size , u32 dest )
{
2011-05-31 15:03:18 -04:00
struct sk_buff * buf = tipc_buf_acquire ( INT_H_SIZE + size ) ;
2006-01-02 19:04:38 +01:00
struct tipc_msg * msg ;
if ( buf ! = NULL ) {
msg = buf_msg ( buf ) ;
2011-05-31 15:03:18 -04:00
tipc_msg_init ( msg , NAME_DISTRIBUTOR , type , INT_H_SIZE , dest ) ;
msg_set_size ( msg , INT_H_SIZE + size ) ;
2006-01-02 19:04:38 +01:00
}
return buf ;
}
2014-04-28 18:00:10 +08:00
void named_cluster_distribute ( struct sk_buff * buf )
2010-12-31 18:59:19 +00:00
{
struct sk_buff * buf_copy ;
struct tipc_node * n_ptr ;
2014-03-27 12:54:32 +08:00
struct tipc_link * l_ptr ;
2010-12-31 18:59:19 +00:00
2014-03-27 12:54:37 +08:00
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( n_ptr , & tipc_node_list , list ) {
2014-05-05 08:56:09 +08:00
tipc_node_lock ( n_ptr ) ;
2014-03-27 12:54:32 +08:00
l_ptr = n_ptr - > active_links [ n_ptr - > addr & 1 ] ;
if ( l_ptr ) {
2010-12-31 18:59:19 +00:00
buf_copy = skb_copy ( buf , GFP_ATOMIC ) ;
2014-03-27 12:54:32 +08:00
if ( ! buf_copy ) {
2014-05-05 08:56:09 +08:00
tipc_node_unlock ( n_ptr ) ;
2010-12-31 18:59:19 +00:00
break ;
2014-03-27 12:54:32 +08:00
}
2010-12-31 18:59:19 +00:00
msg_set_destnode ( buf_msg ( buf_copy ) , n_ptr - > addr ) ;
2014-03-27 12:54:32 +08:00
__tipc_link_xmit ( l_ptr , buf_copy ) ;
2010-12-31 18:59:19 +00:00
}
2014-05-05 08:56:09 +08:00
tipc_node_unlock ( n_ptr ) ;
2010-12-31 18:59:19 +00:00
}
2014-03-27 12:54:37 +08:00
rcu_read_unlock ( ) ;
2010-12-31 18:59:19 +00:00
2011-11-04 13:24:29 -04:00
kfree_skb ( buf ) ;
2010-12-31 18:59:19 +00:00
}
2006-01-02 19:04:38 +01:00
/**
2006-01-18 00:38:21 +01:00
* tipc_named_publish - tell other nodes about a new publication by this node
2006-01-02 19:04:38 +01:00
*/
2014-04-28 18:00:10 +08:00
struct sk_buff * tipc_named_publish ( struct publication * publ )
2006-01-02 19:04:38 +01:00
{
struct sk_buff * buf ;
struct distr_item * item ;
2012-04-17 17:57:52 -04:00
list_add_tail ( & publ - > local_list , & publ_lists [ publ - > scope ] - > list ) ;
publ_lists [ publ - > scope ] - > size + + ;
2006-01-02 19:04:38 +01:00
2012-04-17 17:57:52 -04:00
if ( publ - > scope = = TIPC_NODE_SCOPE )
2014-04-28 18:00:10 +08:00
return NULL ;
2012-04-17 17:57:52 -04:00
2006-01-02 19:04:38 +01:00
buf = named_prepare_buf ( PUBLICATION , ITEM_SIZE , 0 ) ;
if ( ! buf ) {
2012-06-29 00:16:37 -04:00
pr_warn ( " Publication distribution failure \n " ) ;
2014-04-28 18:00:10 +08:00
return NULL ;
2006-01-02 19:04:38 +01:00
}
item = ( struct distr_item * ) msg_data ( buf_msg ( buf ) ) ;
publ_to_item ( item , publ ) ;
2014-04-28 18:00:10 +08:00
return buf ;
2006-01-02 19:04:38 +01:00
}
/**
2006-01-18 00:38:21 +01:00
* tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
2006-01-02 19:04:38 +01:00
*/
2014-04-28 18:00:10 +08:00
struct sk_buff * tipc_named_withdraw ( struct publication * publ )
2006-01-02 19:04:38 +01:00
{
struct sk_buff * buf ;
struct distr_item * item ;
list_del ( & publ - > local_list ) ;
2012-04-17 17:57:52 -04:00
publ_lists [ publ - > scope ] - > size - - ;
2006-01-02 19:04:38 +01:00
2012-04-17 17:57:52 -04:00
if ( publ - > scope = = TIPC_NODE_SCOPE )
2014-04-28 18:00:10 +08:00
return NULL ;
2012-04-17 17:57:52 -04:00
2006-01-02 19:04:38 +01:00
buf = named_prepare_buf ( WITHDRAWAL , ITEM_SIZE , 0 ) ;
if ( ! buf ) {
2012-06-29 00:16:37 -04:00
pr_warn ( " Withdrawal distribution failure \n " ) ;
2014-04-28 18:00:10 +08:00
return NULL ;
2006-01-02 19:04:38 +01:00
}
item = ( struct distr_item * ) msg_data ( buf_msg ( buf ) ) ;
publ_to_item ( item , publ ) ;
2014-04-28 18:00:10 +08:00
return buf ;
2006-01-02 19:04:38 +01:00
}
2012-04-17 17:57:52 -04:00
/*
* named_distribute - prepare name info for bulk distribution to another node
*/
static void named_distribute ( struct list_head * message_list , u32 node ,
struct publ_list * pls , u32 max_item_buf )
{
struct publication * publ ;
struct sk_buff * buf = NULL ;
struct distr_item * item = NULL ;
u32 left = 0 ;
u32 rest = pls - > size * ITEM_SIZE ;
list_for_each_entry ( publ , & pls - > list , local_list ) {
if ( ! buf ) {
left = ( rest < = max_item_buf ) ? rest : max_item_buf ;
rest - = left ;
buf = named_prepare_buf ( PUBLICATION , left , node ) ;
if ( ! buf ) {
2012-06-29 00:16:37 -04:00
pr_warn ( " Bulk publication failure \n " ) ;
2012-04-17 17:57:52 -04:00
return ;
}
item = ( struct distr_item * ) msg_data ( buf_msg ( buf ) ) ;
}
publ_to_item ( item , publ ) ;
item + + ;
left - = ITEM_SIZE ;
if ( ! left ) {
list_add_tail ( ( struct list_head * ) buf , message_list ) ;
buf = NULL ;
}
}
}
2006-01-02 19:04:38 +01:00
/**
2006-01-18 00:38:21 +01:00
* tipc_named_node_up - tell specified node about all publications by this node
2006-01-02 19:04:38 +01:00
*/
2014-05-05 08:56:14 +08:00
void tipc_named_node_up ( u32 max_item_buf , u32 node )
2006-01-02 19:04:38 +01:00
{
2014-05-05 08:56:14 +08:00
LIST_HEAD ( message_list ) ;
2011-05-31 13:38:02 -04:00
2007-02-09 23:25:21 +09:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2012-04-17 17:57:52 -04:00
named_distribute ( & message_list , node , & publ_cluster , max_item_buf ) ;
2012-04-17 17:57:52 -04:00
named_distribute ( & message_list , node , & publ_zone , max_item_buf ) ;
2007-02-09 23:25:21 +09:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2011-05-31 13:38:02 -04:00
2014-02-18 16:06:46 +08:00
tipc_link_names_xmit ( & message_list , node ) ;
2006-01-02 19:04:38 +01:00
}
/**
2011-02-23 14:13:41 -05:00
* named_purge_publ - remove publication associated with a failed node
2007-02-09 23:25:21 +09:00
*
* Invoked for each publication issued by a newly failed node .
2006-01-02 19:04:38 +01:00
* Removes publication structure from name table & deletes it .
*/
2011-02-23 14:13:41 -05:00
static void named_purge_publ ( struct publication * publ )
2006-01-02 19:04:38 +01:00
{
struct publication * p ;
2006-06-25 23:51:37 -07:00
2007-02-09 23:25:21 +09:00
write_lock_bh ( & tipc_nametbl_lock ) ;
p = tipc_nametbl_remove_publ ( publ - > type , publ - > lower ,
2006-01-18 00:38:21 +01:00
publ - > node , publ - > ref , publ - > key ) ;
2011-02-23 13:51:15 -05:00
if ( p )
tipc_nodesub_unsubscribe ( & p - > subscr ) ;
2006-01-18 00:38:21 +01:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-06-25 23:51:37 -07:00
2007-02-09 23:25:21 +09:00
if ( p ! = publ ) {
2012-06-29 00:16:37 -04:00
pr_err ( " Unable to remove publication from failed node \n "
" (type=%u, lower=%u, node=0x%x, ref=%u, key=%u) \n " ,
publ - > type , publ - > lower , publ - > node , publ - > ref ,
publ - > key ) ;
2006-06-25 23:51:37 -07:00
}
2010-12-31 18:59:30 +00:00
kfree ( p ) ;
2006-01-02 19:04:38 +01:00
}
/**
2014-02-18 16:06:46 +08:00
* tipc_named_rcv - process name table update message sent by another node
2006-01-02 19:04:38 +01:00
*/
2014-02-18 16:06:46 +08:00
void tipc_named_rcv ( struct sk_buff * buf )
2006-01-02 19:04:38 +01:00
{
struct publication * publ ;
struct tipc_msg * msg = buf_msg ( buf ) ;
struct distr_item * item = ( struct distr_item * ) msg_data ( msg ) ;
u32 count = msg_data_sz ( msg ) / ITEM_SIZE ;
2007-02-09 23:25:21 +09:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 19:04:38 +01:00
while ( count - - ) {
if ( msg_type ( msg ) = = PUBLICATION ) {
2007-02-09 23:25:21 +09:00
publ = tipc_nametbl_insert_publ ( ntohl ( item - > type ) ,
2006-01-18 00:38:21 +01:00
ntohl ( item - > lower ) ,
ntohl ( item - > upper ) ,
TIPC_CLUSTER_SCOPE ,
2007-02-09 23:25:21 +09:00
msg_orignode ( msg ) ,
2006-01-18 00:38:21 +01:00
ntohl ( item - > ref ) ,
ntohl ( item - > key ) ) ;
2006-01-02 19:04:38 +01:00
if ( publ ) {
2007-02-09 23:25:21 +09:00
tipc_nodesub_subscribe ( & publ - > subscr ,
msg_orignode ( msg ) ,
2006-01-18 00:38:21 +01:00
publ ,
2011-02-23 14:13:41 -05:00
( net_ev_handler )
named_purge_publ ) ;
2006-01-02 19:04:38 +01:00
}
} else if ( msg_type ( msg ) = = WITHDRAWAL ) {
2006-01-18 00:38:21 +01:00
publ = tipc_nametbl_remove_publ ( ntohl ( item - > type ) ,
ntohl ( item - > lower ) ,
msg_orignode ( msg ) ,
ntohl ( item - > ref ) ,
ntohl ( item - > key ) ) ;
2006-01-02 19:04:38 +01:00
if ( publ ) {
2006-01-18 00:38:21 +01:00
tipc_nodesub_unsubscribe ( & publ - > subscr ) ;
2007-02-09 23:25:21 +09:00
kfree ( publ ) ;
2006-06-25 23:51:37 -07:00
} else {
2012-06-29 00:16:37 -04:00
pr_err ( " Unable to remove publication by node 0x%x \n "
" (type=%u, lower=%u, ref=%u, key=%u) \n " ,
msg_orignode ( msg ) , ntohl ( item - > type ) ,
ntohl ( item - > lower ) , ntohl ( item - > ref ) ,
ntohl ( item - > key ) ) ;
2006-01-02 19:04:38 +01:00
}
} else {
2012-06-29 00:16:37 -04:00
pr_warn ( " Unrecognized name table message received \n " ) ;
2006-01-02 19:04:38 +01:00
}
item + + ;
}
2007-02-09 23:25:21 +09:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2011-11-04 13:24:29 -04:00
kfree_skb ( buf ) ;
2006-01-02 19:04:38 +01:00
}
/**
2012-04-17 17:57:52 -04:00
* tipc_named_reinit - re - initialize local publications
2007-02-09 23:25:21 +09:00
*
2011-10-14 14:42:25 -04:00
* This routine is called whenever TIPC networking is enabled .
2012-04-17 17:57:52 -04:00
* All name table entries published by this node are updated to reflect
* the node ' s new network address .
2006-01-02 19:04:38 +01:00
*/
2006-01-18 00:38:21 +01:00
void tipc_named_reinit ( void )
2006-01-02 19:04:38 +01:00
{
struct publication * publ ;
2012-04-17 17:57:52 -04:00
int scope ;
2006-01-02 19:04:38 +01:00
2007-02-09 23:25:21 +09:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2011-10-14 14:42:25 -04:00
2012-04-17 17:57:52 -04:00
for ( scope = TIPC_ZONE_SCOPE ; scope < = TIPC_NODE_SCOPE ; scope + + )
2012-04-17 17:57:52 -04:00
list_for_each_entry ( publ , & publ_lists [ scope ] - > list , local_list )
publ - > node = tipc_own_addr ;
2011-10-14 14:42:25 -04:00
2007-02-09 23:25:21 +09:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 19:04:38 +01:00
}