2006-01-02 21:04:38 +03:00
/*
* net / tipc / name_table . c : TIPC name table code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 2000 - 2006 , Ericsson AB
2011-05-30 18:48:48 +04:00
* Copyright ( c ) 2004 - 2008 , 2010 - 2011 , Wind River Systems
2006-01-02 21:04:38 +03:00
* 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 "name_table.h"
# include "name_distr.h"
# include "subscr.h"
# include "port.h"
2006-03-21 09:37:52 +03:00
static int tipc_nametbl_size = 1024 ; /* must be a power of 2 */
2006-01-02 21:04:38 +03:00
/**
2011-05-30 17:44:38 +04:00
* struct name_info - name sequence publication info
2008-07-15 09:45:33 +04:00
* @ node_list : circular list of publications made by own node
* @ cluster_list : circular list of publications made by own cluster
* @ zone_list : circular list of publications made by own zone
* @ node_list_size : number of entries in " node_list "
* @ cluster_list_size : number of entries in " cluster_list "
* @ zone_list_size : number of entries in " zone_list "
*
* Note : The zone list always contains at least one entry , since all
* publications of the associated name sequence belong to it .
* ( The cluster and node lists may be empty . )
2006-01-02 21:04:38 +03:00
*/
2011-05-30 17:44:38 +04:00
struct name_info {
2011-05-30 18:48:48 +04:00
struct list_head node_list ;
struct list_head cluster_list ;
struct list_head zone_list ;
2008-07-15 09:45:33 +04:00
u32 node_list_size ;
u32 cluster_list_size ;
u32 zone_list_size ;
2006-01-02 21:04:38 +03:00
} ;
2011-05-30 17:44:38 +04:00
/**
* struct sub_seq - container for all published instances of a name sequence
* @ lower : name sequence lower bound
* @ upper : name sequence upper bound
* @ info : pointer to name sequence publication info
*/
struct sub_seq {
u32 lower ;
u32 upper ;
struct name_info * info ;
} ;
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* 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
2006-06-26 10:51:37 +04:00
* @ first_free : array index of first unused sub - sequence entry
2006-01-02 21:04:38 +03:00
* @ ns_list : links to adjacent name sequences in hash chain
* @ subscriptions : list of subscriptions for this ' type '
2008-06-05 04:38:22 +04:00
* @ lock : spinlock controlling access to publication lists of all sub - sequences
2006-01-02 21:04:38 +03:00
*/
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
2007-02-09 17:25:21 +03:00
* @ types : pointer to fixed - sized array of name sequence lists ,
2006-01-02 21:04:38 +03:00
* 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 ;
} ;
2010-12-31 21:59:34 +03:00
static struct name_table table ;
2006-06-27 13:53:55 +04:00
DEFINE_RWLOCK ( tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
2006-03-21 09:37:04 +03:00
static int hash ( int x )
2006-01-02 21:04:38 +03:00
{
2010-09-23 00:43:57 +04:00
return x & ( tipc_nametbl_size - 1 ) ;
2006-01-02 21:04:38 +03:00
}
/**
* publ_create - create a publication structure
*/
2007-02-09 17:25:21 +03:00
static struct publication * publ_create ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port_ref ,
2006-01-02 21:04:38 +03:00
u32 key )
{
2006-07-22 01:51:30 +04:00
struct publication * publ = kzalloc ( sizeof ( * publ ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
if ( publ = = NULL ) {
2006-06-26 10:52:17 +04:00
warn ( " Publication creation failure, no memory \n " ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
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 ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_subseq_alloc - allocate a specified number of sub - sequence structures
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct sub_seq * tipc_subseq_alloc ( u32 cnt )
2006-01-02 21:04:38 +03:00
{
2006-07-22 01:51:30 +04:00
struct sub_seq * sseq = kcalloc ( cnt , sizeof ( struct sub_seq ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
return sseq ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nameseq_create - create a name sequence structure for the specified ' type '
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Allocates a single sub - sequence structure and sets it to all 0 ' s .
*/
2006-03-21 09:37:52 +03:00
static struct name_seq * tipc_nameseq_create ( u32 type , struct hlist_head * seq_head )
2006-01-02 21:04:38 +03:00
{
2006-07-22 01:51:30 +04:00
struct name_seq * nseq = kzalloc ( sizeof ( * nseq ) , GFP_ATOMIC ) ;
2006-01-18 02:38:21 +03:00
struct sub_seq * sseq = tipc_subseq_alloc ( 1 ) ;
2006-01-02 21:04:38 +03:00
if ( ! nseq | | ! sseq ) {
2006-06-26 10:52:17 +04:00
warn ( " Name sequence creation failed, no memory \n " ) ;
2006-01-02 21:04:38 +03:00
kfree ( nseq ) ;
kfree ( sseq ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-06-27 13:53:55 +04:00
spin_lock_init ( & nseq - > lock ) ;
2006-01-02 21:04:38 +03:00
nseq - > type = type ;
nseq - > sseqs = sseq ;
nseq - > alloc = 1 ;
INIT_HLIST_NODE ( & nseq - > ns_list ) ;
INIT_LIST_HEAD ( & nseq - > subscriptions ) ;
hlist_add_head ( & nseq - > ns_list , seq_head ) ;
return nseq ;
}
2012-04-27 01:53:03 +04:00
/*
* nameseq_delete_empty - deletes a name sequence structure if now unused
*/
static void nameseq_delete_empty ( struct name_seq * seq )
{
if ( ! seq - > first_free & & list_empty ( & seq - > subscriptions ) ) {
hlist_del_init ( & seq - > ns_list ) ;
kfree ( seq - > sseqs ) ;
kfree ( seq ) ;
}
}
/*
2006-01-02 21:04:38 +03:00
* nameseq_find_subseq - find sub - sequence ( if any ) matching a name instance
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Very time - critical , so binary searches through sub - sequence array .
*/
2006-03-21 09:37:04 +03:00
static struct sub_seq * nameseq_find_subseq ( struct name_seq * nseq ,
u32 instance )
2006-01-02 21:04:38 +03:00
{
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 ] ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
* nameseq_locate_subseq - determine position of name instance in sub - sequence
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* 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 ;
}
/**
2012-04-30 23:29:02 +04:00
* tipc_nameseq_insert_publ
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct publication * tipc_nameseq_insert_publ ( struct name_seq * nseq ,
u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
2011-12-30 05:43:44 +04:00
struct tipc_subscription * s ;
struct tipc_subscription * st ;
2006-01-02 21:04:38 +03:00
struct publication * publ ;
struct sub_seq * sseq ;
2011-05-30 17:44:38 +04:00
struct name_info * info ;
2006-01-02 21:04:38 +03:00
int created_subseq = 0 ;
sseq = nameseq_find_subseq ( nseq , lower ) ;
if ( sseq ) {
/* Lower end overlaps existing entry => need an exact match */
if ( ( sseq - > lower ! = lower ) | | ( sseq - > upper ! = upper ) ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, overlap error \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2011-05-30 17:44:38 +04:00
info = sseq - > info ;
2011-11-03 19:12:01 +04:00
/* Check if an identical publication already exists */
list_for_each_entry ( publ , & info - > zone_list , zone_list ) {
if ( ( publ - > ref = = port ) & & ( publ - > key = = key ) & &
( ! publ - > node | | ( publ - > node = = node ) ) )
return NULL ;
}
2006-01-02 21:04:38 +03:00
} 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 ) ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, overlap error \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/* Ensure there is space for new sub-sequence */
if ( nseq - > first_free = = nseq - > alloc ) {
2006-06-26 10:37:24 +04:00
struct sub_seq * sseqs = tipc_subseq_alloc ( nseq - > alloc * 2 ) ;
if ( ! sseqs ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, no memory \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:37:24 +04:00
memcpy ( sseqs , nseq - > sseqs ,
nseq - > alloc * sizeof ( struct sub_seq ) ) ;
kfree ( nseq - > sseqs ) ;
nseq - > sseqs = sseqs ;
nseq - > alloc * = 2 ;
2006-01-02 21:04:38 +03:00
}
2011-05-30 17:44:38 +04:00
info = kzalloc ( sizeof ( * info ) , GFP_ATOMIC ) ;
if ( ! info ) {
warn ( " Cannot publish {%u,%u,%u}, no memory \n " ,
type , lower , upper ) ;
return NULL ;
}
2011-05-30 18:48:48 +04:00
INIT_LIST_HEAD ( & info - > node_list ) ;
INIT_LIST_HEAD ( & info - > cluster_list ) ;
INIT_LIST_HEAD ( & info - > zone_list ) ;
2006-01-02 21:04:38 +03:00
/* Insert new sub-sequence */
sseq = & nseq - > sseqs [ inspos ] ;
freesseq = & nseq - > sseqs [ nseq - > first_free ] ;
2010-12-31 21:59:32 +03:00
memmove ( sseq + 1 , sseq , ( freesseq - sseq ) * sizeof ( * sseq ) ) ;
memset ( sseq , 0 , sizeof ( * sseq ) ) ;
2006-01-02 21:04:38 +03:00
nseq - > first_free + + ;
sseq - > lower = lower ;
sseq - > upper = upper ;
2011-05-30 17:44:38 +04:00
sseq - > info = info ;
2006-01-02 21:04:38 +03:00
created_subseq = 1 ;
}
2012-04-30 23:29:02 +04:00
/* Insert a publication */
2006-01-02 21:04:38 +03:00
publ = publ_create ( type , lower , upper , scope , node , port , key ) ;
if ( ! publ )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2011-05-30 18:48:48 +04:00
list_add ( & publ - > zone_list , & info - > zone_list ) ;
2011-05-30 17:44:38 +04:00
info - > zone_list_size + + ;
2006-01-02 21:04:38 +03:00
2012-04-18 02:16:34 +04:00
if ( in_own_cluster ( node ) ) {
2011-05-30 18:48:48 +04:00
list_add ( & publ - > cluster_list , & info - > cluster_list ) ;
2011-05-30 17:44:38 +04:00
info - > cluster_list_size + + ;
2006-01-02 21:04:38 +03:00
}
2012-04-18 02:16:34 +04:00
if ( in_own_node ( node ) ) {
2011-05-30 18:48:48 +04:00
list_add ( & publ - > node_list , & info - > node_list ) ;
2011-05-30 17:44:38 +04:00
info - > node_list_size + + ;
2006-01-02 21:04:38 +03:00
}
2012-04-30 23:29:02 +04:00
/* Any subscriptions waiting for notification? */
2006-01-02 21:04:38 +03:00
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
2006-01-18 02:38:21 +03:00
tipc_subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
TIPC_PUBLISHED ,
2007-02-09 17:25:21 +03:00
publ - > ref ,
2006-01-18 02:38:21 +03:00
publ - > node ,
created_subseq ) ;
2006-01-02 21:04:38 +03:00
}
return publ ;
}
/**
2012-04-30 23:29:02 +04:00
* tipc_nameseq_remove_publ
2007-02-09 17:25:21 +03:00
*
2006-06-26 10:51:37 +04:00
* NOTE : There may be cases where TIPC is asked to remove a publication
* that is not in the name table . For example , if another node issues a
* publication for a name sequence that overlaps an existing name sequence
* the publication will not be recorded , which means the publication won ' t
* be found when the name sequence is later withdrawn by that node .
* A failed withdraw request simply returns a failure indication and lets the
* caller issue any error or warning messages associated with such a problem .
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct publication * tipc_nameseq_remove_publ ( struct name_seq * nseq , u32 inst ,
u32 node , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
struct sub_seq * sseq = nameseq_find_subseq ( nseq , inst ) ;
2011-05-30 17:44:38 +04:00
struct name_info * info ;
2006-01-02 21:04:38 +03:00
struct sub_seq * free ;
2011-12-30 05:43:44 +04:00
struct tipc_subscription * s , * st ;
2006-01-02 21:04:38 +03:00
int removed_subseq = 0 ;
2006-06-26 10:51:37 +04:00
if ( ! sseq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-06-26 10:51:37 +04:00
2011-05-30 17:44:38 +04:00
info = sseq - > info ;
2011-05-30 18:48:48 +04:00
/* Locate publication, if it exists */
list_for_each_entry ( publ , & info - > zone_list , zone_list ) {
if ( ( publ - > key = = key ) & & ( publ - > ref = = ref ) & &
( ! publ - > node | | ( publ - > node = = node ) ) )
goto found ;
}
return NULL ;
2007-02-09 17:25:21 +03:00
2011-05-30 18:48:48 +04:00
found :
/* Remove publication from zone scope list */
list_del ( & publ - > zone_list ) ;
2011-05-30 17:44:38 +04:00
info - > zone_list_size - - ;
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
/* Remove publication from cluster scope list, if present */
2012-04-18 02:16:34 +04:00
if ( in_own_cluster ( node ) ) {
2011-05-30 18:48:48 +04:00
list_del ( & publ - > cluster_list ) ;
2011-05-30 17:44:38 +04:00
info - > cluster_list_size - - ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
/* Remove publication from node scope list, if present */
2012-04-18 02:16:34 +04:00
if ( in_own_node ( node ) ) {
2011-05-30 18:48:48 +04:00
list_del ( & publ - > node_list ) ;
2011-05-30 17:44:38 +04:00
info - > node_list_size - - ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
/* Contract subseq list if no more publications for that subseq */
2011-05-30 18:48:48 +04:00
if ( list_empty ( & info - > zone_list ) ) {
2011-05-30 17:44:38 +04:00
kfree ( info ) ;
2006-01-02 21:04:38 +03:00
free = & nseq - > sseqs [ nseq - > first_free - - ] ;
2010-12-31 21:59:32 +03:00
memmove ( sseq , sseq + 1 , ( free - ( sseq + 1 ) ) * sizeof ( * sseq ) ) ;
2006-01-02 21:04:38 +03:00
removed_subseq = 1 ;
}
2006-06-26 10:51:37 +04:00
/* Notify any waiting subscriptions */
2006-01-02 21:04:38 +03:00
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
2006-01-18 02:38:21 +03:00
tipc_subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
2007-02-09 17:25:21 +03:00
TIPC_WITHDRAWN ,
publ - > ref ,
2006-01-18 02:38:21 +03:00
publ - > node ,
removed_subseq ) ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
2006-01-02 21:04:38 +03:00
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nameseq_subscribe : attach a subscription , and issue
2006-01-02 21:04:38 +03:00
* the prescribed number of events if there is any sub -
* sequence overlapping with the requested sequence
*/
2011-12-30 05:43:44 +04:00
static void tipc_nameseq_subscribe ( struct name_seq * nseq ,
struct tipc_subscription * s )
2006-01-02 21:04:38 +03:00
{
struct sub_seq * sseq = nseq - > sseqs ;
list_add ( & s - > nameseq_list , & nseq - > subscriptions ) ;
if ( ! sseq )
return ;
while ( sseq ! = & nseq - > sseqs [ nseq - > first_free ] ) {
2011-05-30 18:48:48 +04:00
if ( tipc_subscr_overlap ( s , sseq - > lower , sseq - > upper ) ) {
struct publication * crs ;
struct name_info * info = sseq - > info ;
2006-01-02 21:04:38 +03:00
int must_report = 1 ;
2011-05-30 18:48:48 +04:00
list_for_each_entry ( crs , & info - > zone_list , zone_list ) {
2007-02-09 17:25:21 +03:00
tipc_subscr_report_overlap ( s ,
sseq - > lower ,
2006-01-18 02:38:21 +03:00
sseq - > upper ,
TIPC_PUBLISHED ,
crs - > ref ,
crs - > node ,
must_report ) ;
2006-01-02 21:04:38 +03:00
must_report = 0 ;
2011-05-30 18:48:48 +04:00
}
2006-01-02 21:04:38 +03:00
}
sseq + + ;
}
}
static struct name_seq * nametbl_find_seq ( u32 type )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct name_seq * ns ;
seq_head = & table . types [ hash ( type ) ] ;
hlist_for_each_entry ( ns , seq_node , seq_head , ns_list ) {
2010-12-31 21:59:25 +03:00
if ( ns - > type = = type )
2006-01-02 21:04:38 +03:00
return ns ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
} ;
2006-01-18 02:38:21 +03:00
struct publication * tipc_nametbl_insert_publ ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq = nametbl_find_seq ( type ) ;
2012-04-27 01:57:17 +04:00
if ( ( scope < TIPC_ZONE_SCOPE ) | | ( scope > TIPC_NODE_SCOPE ) | |
( lower > upper ) ) {
dbg ( " Failed to publish illegal {%u,%u,%u} with scope %u \n " ,
type , lower , upper , scope ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2010-12-31 21:59:25 +03:00
if ( ! seq )
2006-01-18 02:38:21 +03:00
seq = tipc_nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
2006-01-02 21:04:38 +03:00
if ( ! seq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
return tipc_nameseq_insert_publ ( seq , type , lower , upper ,
scope , node , port , key ) ;
2006-01-02 21:04:38 +03:00
}
2007-02-09 17:25:21 +03:00
struct publication * tipc_nametbl_remove_publ ( u32 type , u32 lower ,
2006-01-18 02:38:21 +03:00
u32 node , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
struct name_seq * seq = nametbl_find_seq ( type ) ;
if ( ! seq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
publ = tipc_nameseq_remove_publ ( seq , lower , node , ref , key ) ;
2012-04-27 01:53:03 +04:00
nameseq_delete_empty ( seq ) ;
2006-01-02 21:04:38 +03:00
return publ ;
}
/*
2011-11-08 02:00:54 +04:00
* tipc_nametbl_translate - perform name translation
2006-01-02 21:04:38 +03:00
*
2011-11-08 02:00:54 +04:00
* On entry , ' destnode ' is the search domain used during translation .
*
* On exit :
* - if name translation is deferred to another node / cluster / zone ,
* leaves ' destnode ' unchanged ( will be non - zero ) and returns 0
* - if name translation is attempted and succeeds , sets ' destnode '
* to publishing node and returns port reference ( will be non - zero )
* - if name translation is attempted and fails , sets ' destnode ' to 0
* and returns 0
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
u32 tipc_nametbl_translate ( u32 type , u32 instance , u32 * destnode )
2006-01-02 21:04:38 +03:00
{
struct sub_seq * sseq ;
2011-05-30 17:44:38 +04:00
struct name_info * info ;
2011-05-30 18:48:48 +04:00
struct publication * publ ;
2006-01-02 21:04:38 +03:00
struct name_seq * seq ;
2011-05-30 18:48:48 +04:00
u32 ref = 0 ;
2011-11-08 02:00:54 +04:00
u32 node = 0 ;
2006-01-02 21:04:38 +03:00
2010-05-11 18:30:12 +04:00
if ( ! tipc_in_scope ( * destnode , tipc_own_addr ) )
2006-01-02 21:04:38 +03:00
return 0 ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
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 ) ;
2011-05-30 17:44:38 +04:00
info = sseq - > info ;
2006-01-02 21:04:38 +03:00
2012-04-30 23:29:02 +04:00
/* Closest-First Algorithm */
2006-01-02 21:04:38 +03:00
if ( likely ( ! * destnode ) ) {
2011-05-30 18:48:48 +04:00
if ( ! list_empty ( & info - > node_list ) ) {
publ = list_first_entry ( & info - > node_list ,
struct publication ,
node_list ) ;
list_move_tail ( & publ - > node_list ,
& info - > node_list ) ;
} else if ( ! list_empty ( & info - > cluster_list ) ) {
publ = list_first_entry ( & info - > cluster_list ,
struct publication ,
cluster_list ) ;
list_move_tail ( & publ - > cluster_list ,
& info - > cluster_list ) ;
2011-05-30 19:27:50 +04:00
} else {
2011-05-30 18:48:48 +04:00
publ = list_first_entry ( & info - > zone_list ,
struct publication ,
zone_list ) ;
list_move_tail ( & publ - > zone_list ,
& info - > zone_list ) ;
2011-05-30 19:27:50 +04:00
}
2006-01-02 21:04:38 +03:00
}
2012-04-30 23:29:02 +04:00
/* Round-Robin Algorithm */
2006-01-02 21:04:38 +03:00
else if ( * destnode = = tipc_own_addr ) {
2011-05-30 18:48:48 +04:00
if ( list_empty ( & info - > node_list ) )
goto no_match ;
publ = list_first_entry ( & info - > node_list , struct publication ,
node_list ) ;
list_move_tail ( & publ - > node_list , & info - > node_list ) ;
2012-04-18 02:02:01 +04:00
} else if ( in_own_cluster_exact ( * destnode ) ) {
2011-05-30 18:48:48 +04:00
if ( list_empty ( & info - > cluster_list ) )
goto no_match ;
publ = list_first_entry ( & info - > cluster_list , struct publication ,
cluster_list ) ;
list_move_tail ( & publ - > cluster_list , & info - > cluster_list ) ;
2006-01-02 21:04:38 +03:00
} else {
2011-05-30 18:48:48 +04:00
publ = list_first_entry ( & info - > zone_list , struct publication ,
zone_list ) ;
list_move_tail ( & publ - > zone_list , & info - > zone_list ) ;
2006-01-02 21:04:38 +03:00
}
2011-05-30 18:48:48 +04:00
ref = publ - > ref ;
2011-11-08 02:00:54 +04:00
node = publ - > node ;
2011-05-30 18:48:48 +04:00
no_match :
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & seq - > lock ) ;
not_found :
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2011-11-08 02:00:54 +04:00
* destnode = node ;
2011-05-30 18:48:48 +04:00
return ref ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_mc_translate - find multicast destinations
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* 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 )
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns non - zero if any off - node ports overlap
*/
2006-01-18 02:38:21 +03:00
int tipc_nametbl_mc_translate ( u32 type , u32 lower , u32 upper , u32 limit ,
2011-12-30 05:33:30 +04:00
struct tipc_port_list * dports )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq ;
struct sub_seq * sseq ;
struct sub_seq * sseq_stop ;
2011-05-30 17:44:38 +04:00
struct name_info * info ;
2006-01-02 21:04:38 +03:00
int res = 0 ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
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 ;
2008-07-15 09:45:33 +04:00
2011-05-30 17:44:38 +04:00
info = sseq - > info ;
2011-05-30 18:48:48 +04:00
list_for_each_entry ( publ , & info - > node_list , node_list ) {
if ( publ - > scope < = limit )
tipc_port_list_add ( dports , publ - > ref ) ;
2008-07-15 09:45:33 +04:00
}
2011-05-30 17:44:38 +04:00
if ( info - > cluster_list_size ! = info - > node_list_size )
2008-07-15 09:45:33 +04:00
res = 1 ;
2006-01-02 21:04:38 +03:00
}
spin_unlock_bh ( & seq - > lock ) ;
exit :
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
2011-11-02 23:49:40 +04:00
/*
2006-01-18 02:38:21 +03:00
* tipc_nametbl_publish - add name publication to network name tables
2006-01-02 21:04:38 +03:00
*/
2007-02-09 17:25:21 +03:00
struct publication * tipc_nametbl_publish ( u32 type , u32 lower , u32 upper ,
2006-01-02 21:04:38 +03:00
u32 scope , u32 port_ref , u32 key )
{
struct publication * publ ;
if ( table . local_publ_count > = tipc_max_publications ) {
2007-02-09 17:25:21 +03:00
warn ( " Publication failed, local publication limit reached (%u) \n " ,
2006-01-02 21:04:38 +03:00
tipc_max_publications ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
publ = tipc_nametbl_insert_publ ( type , lower , upper , scope ,
2006-01-02 21:04:38 +03:00
tipc_own_addr , port_ref , key ) ;
2011-11-09 23:22:52 +04:00
if ( likely ( publ ) ) {
table . local_publ_count + + ;
2006-01-18 02:38:21 +03:00
tipc_named_publish ( publ ) ;
2011-11-09 23:22:52 +04:00
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_withdraw - withdraw name publication from network name tables
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_nametbl_withdraw ( u32 type , u32 lower , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
publ = tipc_nametbl_remove_publ ( type , lower , tipc_own_addr , ref , key ) ;
2006-06-26 10:51:37 +04:00
if ( likely ( publ ) ) {
2006-01-02 21:04:38 +03:00
table . local_publ_count - - ;
2012-04-18 01:57:52 +04:00
tipc_named_withdraw ( publ ) ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
list_del_init ( & publ - > pport_list ) ;
kfree ( publ ) ;
return 1 ;
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-06-26 10:51:37 +04:00
err ( " Unable to remove local publication \n "
" (type=%u, lower=%u, ref=%u, key=%u) \n " ,
type , lower , ref , key ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_subscribe - add a subscription object to the name table
2006-01-02 21:04:38 +03:00
*/
2011-12-30 05:43:44 +04:00
void tipc_nametbl_subscribe ( struct tipc_subscription * s )
2006-01-02 21:04:38 +03:00
{
u32 type = s - > seq . type ;
struct name_seq * seq ;
2007-02-09 17:25:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
seq = nametbl_find_seq ( type ) ;
2010-12-31 21:59:35 +03:00
if ( ! seq )
2006-01-18 02:38:21 +03:00
seq = tipc_nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
2010-12-31 21:59:32 +03:00
if ( seq ) {
2007-02-09 17:25:21 +03:00
spin_lock_bh ( & seq - > lock ) ;
tipc_nameseq_subscribe ( seq , s ) ;
spin_unlock_bh ( & seq - > lock ) ;
} else {
2006-06-26 10:51:37 +04:00
warn ( " Failed to create subscription for {%u,%u,%u} \n " ,
s - > seq . type , s - > seq . lower , s - > seq . upper ) ;
2007-02-09 17:25:21 +03:00
}
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_unsubscribe - remove a subscription object from name table
2006-01-02 21:04:38 +03:00
*/
2011-12-30 05:43:44 +04:00
void tipc_nametbl_unsubscribe ( struct tipc_subscription * s )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq ;
2007-02-09 17:25:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
seq = nametbl_find_seq ( s - > seq . type ) ;
2010-12-31 21:59:32 +03:00
if ( seq ! = NULL ) {
2007-02-09 17:25:21 +03:00
spin_lock_bh ( & seq - > lock ) ;
list_del_init ( & s - > nameseq_list ) ;
spin_unlock_bh ( & seq - > lock ) ;
2012-04-27 01:53:03 +04:00
nameseq_delete_empty ( seq ) ;
2007-02-09 17:25:21 +03:00
}
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
/**
* 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 ] ;
2010-08-17 15:00:14 +04:00
const char * scope_str [ ] = { " " , " zone " , " cluster " , " node " } ;
2011-05-30 18:48:48 +04:00
struct publication * publ ;
struct name_info * info ;
2006-01-02 21:04:38 +03:00
tipc_printf ( buf , " %-10u %-10u " , sseq - > lower , sseq - > upper ) ;
2011-05-30 18:48:48 +04:00
if ( depth = = 2 ) {
2006-01-02 21:04:38 +03:00
tipc_printf ( buf , " \n " ) ;
return ;
}
2011-05-30 18:48:48 +04:00
info = sseq - > info ;
list_for_each_entry ( publ , & info - > zone_list , zone_list ) {
2010-12-31 21:59:32 +03:00
sprintf ( portIdStr , " <%u.%u.%u:%u> " ,
2006-01-02 21:04:38 +03:00
tipc_zone ( publ - > node ) , tipc_cluster ( publ - > node ) ,
tipc_node ( publ - > node ) , publ - > ref ) ;
tipc_printf ( buf , " %-26s " , portIdStr ) ;
if ( depth > 3 ) {
2010-08-17 15:00:14 +04:00
tipc_printf ( buf , " %-10u %s " , publ - > key ,
scope_str [ publ - > scope ] ) ;
2006-01-02 21:04:38 +03:00
}
2011-05-30 18:48:48 +04:00
if ( ! list_is_last ( & publ - > zone_list , & info - > zone_list ) )
tipc_printf ( buf , " \n %33s " , " " ) ;
} ;
2006-01-02 21:04:38 +03:00
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 ] ;
2008-06-05 04:37:59 +04:00
if ( seq - > first_free = = 0 )
return ;
2006-01-02 21:04:38 +03:00
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 ) ;
2008-06-05 04:38:22 +04:00
spin_lock_bh ( & seq - > lock ) ;
2006-01-02 21:04:38 +03:00
subseq_list ( sseq , buf , depth , index ) ;
2008-06-05 04:38:22 +04:00
spin_unlock_bh ( & seq - > lock ) ;
2006-01-02 21:04:38 +03:00
sprintf ( typearea , " %10s " , " " ) ;
}
}
}
/**
* nametbl_header - print name table header into the given buffer
*/
static void nametbl_header ( struct print_buf * buf , u32 depth )
{
2010-08-17 15:00:14 +04:00
const char * header [ ] = {
" Type " ,
" Lower Upper " ,
" Port Identity " ,
" Publication Scope "
} ;
int i ;
if ( depth > 4 )
depth = 4 ;
for ( i = 0 ; i < depth ; i + + )
tipc_printf ( buf , header [ i ] ) ;
2006-01-02 21:04:38 +03:00
tipc_printf ( buf , " \n " ) ;
}
/**
* nametbl_list - print specified name table contents into the given buffer
*/
2007-02-09 17:25:21 +03:00
static void nametbl_list ( struct print_buf * buf , u32 depth_info ,
2006-01-02 21:04:38 +03:00
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 ) {
2007-02-09 17:25:21 +03:00
nameseq_list ( seq , buf , depth , seq - > type ,
2006-01-02 21:04:38 +03:00
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 ) {
2007-02-09 17:25:21 +03:00
nameseq_list ( seq , buf , depth , type ,
2006-01-02 21:04:38 +03:00
lowbound , upbound , i ) ;
break ;
}
}
}
}
# define MAX_NAME_TBL_QUERY 32768
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_nametbl_get ( const void * req_tlv_area , int req_tlv_space )
2006-01-02 21:04:38 +03:00
{
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 ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( MAX_NAME_TBL_QUERY ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_init ( & b , TLV_DATA ( rep_tlv ) , MAX_NAME_TBL_QUERY ) ;
2006-01-02 21:04:38 +03:00
argv = ( struct tipc_name_table_query * ) TLV_DATA ( req_tlv_area ) ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2007-02-09 17:25:21 +03:00
nametbl_list ( & b , ntohl ( argv - > depth ) , ntohl ( argv - > type ) ,
2006-01-02 21:04:38 +03:00
ntohl ( argv - > lowbound ) , ntohl ( argv - > upbound ) ) ;
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
str_len = tipc_printbuf_validate ( & b ) ;
2006-01-02 21:04:38 +03:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
2006-01-18 02:38:21 +03:00
int tipc_nametbl_init ( void )
2006-01-02 21:04:38 +03:00
{
2008-05-13 02:41:53 +04:00
table . types = kcalloc ( tipc_nametbl_size , sizeof ( struct hlist_head ) ,
GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
if ( ! table . types )
return - ENOMEM ;
table . local_publ_count = 0 ;
return 0 ;
}
2006-01-18 02:38:21 +03:00
void tipc_nametbl_stop ( void )
2006-01-02 21:04:38 +03:00
{
u32 i ;
if ( ! table . types )
return ;
2006-06-26 10:51:37 +04:00
/* Verify name table is empty, then release it */
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
for ( i = 0 ; i < tipc_nametbl_size ; i + + ) {
2006-06-26 10:51:37 +04:00
if ( ! hlist_empty ( & table . types [ i ] ) )
err ( " tipc_nametbl_stop(): hash chain %u is non-null \n " , i ) ;
2006-01-02 21:04:38 +03:00
}
kfree ( table . types ) ;
table . types = NULL ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}