2006-01-02 21:04:38 +03:00
/*
* net / tipc / name_table . c : TIPC name table code
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 2000 - 2006 , Ericsson AB
2006-01-02 21:04:38 +03:00
* Copyright ( c ) 2004 - 2005 , Wind River Systems
* All rights reserved .
*
2006-01-11 15:30:43 +03:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 21:04:38 +03:00
* 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 .
2006-01-02 21:04:38 +03:00
*
2006-01-11 15:30:43 +03: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 21:04:38 +03:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "config.h"
# include "dbg.h"
# include "name_table.h"
# include "name_distr.h"
# include "addr.h"
# include "node_subscr.h"
# include "subscr.h"
# include "port.h"
# include "cluster.h"
# include "bcast.h"
int tipc_nametbl_size = 1024 ; /* must be a power of 2 */
/**
* struct sub_seq - container for all published instances of a name sequence
* @ lower : name sequence lower bound
* @ upper : name sequence upper bound
* @ node_list : circular list of matching publications with > = node scope
* @ cluster_list : circular list of matching publications with > = cluster scope
* @ zone_list : circular list of matching publications with > = zone scope
*/
struct sub_seq {
u32 lower ;
u32 upper ;
struct publication * node_list ;
struct publication * cluster_list ;
struct publication * zone_list ;
} ;
/**
* struct name_seq - container for all published instances of a name type
* @ type : 32 bit ' type ' value for name sequence
* @ sseq : pointer to dynamically - sized array of sub - sequences of this ' type ' ;
* sub - sequences are sorted in ascending order
* @ alloc : number of sub - sequences currently in array
* @ first_free : upper bound of highest sub - sequence + 1
* @ ns_list : links to adjacent name sequences in hash chain
* @ subscriptions : list of subscriptions for this ' type '
* @ lock : spinlock controlling access to name sequence structure
*/
struct name_seq {
u32 type ;
struct sub_seq * sseqs ;
u32 alloc ;
u32 first_free ;
struct hlist_node ns_list ;
struct list_head subscriptions ;
spinlock_t lock ;
} ;
/**
* struct name_table - table containing all existing port name publications
* @ types : pointer to fixed - sized array of name sequence lists ,
* accessed via hashing on ' type ' ; name sequence lists are * not * sorted
* @ local_publ_count : number of publications issued by this node
*/
struct name_table {
struct hlist_head * types ;
u32 local_publ_count ;
} ;
struct name_table table = { NULL } ;
static atomic_t rsv_publ_ok = ATOMIC_INIT ( 0 ) ;
rwlock_t nametbl_lock = RW_LOCK_UNLOCKED ;
static inline int hash ( int x )
{
return ( x & ( tipc_nametbl_size - 1 ) ) ;
}
/**
* publ_create - create a publication structure
*/
static struct publication * publ_create ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port_ref ,
u32 key )
{
struct publication * publ =
( struct publication * ) kmalloc ( sizeof ( * publ ) , GFP_ATOMIC ) ;
if ( publ = = NULL ) {
warn ( " Memory squeeze; failed to create publication \n " ) ;
return 0 ;
}
memset ( publ , 0 , sizeof ( * publ ) ) ;
publ - > type = type ;
publ - > lower = lower ;
publ - > upper = upper ;
publ - > scope = scope ;
publ - > node = node ;
publ - > ref = port_ref ;
publ - > key = key ;
INIT_LIST_HEAD ( & publ - > local_list ) ;
INIT_LIST_HEAD ( & publ - > pport_list ) ;
INIT_LIST_HEAD ( & publ - > subscr . nodesub_list ) ;
return publ ;
}
/**
* subseq_alloc - allocate a specified number of sub - sequence structures
*/
struct sub_seq * subseq_alloc ( u32 cnt )
{
u32 sz = cnt * sizeof ( struct sub_seq ) ;
struct sub_seq * sseq = ( struct sub_seq * ) kmalloc ( sz , GFP_ATOMIC ) ;
if ( sseq )
memset ( sseq , 0 , sz ) ;
return sseq ;
}
/**
* nameseq_create - create a name sequence structure for the specified ' type '
*
* Allocates a single sub - sequence structure and sets it to all 0 ' s .
*/
struct name_seq * nameseq_create ( u32 type , struct hlist_head * seq_head )
{
struct name_seq * nseq =
( struct name_seq * ) kmalloc ( sizeof ( * nseq ) , GFP_ATOMIC ) ;
struct sub_seq * sseq = subseq_alloc ( 1 ) ;
if ( ! nseq | | ! sseq ) {
warn ( " Memory squeeze; failed to create name sequence \n " ) ;
kfree ( nseq ) ;
kfree ( sseq ) ;
return 0 ;
}
memset ( nseq , 0 , sizeof ( * nseq ) ) ;
nseq - > lock = SPIN_LOCK_UNLOCKED ;
nseq - > type = type ;
nseq - > sseqs = sseq ;
dbg ( " nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u \n " ,
nseq , type , nseq - > sseqs , nseq - > first_free ) ;
nseq - > alloc = 1 ;
INIT_HLIST_NODE ( & nseq - > ns_list ) ;
INIT_LIST_HEAD ( & nseq - > subscriptions ) ;
hlist_add_head ( & nseq - > ns_list , seq_head ) ;
return nseq ;
}
/**
* nameseq_find_subseq - find sub - sequence ( if any ) matching a name instance
*
* Very time - critical , so binary searches through sub - sequence array .
*/
static inline struct sub_seq * nameseq_find_subseq ( struct name_seq * nseq ,
u32 instance )
{
struct sub_seq * sseqs = nseq - > sseqs ;
int low = 0 ;
int high = nseq - > first_free - 1 ;
int mid ;
while ( low < = high ) {
mid = ( low + high ) / 2 ;
if ( instance < sseqs [ mid ] . lower )
high = mid - 1 ;
else if ( instance > sseqs [ mid ] . upper )
low = mid + 1 ;
else
return & sseqs [ mid ] ;
}
return 0 ;
}
/**
* nameseq_locate_subseq - determine position of name instance in sub - sequence
*
* Returns index in sub - sequence array of the entry that contains the specified
* instance value ; if no entry contains that value , returns the position
* where a new entry for it would be inserted in the array .
*
* Note : Similar to binary search code for locating a sub - sequence .
*/
static u32 nameseq_locate_subseq ( struct name_seq * nseq , u32 instance )
{
struct sub_seq * sseqs = nseq - > sseqs ;
int low = 0 ;
int high = nseq - > first_free - 1 ;
int mid ;
while ( low < = high ) {
mid = ( low + high ) / 2 ;
if ( instance < sseqs [ mid ] . lower )
high = mid - 1 ;
else if ( instance > sseqs [ mid ] . upper )
low = mid + 1 ;
else
return mid ;
}
return low ;
}
/**
* nameseq_insert_publ -
*/
struct publication * nameseq_insert_publ ( struct name_seq * nseq ,
u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
{
struct subscription * s ;
struct subscription * st ;
struct publication * publ ;
struct sub_seq * sseq ;
int created_subseq = 0 ;
assert ( nseq - > first_free < = nseq - > alloc ) ;
sseq = nameseq_find_subseq ( nseq , lower ) ;
dbg ( " nameseq_ins: for seq %x,<%u,%u>, found sseq %x \n " ,
nseq , type , lower , sseq ) ;
if ( sseq ) {
/* Lower end overlaps existing entry => need an exact match */
if ( ( sseq - > lower ! = lower ) | | ( sseq - > upper ! = upper ) ) {
warn ( " Overlapping publ <%u,%u,%u> \n " , type , lower , upper ) ;
return 0 ;
}
} else {
u32 inspos ;
struct sub_seq * freesseq ;
/* Find where lower end should be inserted */
inspos = nameseq_locate_subseq ( nseq , lower ) ;
/* Fail if upper end overlaps into an existing entry */
if ( ( inspos < nseq - > first_free ) & &
( upper > = nseq - > sseqs [ inspos ] . lower ) ) {
warn ( " Overlapping publ <%u,%u,%u> \n " , type , lower , upper ) ;
return 0 ;
}
/* Ensure there is space for new sub-sequence */
if ( nseq - > first_free = = nseq - > alloc ) {
struct sub_seq * sseqs = nseq - > sseqs ;
nseq - > sseqs = subseq_alloc ( nseq - > alloc * 2 ) ;
if ( nseq - > sseqs ! = NULL ) {
memcpy ( nseq - > sseqs , sseqs ,
nseq - > alloc * sizeof ( struct sub_seq ) ) ;
kfree ( sseqs ) ;
dbg ( " Allocated %u sseqs \n " , nseq - > alloc ) ;
nseq - > alloc * = 2 ;
} else {
warn ( " Memory squeeze; failed to create sub-sequence \n " ) ;
return 0 ;
}
}
dbg ( " Have %u sseqs for type %u \n " , nseq - > alloc , type ) ;
/* Insert new sub-sequence */
dbg ( " ins in pos %u, ff = %u \n " , inspos , nseq - > first_free ) ;
sseq = & nseq - > sseqs [ inspos ] ;
freesseq = & nseq - > sseqs [ nseq - > first_free ] ;
memmove ( sseq + 1 , sseq , ( freesseq - sseq ) * sizeof ( * sseq ) ) ;
memset ( sseq , 0 , sizeof ( * sseq ) ) ;
nseq - > first_free + + ;
sseq - > lower = lower ;
sseq - > upper = upper ;
created_subseq = 1 ;
}
dbg ( " inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x \n " ,
type , lower , upper , node , port , sseq ,
sseq - > lower , sseq - > upper , nseq ) ;
/* Insert a publication: */
publ = publ_create ( type , lower , upper , scope , node , port , key ) ;
if ( ! publ )
return 0 ;
dbg ( " inserting publ %x, node=%x publ->node=%x, subscr->node=%x \n " ,
publ , node , publ - > node , publ - > subscr . node ) ;
if ( ! sseq - > zone_list )
sseq - > zone_list = publ - > zone_list_next = publ ;
else {
publ - > zone_list_next = sseq - > zone_list - > zone_list_next ;
sseq - > zone_list - > zone_list_next = publ ;
}
if ( in_own_cluster ( node ) ) {
if ( ! sseq - > cluster_list )
sseq - > cluster_list = publ - > cluster_list_next = publ ;
else {
publ - > cluster_list_next =
sseq - > cluster_list - > cluster_list_next ;
sseq - > cluster_list - > cluster_list_next = publ ;
}
}
if ( node = = tipc_own_addr ) {
if ( ! sseq - > node_list )
sseq - > node_list = publ - > node_list_next = publ ;
else {
publ - > node_list_next = sseq - > node_list - > node_list_next ;
sseq - > node_list - > node_list_next = publ ;
}
}
/*
* Any subscriptions waiting for notification ?
*/
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
dbg ( " calling report_overlap() \n " ) ;
subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
TIPC_PUBLISHED ,
publ - > ref ,
publ - > node ,
created_subseq ) ;
}
return publ ;
}
/**
* nameseq_remove_publ -
*/
struct publication * nameseq_remove_publ ( struct name_seq * nseq , u32 inst ,
u32 node , u32 ref , u32 key )
{
struct publication * publ ;
struct publication * prev ;
struct sub_seq * sseq = nameseq_find_subseq ( nseq , inst ) ;
struct sub_seq * free ;
struct subscription * s , * st ;
int removed_subseq = 0 ;
assert ( nseq ) ;
if ( ! sseq ) {
int i ;
warn ( " Withdraw unknown <%u,%u>? \n " , nseq - > type , inst ) ;
assert ( nseq - > sseqs ) ;
dbg ( " Dumping subseqs %x for %x, alloc = %u,ff=%u \n " ,
nseq - > sseqs , nseq , nseq - > alloc ,
nseq - > first_free ) ;
for ( i = 0 ; i < nseq - > first_free ; i + + ) {
dbg ( " Subseq %u(%x): lower = %u,upper = %u \n " ,
i , & nseq - > sseqs [ i ] , nseq - > sseqs [ i ] . lower ,
nseq - > sseqs [ i ] . upper ) ;
}
return 0 ;
}
dbg ( " nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u \n " ,
nseq , sseq , nseq - > type , inst , key ) ;
prev = sseq - > zone_list ;
publ = sseq - > zone_list - > zone_list_next ;
while ( ( publ - > key ! = key ) | | ( publ - > ref ! = ref ) | |
( publ - > node & & ( publ - > node ! = node ) ) ) {
prev = publ ;
publ = publ - > zone_list_next ;
assert ( prev ! = sseq - > zone_list ) ;
}
if ( publ ! = sseq - > zone_list )
prev - > zone_list_next = publ - > zone_list_next ;
else if ( publ - > zone_list_next ! = publ ) {
prev - > zone_list_next = publ - > zone_list_next ;
sseq - > zone_list = publ - > zone_list_next ;
} else {
sseq - > zone_list = 0 ;
}
if ( in_own_cluster ( node ) ) {
prev = sseq - > cluster_list ;
publ = sseq - > cluster_list - > cluster_list_next ;
while ( ( publ - > key ! = key ) | | ( publ - > ref ! = ref ) | |
( publ - > node & & ( publ - > node ! = node ) ) ) {
prev = publ ;
publ = publ - > cluster_list_next ;
assert ( prev ! = sseq - > cluster_list ) ;
}
if ( publ ! = sseq - > cluster_list )
prev - > cluster_list_next = publ - > cluster_list_next ;
else if ( publ - > cluster_list_next ! = publ ) {
prev - > cluster_list_next = publ - > cluster_list_next ;
sseq - > cluster_list = publ - > cluster_list_next ;
} else {
sseq - > cluster_list = 0 ;
}
}
if ( node = = tipc_own_addr ) {
prev = sseq - > node_list ;
publ = sseq - > node_list - > node_list_next ;
while ( ( publ - > key ! = key ) | | ( publ - > ref ! = ref ) | |
( publ - > node & & ( publ - > node ! = node ) ) ) {
prev = publ ;
publ = publ - > node_list_next ;
assert ( prev ! = sseq - > node_list ) ;
}
if ( publ ! = sseq - > node_list )
prev - > node_list_next = publ - > node_list_next ;
else if ( publ - > node_list_next ! = publ ) {
prev - > node_list_next = publ - > node_list_next ;
sseq - > node_list = publ - > node_list_next ;
} else {
sseq - > node_list = 0 ;
}
}
assert ( ! publ - > node | | ( publ - > node = = node ) ) ;
assert ( publ - > ref = = ref ) ;
assert ( publ - > key = = key ) ;
/*
* Contract subseq list if no more publications :
*/
if ( ! sseq - > node_list & & ! sseq - > cluster_list & & ! sseq - > zone_list ) {
free = & nseq - > sseqs [ nseq - > first_free - - ] ;
memmove ( sseq , sseq + 1 , ( free - ( sseq + 1 ) ) * sizeof ( * sseq ) ) ;
removed_subseq = 1 ;
}
/*
* Any subscriptions waiting ?
*/
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
TIPC_WITHDRAWN ,
publ - > ref ,
publ - > node ,
removed_subseq ) ;
}
return publ ;
}
/**
* nameseq_subscribe : attach a subscription , and issue
* the prescribed number of events if there is any sub -
* sequence overlapping with the requested sequence
*/
void nameseq_subscribe ( struct name_seq * nseq , struct subscription * s )
{
struct sub_seq * sseq = nseq - > sseqs ;
list_add ( & s - > nameseq_list , & nseq - > subscriptions ) ;
if ( ! sseq )
return ;
while ( sseq ! = & nseq - > sseqs [ nseq - > first_free ] ) {
struct publication * zl = sseq - > zone_list ;
if ( zl & & subscr_overlap ( s , sseq - > lower , sseq - > upper ) ) {
struct publication * crs = zl ;
int must_report = 1 ;
do {
subscr_report_overlap ( s ,
sseq - > lower ,
sseq - > upper ,
TIPC_PUBLISHED ,
crs - > ref ,
crs - > node ,
must_report ) ;
must_report = 0 ;
crs = crs - > zone_list_next ;
} while ( crs ! = zl ) ;
}
sseq + + ;
}
}
static struct name_seq * nametbl_find_seq ( u32 type )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct name_seq * ns ;
dbg ( " find_seq %u,(%u,0x%x) table = %p, hash[type] = %u \n " ,
type , ntohl ( type ) , type , table . types , hash ( type ) ) ;
seq_head = & table . types [ hash ( type ) ] ;
hlist_for_each_entry ( ns , seq_node , seq_head , ns_list ) {
if ( ns - > type = = type ) {
dbg ( " found %x \n " , ns ) ;
return ns ;
}
}
return 0 ;
} ;
struct publication * nametbl_insert_publ ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
{
struct name_seq * seq = nametbl_find_seq ( type ) ;
dbg ( " ins_publ: <%u,%x,%x> found %x \n " , type , lower , upper , seq ) ;
if ( lower > upper ) {
warn ( " Failed to publish illegal <%u,%u,%u> \n " ,
type , lower , upper ) ;
return 0 ;
}
dbg ( " Publishing <%u,%u,%u> from %x \n " , type , lower , upper , node ) ;
if ( ! seq ) {
seq = nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
dbg ( " nametbl_insert_publ: created %x \n " , seq ) ;
}
if ( ! seq )
return 0 ;
assert ( seq - > type = = type ) ;
return nameseq_insert_publ ( seq , type , lower , upper ,
scope , node , port , key ) ;
}
struct publication * nametbl_remove_publ ( u32 type , u32 lower ,
u32 node , u32 ref , u32 key )
{
struct publication * publ ;
struct name_seq * seq = nametbl_find_seq ( type ) ;
if ( ! seq )
return 0 ;
dbg ( " Withdrawing <%u,%u> from %x \n " , type , lower , node ) ;
publ = nameseq_remove_publ ( seq , lower , node , ref , key ) ;
if ( ! seq - > first_free & & list_empty ( & seq - > subscriptions ) ) {
hlist_del_init ( & seq - > ns_list ) ;
kfree ( seq - > sseqs ) ;
kfree ( seq ) ;
}
return publ ;
}
/*
* nametbl_translate ( ) : Translate tipc_name - > tipc_portid .
* Very time - critical .
*
* Note : on entry ' destnode ' is the search domain used during translation ;
* on exit it passes back the node address of the matching port ( if any )
*/
u32 nametbl_translate ( u32 type , u32 instance , u32 * destnode )
{
struct sub_seq * sseq ;
struct publication * publ = 0 ;
struct name_seq * seq ;
u32 ref ;
if ( ! in_scope ( * destnode , tipc_own_addr ) )
return 0 ;
read_lock_bh ( & nametbl_lock ) ;
seq = nametbl_find_seq ( type ) ;
if ( unlikely ( ! seq ) )
goto not_found ;
sseq = nameseq_find_subseq ( seq , instance ) ;
if ( unlikely ( ! sseq ) )
goto not_found ;
spin_lock_bh ( & seq - > lock ) ;
/* Closest-First Algorithm: */
if ( likely ( ! * destnode ) ) {
publ = sseq - > node_list ;
if ( publ ) {
sseq - > node_list = publ - > node_list_next ;
found :
ref = publ - > ref ;
* destnode = publ - > node ;
spin_unlock_bh ( & seq - > lock ) ;
read_unlock_bh ( & nametbl_lock ) ;
return ref ;
}
publ = sseq - > cluster_list ;
if ( publ ) {
sseq - > cluster_list = publ - > cluster_list_next ;
goto found ;
}
publ = sseq - > zone_list ;
if ( publ ) {
sseq - > zone_list = publ - > zone_list_next ;
goto found ;
}
}
/* Round-Robin Algorithm: */
else if ( * destnode = = tipc_own_addr ) {
publ = sseq - > node_list ;
if ( publ ) {
sseq - > node_list = publ - > node_list_next ;
goto found ;
}
} else if ( in_own_cluster ( * destnode ) ) {
publ = sseq - > cluster_list ;
if ( publ ) {
sseq - > cluster_list = publ - > cluster_list_next ;
goto found ;
}
} else {
publ = sseq - > zone_list ;
if ( publ ) {
sseq - > zone_list = publ - > zone_list_next ;
goto found ;
}
}
spin_unlock_bh ( & seq - > lock ) ;
not_found :
* destnode = 0 ;
read_unlock_bh ( & nametbl_lock ) ;
return 0 ;
}
/**
* nametbl_mc_translate - find multicast destinations
*
* Creates list of all local ports that overlap the given multicast address ;
* also determines if any off - node ports overlap .
*
* Note : Publications with a scope narrower than ' limit ' are ignored .
* ( i . e . local node - scope publications mustn ' t receive messages arriving
* from another node , even if the multcast link brought it here )
*
* Returns non - zero if any off - node ports overlap
*/
int nametbl_mc_translate ( u32 type , u32 lower , u32 upper , u32 limit ,
struct port_list * dports )
{
struct name_seq * seq ;
struct sub_seq * sseq ;
struct sub_seq * sseq_stop ;
int res = 0 ;
read_lock_bh ( & nametbl_lock ) ;
seq = nametbl_find_seq ( type ) ;
if ( ! seq )
goto exit ;
spin_lock_bh ( & seq - > lock ) ;
sseq = seq - > sseqs + nameseq_locate_subseq ( seq , lower ) ;
sseq_stop = seq - > sseqs + seq - > first_free ;
for ( ; sseq ! = sseq_stop ; sseq + + ) {
struct publication * publ ;
if ( sseq - > lower > upper )
break ;
publ = sseq - > cluster_list ;
if ( publ & & ( publ - > scope < = limit ) )
do {
if ( publ - > node = = tipc_own_addr )
port_list_add ( dports , publ - > ref ) ;
else
res = 1 ;
publ = publ - > cluster_list_next ;
} while ( publ ! = sseq - > cluster_list ) ;
}
spin_unlock_bh ( & seq - > lock ) ;
exit :
read_unlock_bh ( & nametbl_lock ) ;
return res ;
}
/**
* nametbl_publish_rsv - publish port name using a reserved name type
*/
int nametbl_publish_rsv ( u32 ref , unsigned int scope ,
struct tipc_name_seq const * seq )
{
int res ;
atomic_inc ( & rsv_publ_ok ) ;
res = tipc_publish ( ref , scope , seq ) ;
atomic_dec ( & rsv_publ_ok ) ;
return res ;
}
/**
* nametbl_publish - add name publication to network name tables
*/
struct publication * nametbl_publish ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 port_ref , u32 key )
{
struct publication * publ ;
if ( table . local_publ_count > = tipc_max_publications ) {
warn ( " Failed publish: max %u local publication \n " ,
tipc_max_publications ) ;
return 0 ;
}
if ( ( type < TIPC_RESERVED_TYPES ) & & ! atomic_read ( & rsv_publ_ok ) ) {
warn ( " Failed to publish reserved name <%u,%u,%u> \n " ,
type , lower , upper ) ;
return 0 ;
}
write_lock_bh ( & nametbl_lock ) ;
table . local_publ_count + + ;
publ = nametbl_insert_publ ( type , lower , upper , scope ,
tipc_own_addr , port_ref , key ) ;
if ( publ & & ( scope ! = TIPC_NODE_SCOPE ) ) {
named_publish ( publ ) ;
}
write_unlock_bh ( & nametbl_lock ) ;
return publ ;
}
/**
* nametbl_withdraw - withdraw name publication from network name tables
*/
int nametbl_withdraw ( u32 type , u32 lower , u32 ref , u32 key )
{
struct publication * publ ;
dbg ( " nametbl_withdraw:<%d,%d,%d> \n " , type , lower , key ) ;
write_lock_bh ( & nametbl_lock ) ;
publ = nametbl_remove_publ ( type , lower , tipc_own_addr , ref , key ) ;
if ( publ ) {
table . local_publ_count - - ;
if ( publ - > scope ! = TIPC_NODE_SCOPE )
named_withdraw ( publ ) ;
write_unlock_bh ( & nametbl_lock ) ;
list_del_init ( & publ - > pport_list ) ;
kfree ( publ ) ;
return 1 ;
}
write_unlock_bh ( & nametbl_lock ) ;
return 0 ;
}
/**
* nametbl_subscribe - add a subscription object to the name table
*/
void
nametbl_subscribe ( struct subscription * s )
{
u32 type = s - > seq . type ;
struct name_seq * seq ;
write_lock_bh ( & nametbl_lock ) ;
seq = nametbl_find_seq ( type ) ;
if ( ! seq ) {
seq = nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
}
if ( seq ) {
spin_lock_bh ( & seq - > lock ) ;
dbg ( " nametbl_subscribe:found %x for <%u,%u,%u> \n " ,
seq , type , s - > seq . lower , s - > seq . upper ) ;
assert ( seq - > type = = type ) ;
nameseq_subscribe ( seq , s ) ;
spin_unlock_bh ( & seq - > lock ) ;
}
write_unlock_bh ( & nametbl_lock ) ;
}
/**
* nametbl_unsubscribe - remove a subscription object from name table
*/
void
nametbl_unsubscribe ( struct subscription * s )
{
struct name_seq * seq ;
write_lock_bh ( & nametbl_lock ) ;
seq = nametbl_find_seq ( s - > seq . type ) ;
if ( seq ! = NULL ) {
spin_lock_bh ( & seq - > lock ) ;
list_del_init ( & s - > nameseq_list ) ;
spin_unlock_bh ( & seq - > lock ) ;
if ( ( seq - > first_free = = 0 ) & & list_empty ( & seq - > subscriptions ) ) {
hlist_del_init ( & seq - > ns_list ) ;
kfree ( seq - > sseqs ) ;
kfree ( seq ) ;
}
}
write_unlock_bh ( & nametbl_lock ) ;
}
/**
* subseq_list : print specified sub - sequence contents into the given buffer
*/
static void subseq_list ( struct sub_seq * sseq , struct print_buf * buf , u32 depth ,
u32 index )
{
char portIdStr [ 27 ] ;
char * scopeStr ;
struct publication * publ = sseq - > zone_list ;
tipc_printf ( buf , " %-10u %-10u " , sseq - > lower , sseq - > upper ) ;
if ( depth = = 2 | | ! publ ) {
tipc_printf ( buf , " \n " ) ;
return ;
}
do {
sprintf ( portIdStr , " <%u.%u.%u:%u> " ,
tipc_zone ( publ - > node ) , tipc_cluster ( publ - > node ) ,
tipc_node ( publ - > node ) , publ - > ref ) ;
tipc_printf ( buf , " %-26s " , portIdStr ) ;
if ( depth > 3 ) {
if ( publ - > node ! = tipc_own_addr )
scopeStr = " " ;
else if ( publ - > scope = = TIPC_NODE_SCOPE )
scopeStr = " node " ;
else if ( publ - > scope = = TIPC_CLUSTER_SCOPE )
scopeStr = " cluster " ;
else
scopeStr = " zone " ;
tipc_printf ( buf , " %-10u %s " , publ - > key , scopeStr ) ;
}
publ = publ - > zone_list_next ;
if ( publ = = sseq - > zone_list )
break ;
tipc_printf ( buf , " \n %33s " , " " ) ;
} while ( 1 ) ;
tipc_printf ( buf , " \n " ) ;
}
/**
* nameseq_list : print specified name sequence contents into the given buffer
*/
static void nameseq_list ( struct name_seq * seq , struct print_buf * buf , u32 depth ,
u32 type , u32 lowbound , u32 upbound , u32 index )
{
struct sub_seq * sseq ;
char typearea [ 11 ] ;
sprintf ( typearea , " %-10u " , seq - > type ) ;
if ( depth = = 1 ) {
tipc_printf ( buf , " %s \n " , typearea ) ;
return ;
}
for ( sseq = seq - > sseqs ; sseq ! = & seq - > sseqs [ seq - > first_free ] ; sseq + + ) {
if ( ( lowbound < = sseq - > upper ) & & ( upbound > = sseq - > lower ) ) {
tipc_printf ( buf , " %s " , typearea ) ;
subseq_list ( sseq , buf , depth , index ) ;
sprintf ( typearea , " %10s " , " " ) ;
}
}
}
/**
* nametbl_header - print name table header into the given buffer
*/
static void nametbl_header ( struct print_buf * buf , u32 depth )
{
tipc_printf ( buf , " Type " ) ;
if ( depth > 1 )
tipc_printf ( buf , " Lower Upper " ) ;
if ( depth > 2 )
tipc_printf ( buf , " Port Identity " ) ;
if ( depth > 3 )
tipc_printf ( buf , " Publication " ) ;
tipc_printf ( buf , " \n ----------- " ) ;
if ( depth > 1 )
tipc_printf ( buf , " --------------------- " ) ;
if ( depth > 2 )
tipc_printf ( buf , " -------------------------- " ) ;
if ( depth > 3 )
tipc_printf ( buf , " ------------------ " ) ;
tipc_printf ( buf , " \n " ) ;
}
/**
* nametbl_list - print specified name table contents into the given buffer
*/
static void nametbl_list ( struct print_buf * buf , u32 depth_info ,
u32 type , u32 lowbound , u32 upbound )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct name_seq * seq ;
int all_types ;
u32 depth ;
u32 i ;
all_types = ( depth_info & TIPC_NTQ_ALLTYPES ) ;
depth = ( depth_info & ~ TIPC_NTQ_ALLTYPES ) ;
if ( depth = = 0 )
return ;
if ( all_types ) {
/* display all entries in name table to specified depth */
nametbl_header ( buf , depth ) ;
lowbound = 0 ;
upbound = ~ 0 ;
for ( i = 0 ; i < tipc_nametbl_size ; i + + ) {
seq_head = & table . types [ i ] ;
hlist_for_each_entry ( seq , seq_node , seq_head , ns_list ) {
nameseq_list ( seq , buf , depth , seq - > type ,
lowbound , upbound , i ) ;
}
}
} else {
/* display only the sequence that matches the specified type */
if ( upbound < lowbound ) {
tipc_printf ( buf , " invalid name sequence specified \n " ) ;
return ;
}
nametbl_header ( buf , depth ) ;
i = hash ( type ) ;
seq_head = & table . types [ i ] ;
hlist_for_each_entry ( seq , seq_node , seq_head , ns_list ) {
if ( seq - > type = = type ) {
nameseq_list ( seq , buf , depth , type ,
lowbound , upbound , i ) ;
break ;
}
}
}
}
void nametbl_print ( struct print_buf * buf , const char * str )
{
tipc_printf ( buf , str ) ;
read_lock_bh ( & nametbl_lock ) ;
nametbl_list ( buf , 0 , 0 , 0 , 0 ) ;
read_unlock_bh ( & nametbl_lock ) ;
}
# define MAX_NAME_TBL_QUERY 32768
struct sk_buff * nametbl_get ( const void * req_tlv_area , int req_tlv_space )
{
struct sk_buff * buf ;
struct tipc_name_table_query * argv ;
struct tlv_desc * rep_tlv ;
struct print_buf b ;
int str_len ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_NAME_TBL_QUERY ) )
return cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
buf = cfg_reply_alloc ( TLV_SPACE ( MAX_NAME_TBL_QUERY ) ) ;
if ( ! buf )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
printbuf_init ( & b , TLV_DATA ( rep_tlv ) , MAX_NAME_TBL_QUERY ) ;
argv = ( struct tipc_name_table_query * ) TLV_DATA ( req_tlv_area ) ;
read_lock_bh ( & nametbl_lock ) ;
nametbl_list ( & b , ntohl ( argv - > depth ) , ntohl ( argv - > type ) ,
ntohl ( argv - > lowbound ) , ntohl ( argv - > upbound ) ) ;
read_unlock_bh ( & nametbl_lock ) ;
str_len = printbuf_validate ( & b ) ;
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
void nametbl_dump ( void )
{
nametbl_list ( CONS , 0 , 0 , 0 , 0 ) ;
}
int nametbl_init ( void )
{
int array_size = sizeof ( struct hlist_head ) * tipc_nametbl_size ;
table . types = ( struct hlist_head * ) kmalloc ( array_size , GFP_ATOMIC ) ;
if ( ! table . types )
return - ENOMEM ;
write_lock_bh ( & nametbl_lock ) ;
memset ( table . types , 0 , array_size ) ;
table . local_publ_count = 0 ;
write_unlock_bh ( & nametbl_lock ) ;
return 0 ;
}
void nametbl_stop ( void )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct hlist_node * tmp ;
struct name_seq * seq ;
u32 i ;
if ( ! table . types )
return ;
write_lock_bh ( & nametbl_lock ) ;
for ( i = 0 ; i < tipc_nametbl_size ; i + + ) {
seq_head = & table . types [ i ] ;
hlist_for_each_entry_safe ( seq , seq_node , tmp , seq_head , ns_list ) {
struct sub_seq * sseq = seq - > sseqs ;
for ( ; sseq ! = & seq - > sseqs [ seq - > first_free ] ; sseq + + ) {
struct publication * publ = sseq - > zone_list ;
assert ( publ ) ;
do {
struct publication * next =
publ - > zone_list_next ;
kfree ( publ ) ;
publ = next ;
}
while ( publ ! = sseq - > zone_list ) ;
}
}
}
kfree ( table . types ) ;
table . types = NULL ;
write_unlock_bh ( & nametbl_lock ) ;
}