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
*
2018-03-15 18:48:55 +03:00
* Copyright ( c ) 2000 - 2006 , 2014 - 2018 , Ericsson AB
2014-12-02 10:00:24 +03:00
* Copyright ( c ) 2004 - 2008 , 2010 - 2014 , 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 .
*/
2015-01-09 10:27:09 +03:00
# include <net/sock.h>
2006-01-02 21:04:38 +03:00
# include "core.h"
2015-02-09 11:50:18 +03:00
# include "netlink.h"
2006-01-02 21:04:38 +03:00
# include "name_table.h"
# include "name_distr.h"
# include "subscr.h"
2015-01-09 10:27:07 +03:00
# include "bcast.h"
2015-02-09 11:50:18 +03:00
# include "addr.h"
2015-11-19 22:30:42 +03:00
# include "node.h"
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
# include "group.h"
2006-01-02 21:04:38 +03:00
/**
2018-03-30 00:20:41 +03:00
* struct service_range - container for all bindings of a service range
* @ lower : service range lower bound
* @ upper : service range upper bound
* @ tree_node : member of service range RB tree
* @ local_publ : list of identical publications made from this node
* Used by closest_first lookup and multicast lookup algorithm
* @ all_publ : all publications identical to this one , whatever node and scope
* Used by round - robin lookup algorithm
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
struct service_range {
2011-05-30 17:44:38 +04:00
u32 lower ;
u32 upper ;
2018-03-30 00:20:41 +03:00
struct rb_node tree_node ;
struct list_head local_publ ;
struct list_head all_publ ;
2011-05-30 17:44:38 +04:00
} ;
2007-02-09 17:25:21 +03:00
/**
2018-03-30 00:20:41 +03:00
* struct tipc_service - container for all published instances of a service type
* @ type : 32 bit ' type ' value for service
* @ ranges : rb tree containing all service ranges for this service
* @ service_list : links to adjacent name ranges in hash chain
* @ subscriptions : list of subscriptions for this service type
* @ lock : spinlock controlling access to pertaining service ranges / publications
2014-12-02 10:00:30 +03:00
* @ rcu : RCU callback head used for deferred freeing
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
struct tipc_service {
2006-01-02 21:04:38 +03:00
u32 type ;
2018-03-30 00:20:41 +03:00
struct rb_root ranges ;
struct hlist_node service_list ;
2006-01-02 21:04:38 +03:00
struct list_head subscriptions ;
2018-03-30 00:20:41 +03:00
spinlock_t lock ; /* Covers service range list */
2014-12-02 10:00:30 +03:00
struct rcu_head rcu ;
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
{
2012-08-16 16:09:11 +04:00
return x & ( TIPC_NAMETBL_SIZE - 1 ) ;
2006-01-02 21:04:38 +03:00
}
/**
2018-03-30 00:20:41 +03:00
* tipc_publ_create - create a publication structure
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
static struct publication * tipc_publ_create ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port ,
u32 key )
2006-01-02 21:04:38 +03:00
{
2006-07-22 01:51:30 +04:00
struct publication * publ = kzalloc ( sizeof ( * publ ) , GFP_ATOMIC ) ;
2018-03-30 00:20:41 +03:00
if ( ! publ )
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 ;
2018-03-15 18:48:55 +03:00
publ - > port = port ;
2006-01-02 21:04:38 +03:00
publ - > key = key ;
2018-03-15 18:48:55 +03:00
INIT_LIST_HEAD ( & publ - > binding_sock ) ;
2018-03-30 00:20:41 +03:00
INIT_LIST_HEAD ( & publ - > binding_node ) ;
INIT_LIST_HEAD ( & publ - > local_publ ) ;
INIT_LIST_HEAD ( & publ - > all_publ ) ;
2006-01-02 21:04:38 +03:00
return publ ;
}
/**
2018-03-30 00:20:41 +03:00
* tipc_service_create - create a service structure for the specified ' type '
2007-02-09 17:25:21 +03:00
*
2018-03-30 00:20:41 +03:00
* Allocates a single range structure and sets it to all 0 ' s .
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
static struct tipc_service * tipc_service_create ( u32 type , struct hlist_head * hd )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_service * service = kzalloc ( sizeof ( * service ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
if ( ! service ) {
pr_warn ( " Service creation failed, no memory \n " ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
spin_lock_init ( & service - > lock ) ;
service - > type = type ;
service - > ranges = RB_ROOT ;
INIT_HLIST_NODE ( & service - > service_list ) ;
INIT_LIST_HEAD ( & service - > subscriptions ) ;
hlist_add_head_rcu ( & service - > service_list , hd ) ;
return service ;
2006-01-02 21:04:38 +03:00
}
2012-07-10 14:55:09 +04:00
/**
2018-03-30 00:20:41 +03:00
* tipc_service_find_range - find service range matching a service instance
2007-02-09 17:25:21 +03:00
*
2018-03-30 00:20:41 +03:00
* Very time - critical , so binary search through range rb tree
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
static struct service_range * tipc_service_find_range ( struct tipc_service * sc ,
u32 instance )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct rb_node * n = sc - > ranges . rb_node ;
struct service_range * sr ;
while ( n ) {
sr = container_of ( n , struct service_range , tree_node ) ;
if ( sr - > lower > instance )
n = n - > rb_left ;
else if ( sr - > upper < instance )
n = n - > rb_right ;
2006-01-02 21:04:38 +03:00
else
2018-03-30 00:20:41 +03:00
return sr ;
2006-01-02 21:04:38 +03:00
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
static struct service_range * tipc_service_create_range ( struct tipc_service * sc ,
u32 lower , u32 upper )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct rb_node * * n , * parent = NULL ;
struct service_range * sr , * tmp ;
n = & sc - > ranges . rb_node ;
while ( * n ) {
tmp = container_of ( * n , struct service_range , tree_node ) ;
parent = * n ;
tmp = container_of ( parent , struct service_range , tree_node ) ;
if ( lower < tmp - > lower )
n = & ( * n ) - > rb_left ;
else if ( upper > tmp - > upper )
n = & ( * n ) - > rb_right ;
2006-01-02 21:04:38 +03:00
else
2018-03-30 00:20:41 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
sr = kzalloc ( sizeof ( * sr ) , GFP_ATOMIC ) ;
if ( ! sr )
return NULL ;
sr - > lower = lower ;
sr - > upper = upper ;
INIT_LIST_HEAD ( & sr - > local_publ ) ;
INIT_LIST_HEAD ( & sr - > all_publ ) ;
rb_link_node ( & sr - > tree_node , parent , n ) ;
rb_insert_color ( & sr - > tree_node , & sc - > ranges ) ;
return sr ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
static struct publication * tipc_service_insert_publ ( struct net * net ,
struct tipc_service * sc ,
2015-01-09 10:27:10 +03:00
u32 type , u32 lower ,
u32 upper , u32 scope ,
2018-03-30 00:20:41 +03:00
u32 node , u32 port ,
u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_subscription * sub , * tmp ;
struct service_range * sr ;
struct publication * p ;
bool first = false ;
2011-05-30 17:44:38 +04:00
2018-03-30 00:20:41 +03:00
sr = tipc_service_find_range ( sc , lower ) ;
if ( ! sr ) {
sr = tipc_service_create_range ( sc , lower , upper ) ;
if ( ! sr )
goto err ;
first = true ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
/* Lower end overlaps existing entry, but we need an exact match */
if ( sr - > lower ! = lower | | sr - > upper ! = upper )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
/* Return if the publication already exists */
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
if ( p - > key = = key & & ( ! p - > node | | p - > node = = node ) )
return NULL ;
}
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
/* Create and insert publication */
p = tipc_publ_create ( type , lower , upper , scope , node , port , key ) ;
if ( ! p )
goto err ;
2018-03-15 18:48:53 +03:00
if ( in_own_node ( net , node ) )
2018-03-30 00:20:41 +03:00
list_add ( & p - > local_publ , & sr - > local_publ ) ;
list_add ( & p - > all_publ , & sr - > all_publ ) ;
2006-01-02 21:04:38 +03:00
2012-04-30 23:29:02 +04:00
/* Any subscriptions waiting for notification? */
2018-03-30 00:20:41 +03:00
list_for_each_entry_safe ( sub , tmp , & sc - > subscriptions , service_list ) {
tipc_sub_report_overlap ( sub , p - > lower , p - > upper , TIPC_PUBLISHED ,
p - > port , p - > node , p - > scope , first ) ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
return p ;
err :
pr_warn ( " Failed to bind to %u,%u,%u, no memory \n " , type , lower , upper ) ;
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
2018-03-30 00:20:41 +03:00
* tipc_service_remove_publ - remove a publication from a service
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
2018-03-30 00:20:41 +03:00
* publication for a name range that overlaps an existing name range
2006-06-26 10:51:37 +04:00
* the publication will not be recorded , which means the publication won ' t
2018-03-30 00:20:41 +03:00
* be found when the name range is later withdrawn by that node .
2006-06-26 10:51:37 +04:00
* 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
*/
2018-03-30 00:20:41 +03:00
static struct publication * tipc_service_remove_publ ( struct net * net ,
struct tipc_service * sc ,
2015-01-09 10:27:10 +03:00
u32 inst , u32 node ,
2018-03-15 18:48:55 +03:00
u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_subscription * sub , * tmp ;
struct service_range * sr ;
struct publication * p ;
bool found = false ;
bool last = false ;
2006-06-26 10:51:37 +04:00
2018-03-30 00:20:41 +03:00
sr = tipc_service_find_range ( sc , inst ) ;
if ( ! sr )
return NULL ;
2011-05-30 17:44:38 +04:00
2018-03-30 00:20:41 +03:00
/* Find publication, if it exists */
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
if ( p - > key ! = key | | ( node & & node ! = p - > node ) )
continue ;
found = true ;
break ;
2011-05-30 18:48:48 +04:00
}
2018-03-30 00:20:41 +03:00
if ( ! found )
return NULL ;
2007-02-09 17:25:21 +03:00
2018-03-30 00:20:41 +03:00
list_del ( & p - > all_publ ) ;
list_del ( & p - > local_publ ) ;
/* Remove service range item if this was its last publication */
if ( list_empty ( & sr - > all_publ ) ) {
last = true ;
rb_erase ( & sr - > tree_node , & sc - > ranges ) ;
kfree ( sr ) ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
/* Notify any waiting subscriptions */
2018-03-30 00:20:41 +03:00
list_for_each_entry_safe ( sub , tmp , & sc - > subscriptions , service_list ) {
tipc_sub_report_overlap ( sub , p - > lower , p - > upper , TIPC_WITHDRAWN ,
p - > port , p - > node , p - > scope , last ) ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
return p ;
2006-01-02 21:04:38 +03:00
}
/**
2018-03-30 00:20:41 +03:00
* tipc_service_subscribe - attach a subscription , and optionally
* issue the prescribed number of events if there is any service
* range overlapping with the requested range
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
static void tipc_service_subscribe ( struct tipc_service * service ,
2018-02-15 12:40:46 +03:00
struct tipc_subscription * sub )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_subscr * sb = & sub - > evt . s ;
struct service_range * sr ;
2016-02-02 12:52:10 +03:00
struct tipc_name_seq ns ;
2018-03-30 00:20:41 +03:00
struct publication * p ;
struct rb_node * n ;
bool first ;
2016-02-02 12:52:10 +03:00
2018-03-30 00:20:41 +03:00
ns . type = tipc_sub_read ( sb , seq . type ) ;
ns . lower = tipc_sub_read ( sb , seq . lower ) ;
ns . upper = tipc_sub_read ( sb , seq . upper ) ;
2006-01-02 21:04:38 +03:00
2018-02-15 12:40:48 +03:00
tipc_sub_get ( sub ) ;
2018-03-30 00:20:41 +03:00
list_add ( & sub - > service_list , & service - > subscriptions ) ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
if ( tipc_sub_read ( sb , filter ) & TIPC_SUB_NO_STATUS )
2006-01-02 21:04:38 +03:00
return ;
2018-03-30 00:20:41 +03:00
for ( n = rb_first ( & service - > ranges ) ; n ; n = rb_next ( n ) ) {
sr = container_of ( n , struct service_range , tree_node ) ;
if ( sr - > lower > ns . upper )
break ;
if ( ! tipc_sub_check_overlap ( & ns , sr - > lower , sr - > upper ) )
continue ;
first = true ;
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
tipc_sub_report_overlap ( sub , sr - > lower , sr - > upper ,
TIPC_PUBLISHED , p - > port ,
p - > node , p - > scope , first ) ;
first = false ;
2006-01-02 21:04:38 +03:00
}
}
}
2018-03-30 00:20:41 +03:00
static struct tipc_service * tipc_service_find ( struct net * net , u32 type )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( net ) ;
struct hlist_head * service_head ;
struct tipc_service * service ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
service_head = & nt - > services [ hash ( type ) ] ;
hlist_for_each_entry_rcu ( service , service_head , service_list ) {
if ( service - > type = = type )
return service ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
} ;
2015-01-09 10:27:09 +03:00
struct publication * tipc_nametbl_insert_publ ( struct net * net , u32 type ,
2018-03-30 00:20:41 +03:00
u32 lower , u32 upper ,
u32 scope , u32 node ,
u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( net ) ;
struct tipc_service * sc ;
struct publication * p ;
2006-01-02 21:04:38 +03:00
2018-03-15 18:48:51 +03:00
if ( scope > TIPC_NODE_SCOPE | | lower > upper ) {
2018-03-30 00:20:41 +03:00
pr_debug ( " Failed to bind illegal {%u,%u,%u} with scope %u \n " ,
2012-06-29 08:16:37 +04:00
type , lower , upper , scope ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( ! sc )
sc = tipc_service_create ( type , & nt - > services [ hash ( type ) ] ) ;
if ( ! sc )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
p = tipc_service_insert_publ ( net , sc , type , lower , upper ,
scope , node , port , key ) ;
spin_unlock_bh ( & sc - > lock ) ;
return p ;
2006-01-02 21:04:38 +03:00
}
2015-01-09 10:27:09 +03:00
struct publication * tipc_nametbl_remove_publ ( struct net * net , u32 type ,
2018-03-30 00:20:41 +03:00
u32 lower , u32 node , u32 port ,
u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_service * sc = tipc_service_find ( net , type ) ;
struct publication * p = NULL ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
if ( ! sc )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
p = tipc_service_remove_publ ( net , sc , lower , node , port , key ) ;
/* Delete service item if this no more publications and subscriptions */
if ( RB_EMPTY_ROOT ( & sc - > ranges ) & & list_empty ( & sc - > subscriptions ) ) {
hlist_del_init_rcu ( & sc - > service_list ) ;
kfree_rcu ( sc , rcu ) ;
2014-12-02 10:00:26 +03:00
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
return p ;
2006-01-02 21:04:38 +03:00
}
2012-07-10 14:55:09 +04:00
/**
2018-03-30 00:20:41 +03:00
* tipc_nametbl_translate - perform service instance to socket 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 '
2018-03-30 00:20:41 +03:00
* to publication node and returns port reference ( will be non - zero )
2011-11-08 02:00:54 +04:00
* - if name translation is attempted and fails , sets ' destnode ' to 0
* and returns 0
2006-01-02 21:04:38 +03:00
*/
2015-01-09 10:27:09 +03:00
u32 tipc_nametbl_translate ( struct net * net , u32 type , u32 instance ,
u32 * destnode )
2006-01-02 21:04:38 +03:00
{
tipc: allow closest-first lookup algorithm when legacy address is configured
The removal of an internal structure of the node address has an unwanted
side effect.
- Currently, if a user is sending an anycast message with destination
domain 0, the tipc_namebl_translate() function will use the 'closest-
first' algorithm to first look for a node local destination, and only
when no such is found, will it resort to the cluster global 'round-
robin' lookup algorithm.
- Current users can get around this, and enforce unconditional use of
global round-robin by indicating a destination as Z.0.0 or Z.C.0.
- This option disappears when we make the node address flat, since the
lookup algorithm has no way of recognizing this case. So, as long as
there are node local destinations, the algorithm will always select
one of those, and there is nothing the sender can do to change this.
We solve this by eliminating the 'closest-first' option, which was never
a good idea anyway, for non-legacy users, but only for those. To
distinguish between legacy users and non-legacy users we introduce a new
flag 'legacy_addr_format' in struct tipc_core, to be set when the user
configures a legacy-style Z.C.N node address. Hence, when a legacy user
indicates a zero lookup domain 'closest-first' is selected, and in all
other cases we use 'round-robin'.
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-03-22 22:42:48 +03:00
struct tipc_net * tn = tipc_net ( net ) ;
bool legacy = tn - > legacy_addr_format ;
u32 self = tipc_own_addr ( net ) ;
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct tipc_service * sc ;
struct publication * p ;
2018-03-15 18:48:55 +03:00
u32 port = 0 ;
2011-11-08 02:00:54 +04:00
u32 node = 0 ;
2006-01-02 21:04:38 +03:00
tipc: allow closest-first lookup algorithm when legacy address is configured
The removal of an internal structure of the node address has an unwanted
side effect.
- Currently, if a user is sending an anycast message with destination
domain 0, the tipc_namebl_translate() function will use the 'closest-
first' algorithm to first look for a node local destination, and only
when no such is found, will it resort to the cluster global 'round-
robin' lookup algorithm.
- Current users can get around this, and enforce unconditional use of
global round-robin by indicating a destination as Z.0.0 or Z.C.0.
- This option disappears when we make the node address flat, since the
lookup algorithm has no way of recognizing this case. So, as long as
there are node local destinations, the algorithm will always select
one of those, and there is nothing the sender can do to change this.
We solve this by eliminating the 'closest-first' option, which was never
a good idea anyway, for non-legacy users, but only for those. To
distinguish between legacy users and non-legacy users we introduce a new
flag 'legacy_addr_format' in struct tipc_core, to be set when the user
configures a legacy-style Z.C.N node address. Hence, when a legacy user
indicates a zero lookup domain 'closest-first' is selected, and in all
other cases we use 'round-robin'.
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-03-22 22:42:48 +03:00
if ( ! tipc_in_scope ( legacy , * destnode , self ) )
2006-01-02 21:04:38 +03:00
return 0 ;
2014-12-02 10:00:30 +03:00
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( unlikely ( ! sc ) )
2006-01-02 21:04:38 +03:00
goto not_found ;
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
sr = tipc_service_find_range ( sc , instance ) ;
if ( unlikely ( ! sr ) )
2014-12-02 10:00:26 +03:00
goto no_match ;
2006-01-02 21:04:38 +03:00
2012-04-30 23:29:02 +04:00
/* Closest-First Algorithm */
tipc: allow closest-first lookup algorithm when legacy address is configured
The removal of an internal structure of the node address has an unwanted
side effect.
- Currently, if a user is sending an anycast message with destination
domain 0, the tipc_namebl_translate() function will use the 'closest-
first' algorithm to first look for a node local destination, and only
when no such is found, will it resort to the cluster global 'round-
robin' lookup algorithm.
- Current users can get around this, and enforce unconditional use of
global round-robin by indicating a destination as Z.0.0 or Z.C.0.
- This option disappears when we make the node address flat, since the
lookup algorithm has no way of recognizing this case. So, as long as
there are node local destinations, the algorithm will always select
one of those, and there is nothing the sender can do to change this.
We solve this by eliminating the 'closest-first' option, which was never
a good idea anyway, for non-legacy users, but only for those. To
distinguish between legacy users and non-legacy users we introduce a new
flag 'legacy_addr_format' in struct tipc_core, to be set when the user
configures a legacy-style Z.C.N node address. Hence, when a legacy user
indicates a zero lookup domain 'closest-first' is selected, and in all
other cases we use 'round-robin'.
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2018-03-22 22:42:48 +03:00
if ( legacy & & ! * destnode ) {
2018-03-30 00:20:41 +03:00
if ( ! list_empty ( & sr - > local_publ ) ) {
p = list_first_entry ( & sr - > local_publ ,
struct publication ,
local_publ ) ;
list_move_tail ( & p - > local_publ ,
& sr - > local_publ ) ;
2018-03-15 18:48:53 +03:00
} else {
2018-03-30 00:20:41 +03:00
p = list_first_entry ( & sr - > all_publ ,
struct publication ,
all_publ ) ;
list_move_tail ( & p - > all_publ ,
& sr - > all_publ ) ;
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 */
2018-03-30 00:20:41 +03:00
else if ( * destnode = = self ) {
if ( list_empty ( & sr - > local_publ ) )
2011-05-30 18:48:48 +04:00
goto no_match ;
2018-03-30 00:20:41 +03:00
p = list_first_entry ( & sr - > local_publ , struct publication ,
local_publ ) ;
list_move_tail ( & p - > local_publ , & sr - > local_publ ) ;
2018-03-15 18:48:53 +03:00
} else {
2018-03-30 00:20:41 +03:00
p = list_first_entry ( & sr - > all_publ , struct publication ,
all_publ ) ;
list_move_tail ( & p - > all_publ , & sr - > all_publ ) ;
2006-01-02 21:04:38 +03:00
}
2011-05-30 18:48:48 +04:00
2018-03-30 00:20:41 +03:00
port = p - > port ;
node = p - > node ;
2011-05-30 18:48:48 +04:00
no_match :
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
2006-01-02 21:04:38 +03:00
not_found :
2014-12-02 10:00:30 +03:00
rcu_read_unlock ( ) ;
2011-11-08 02:00:54 +04:00
* destnode = node ;
2018-03-15 18:48:55 +03:00
return port ;
2006-01-02 21:04:38 +03:00
}
2018-01-08 23:03:30 +03:00
bool tipc_nametbl_lookup ( struct net * net , u32 type , u32 instance , u32 scope ,
2017-10-13 12:04:28 +03:00
struct list_head * dsts , int * dstcnt , u32 exclude ,
bool all )
{
u32 self = tipc_own_addr ( net ) ;
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct tipc_service * sc ;
struct publication * p ;
2017-10-13 12:04:28 +03:00
* dstcnt = 0 ;
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( unlikely ( ! sc ) )
2017-10-13 12:04:28 +03:00
goto exit ;
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
sr = tipc_service_find_range ( sc , instance ) ;
if ( ! sr )
goto no_match ;
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
if ( p - > scope ! = scope )
continue ;
if ( p - > port = = exclude & & p - > node = = self )
continue ;
tipc_dest_push ( dsts , p - > node , p - > port ) ;
( * dstcnt ) + + ;
if ( all )
continue ;
list_move_tail ( & p - > all_publ , & sr - > all_publ ) ;
break ;
2017-10-13 12:04:28 +03:00
}
2018-03-30 00:20:41 +03:00
no_match :
spin_unlock_bh ( & sc - > lock ) ;
2017-10-13 12:04:28 +03:00
exit :
rcu_read_unlock ( ) ;
return ! list_empty ( dsts ) ;
}
2018-03-15 18:48:53 +03:00
void tipc_nametbl_mc_lookup ( struct net * net , u32 type , u32 lower , u32 upper ,
u32 scope , bool exact , struct list_head * dports )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct tipc_service * sc ;
2018-01-08 23:03:30 +03:00
struct publication * p ;
2018-03-30 00:20:41 +03:00
struct rb_node * n ;
2006-01-02 21:04:38 +03:00
2014-12-02 10:00:30 +03:00
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( ! sc )
2006-01-02 21:04:38 +03:00
goto exit ;
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
for ( n = rb_first ( & sc - > ranges ) ; n ; n = rb_next ( n ) ) {
sr = container_of ( n , struct service_range , tree_node ) ;
if ( sr - > upper < lower )
continue ;
if ( sr - > lower > upper )
2006-01-02 21:04:38 +03:00
break ;
2018-03-30 00:20:41 +03:00
list_for_each_entry ( p , & sr - > local_publ , local_publ ) {
2018-01-08 23:03:30 +03:00
if ( p - > scope = = scope | | ( ! exact & & p - > scope < scope ) )
2018-03-15 18:48:55 +03:00
tipc_dest_push ( dports , 0 , p - > port ) ;
2008-07-15 09:45:33 +04:00
}
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
2006-01-02 21:04:38 +03:00
exit :
2014-12-02 10:00:30 +03:00
rcu_read_unlock ( ) ;
2006-01-02 21:04:38 +03:00
}
2017-01-18 21:50:51 +03:00
/* tipc_nametbl_lookup_dst_nodes - find broadcast destination nodes
* - Creates list of nodes that overlap the given multicast address
2018-03-30 00:20:41 +03:00
* - Determines if any node local destinations overlap
2017-01-18 21:50:51 +03:00
*/
void tipc_nametbl_lookup_dst_nodes ( struct net * net , u32 type , u32 lower ,
2018-01-12 22:56:50 +03:00
u32 upper , struct tipc_nlist * nodes )
2017-01-18 21:50:51 +03:00
{
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct tipc_service * sc ;
struct publication * p ;
struct rb_node * n ;
2017-01-18 21:50:51 +03:00
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( ! sc )
2017-01-18 21:50:51 +03:00
goto exit ;
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
for ( n = rb_first ( & sc - > ranges ) ; n ; n = rb_next ( n ) ) {
sr = container_of ( n , struct service_range , tree_node ) ;
if ( sr - > upper < lower )
continue ;
if ( sr - > lower > upper )
break ;
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
tipc_nlist_add ( nodes , p - > node ) ;
2017-01-18 21:50:51 +03:00
}
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
2017-01-18 21:50:51 +03:00
exit :
rcu_read_unlock ( ) ;
}
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
/* tipc_nametbl_build_group - build list of communication group members
*/
void tipc_nametbl_build_group ( struct net * net , struct tipc_group * grp ,
2018-01-08 23:03:30 +03:00
u32 type , u32 scope )
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
{
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct tipc_service * sc ;
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
struct publication * p ;
2018-03-30 00:20:41 +03:00
struct rb_node * n ;
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( net , type ) ;
if ( ! sc )
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
goto exit ;
2018-03-30 00:20:41 +03:00
spin_lock_bh ( & sc - > lock ) ;
for ( n = rb_first ( & sc - > ranges ) ; n ; n = rb_next ( n ) ) {
sr = container_of ( n , struct service_range , tree_node ) ;
list_for_each_entry ( p , & sr - > all_publ , all_publ ) {
2018-01-08 23:03:30 +03:00
if ( p - > scope ! = scope )
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
continue ;
2018-03-15 18:48:55 +03:00
tipc_group_add_member ( grp , p - > node , p - > port , p - > lower ) ;
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
}
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
tipc: introduce communication groups
As a preparation for introducing flow control for multicast and datagram
messaging we need a more strictly defined framework than we have now. A
socket must be able keep track of exactly how many and which other
sockets it is allowed to communicate with at any moment, and keep the
necessary state for those.
We therefore introduce a new concept we have named Communication Group.
Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
The call takes four parameters: 'type' serves as group identifier,
'instance' serves as an logical member identifier, and 'scope' indicates
the visibility of the group (node/cluster/zone). Finally, 'flags' makes
it possible to set certain properties for the member. For now, there is
only one flag, indicating if the creator of the socket wants to receive
a copy of broadcast or multicast messages it is sending via the socket,
and if wants to be eligible as destination for its own anycasts.
A group is closed, i.e., sockets which have not joined a group will
not be able to send messages to or receive messages from members of
the group, and vice versa.
Any member of a group can send multicast ('group broadcast') messages
to all group members, optionally including itself, using the primitive
send(). The messages are received via the recvmsg() primitive. A socket
can only be member of one group at a time.
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-13 12:04:23 +03:00
exit :
rcu_read_unlock ( ) ;
}
2018-03-30 00:20:41 +03:00
/* tipc_nametbl_publish - add service binding to name table
2006-01-02 21:04:38 +03:00
*/
2015-01-09 10:27:05 +03:00
struct publication * tipc_nametbl_publish ( struct net * net , u32 type , u32 lower ,
2018-03-30 00:20:41 +03:00
u32 upper , u32 scope , u32 port ,
2015-01-09 10:27:05 +03:00
u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( net ) ;
struct tipc_net * tn = tipc_net ( net ) ;
struct publication * p = NULL ;
struct sk_buff * skb = NULL ;
2006-01-02 21:04:38 +03:00
2015-01-09 10:27:09 +03:00
spin_lock_bh ( & tn - > nametbl_lock ) ;
2018-03-30 00:20:41 +03:00
if ( nt - > local_publ_count > = TIPC_MAX_PUBL ) {
pr_warn ( " Bind failed, max limit %u reached \n " , TIPC_MAX_PUBL ) ;
goto exit ;
2006-01-02 21:04:38 +03:00
}
2018-03-30 00:20:41 +03:00
p = tipc_nametbl_insert_publ ( net , type , lower , upper , scope ,
tipc_own_addr ( net ) , port , key ) ;
if ( p ) {
nt - > local_publ_count + + ;
skb = tipc_named_publish ( net , p ) ;
tipc: add name distributor resiliency queue
TIPC name table updates are distributed asynchronously in a cluster,
entailing a risk of certain race conditions. E.g., if two nodes
simultaneously issue conflicting (overlapping) publications, this may
not be detected until both publications have reached a third node, in
which case one of the publications will be silently dropped on that
node. Hence, we end up with an inconsistent name table.
In most cases this conflict is just a temporary race, e.g., one
node is issuing a publication under the assumption that a previous,
conflicting, publication has already been withdrawn by the other node.
However, because of the (rtt related) distributed update delay, this
may not yet hold true on all nodes. The symptom of this failure is a
syslog message: "tipc: Cannot publish {%u,%u,%u}, overlap error".
In this commit we add a resiliency queue at the receiving end of
the name table distributor. When insertion of an arriving publication
fails, we retain it in this queue for a short amount of time, assuming
that another update will arrive very soon and clear the conflict. If so
happens, we insert the publication, otherwise we drop it.
The (configurable) retention value defaults to 2000 ms. Knowing from
experience that the situation described above is extremely rare, there
is no risk that the queue will accumulate any large number of items.
Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-08-28 11:08:47 +04:00
/* Any pending external events? */
2015-01-09 10:27:05 +03:00
tipc_named_process_backlog ( net ) ;
2011-11-09 23:22:52 +04:00
}
2018-03-30 00:20:41 +03:00
exit :
2015-01-09 10:27:09 +03:00
spin_unlock_bh ( & tn - > nametbl_lock ) ;
2014-04-28 14:00:10 +04:00
2018-03-30 00:20:41 +03:00
if ( skb )
tipc_node_broadcast ( net , skb ) ;
return p ;
2006-01-02 21:04:38 +03:00
}
/**
2018-03-30 00:20:41 +03:00
* tipc_nametbl_withdraw - withdraw a service binding
2006-01-02 21:04:38 +03:00
*/
2018-03-30 00:20:41 +03:00
int tipc_nametbl_withdraw ( struct net * net , u32 type , u32 lower ,
u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( net ) ;
struct tipc_net * tn = tipc_net ( net ) ;
u32 self = tipc_own_addr ( net ) ;
2014-12-02 10:00:28 +03:00
struct sk_buff * skb = NULL ;
2018-03-30 00:20:41 +03:00
struct publication * p ;
2006-01-02 21:04:38 +03:00
2015-01-09 10:27:09 +03:00
spin_lock_bh ( & tn - > nametbl_lock ) ;
2018-03-30 00:20:41 +03:00
p = tipc_nametbl_remove_publ ( net , type , lower , self , port , key ) ;
if ( p ) {
nt - > local_publ_count - - ;
skb = tipc_named_withdraw ( net , p ) ;
tipc: add name distributor resiliency queue
TIPC name table updates are distributed asynchronously in a cluster,
entailing a risk of certain race conditions. E.g., if two nodes
simultaneously issue conflicting (overlapping) publications, this may
not be detected until both publications have reached a third node, in
which case one of the publications will be silently dropped on that
node. Hence, we end up with an inconsistent name table.
In most cases this conflict is just a temporary race, e.g., one
node is issuing a publication under the assumption that a previous,
conflicting, publication has already been withdrawn by the other node.
However, because of the (rtt related) distributed update delay, this
may not yet hold true on all nodes. The symptom of this failure is a
syslog message: "tipc: Cannot publish {%u,%u,%u}, overlap error".
In this commit we add a resiliency queue at the receiving end of
the name table distributor. When insertion of an arriving publication
fails, we retain it in this queue for a short amount of time, assuming
that another update will arrive very soon and clear the conflict. If so
happens, we insert the publication, otherwise we drop it.
The (configurable) retention value defaults to 2000 ms. Knowing from
experience that the situation described above is extremely rare, there
is no risk that the queue will accumulate any large number of items.
Signed-off-by: Erik Hugne <erik.hugne@ericsson.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-08-28 11:08:47 +04:00
/* Any pending external events? */
2015-01-09 10:27:05 +03:00
tipc_named_process_backlog ( net ) ;
2018-03-30 00:20:41 +03:00
list_del_init ( & p - > binding_sock ) ;
kfree_rcu ( p , rcu ) ;
2014-12-02 10:00:28 +03:00
} else {
2018-03-30 00:20:41 +03:00
pr_err ( " Failed to remove local publication {%u,%u,%u}/%u \n " ,
2018-03-15 18:48:55 +03:00
type , lower , port , key ) ;
2014-12-02 10:00:28 +03:00
}
2015-01-09 10:27:09 +03:00
spin_unlock_bh ( & tn - > nametbl_lock ) ;
2014-04-28 14:00:10 +04:00
2014-12-02 10:00:28 +03:00
if ( skb ) {
2015-11-19 22:30:42 +03:00
tipc_node_broadcast ( net , skb ) ;
2006-01-02 21:04:38 +03:00
return 1 ;
}
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
*/
2018-02-15 12:40:46 +03:00
void tipc_nametbl_subscribe ( struct tipc_subscription * sub )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( sub - > net ) ;
2018-02-15 12:40:49 +03:00
struct tipc_net * tn = tipc_net ( sub - > net ) ;
2018-02-15 12:40:46 +03:00
struct tipc_subscr * s = & sub - > evt . s ;
u32 type = tipc_sub_read ( s , seq . type ) ;
2018-03-30 00:20:41 +03:00
struct tipc_service * sc ;
2006-01-02 21:04:38 +03:00
2015-01-09 10:27:09 +03:00
spin_lock_bh ( & tn - > nametbl_lock ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( sub - > net , type ) ;
if ( ! sc )
sc = tipc_service_create ( type , & nt - > services [ hash ( type ) ] ) ;
if ( sc ) {
spin_lock_bh ( & sc - > lock ) ;
tipc_service_subscribe ( sc , sub ) ;
spin_unlock_bh ( & sc - > lock ) ;
2007-02-09 17:25:21 +03:00
} else {
2018-03-30 00:20:41 +03:00
pr_warn ( " Failed to subscribe for {%u,%u,%u} \n " , type ,
tipc_sub_read ( s , seq . lower ) ,
tipc_sub_read ( s , seq . upper ) ) ;
2007-02-09 17:25:21 +03:00
}
2015-01-09 10:27:09 +03:00
spin_unlock_bh ( & tn - > 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
*/
2018-02-15 12:40:46 +03:00
void tipc_nametbl_unsubscribe ( struct tipc_subscription * sub )
2006-01-02 21:04:38 +03:00
{
2018-02-15 12:40:49 +03:00
struct tipc_net * tn = tipc_net ( sub - > net ) ;
2018-03-30 00:20:41 +03:00
struct tipc_subscr * s = & sub - > evt . s ;
2018-02-15 12:40:46 +03:00
u32 type = tipc_sub_read ( s , seq . type ) ;
2018-03-30 00:20:41 +03:00
struct tipc_service * sc ;
2006-01-02 21:04:38 +03:00
2015-01-09 10:27:09 +03:00
spin_lock_bh ( & tn - > nametbl_lock ) ;
2018-03-30 00:20:41 +03:00
sc = tipc_service_find ( sub - > net , type ) ;
if ( ! sc )
goto exit ;
spin_lock_bh ( & sc - > lock ) ;
list_del_init ( & sub - > service_list ) ;
tipc_sub_put ( sub ) ;
/* Delete service item if no more publications and subscriptions */
if ( RB_EMPTY_ROOT ( & sc - > ranges ) & & list_empty ( & sc - > subscriptions ) ) {
hlist_del_init_rcu ( & sc - > service_list ) ;
kfree_rcu ( sc , rcu ) ;
2007-02-09 17:25:21 +03:00
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & sc - > lock ) ;
exit :
2015-01-09 10:27:09 +03:00
spin_unlock_bh ( & tn - > nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
2015-01-09 10:27:09 +03:00
int tipc_nametbl_init ( struct net * net )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_net * tn = tipc_net ( net ) ;
struct name_table * nt ;
2014-12-02 10:00:24 +03:00
int i ;
2018-03-30 00:20:41 +03:00
nt = kzalloc ( sizeof ( * nt ) , GFP_ATOMIC ) ;
if ( ! nt )
2006-01-02 21:04:38 +03:00
return - ENOMEM ;
2014-12-02 10:00:24 +03:00
for ( i = 0 ; i < TIPC_NAMETBL_SIZE ; i + + )
2018-03-30 00:20:41 +03:00
INIT_HLIST_HEAD ( & nt - > services [ i ] ) ;
2014-12-02 10:00:24 +03:00
2018-03-30 00:20:41 +03:00
INIT_LIST_HEAD ( & nt - > node_scope ) ;
INIT_LIST_HEAD ( & nt - > cluster_scope ) ;
tn - > nametbl = nt ;
2015-01-09 10:27:09 +03:00
spin_lock_init ( & tn - > nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
2014-03-06 17:40:20 +04:00
/**
2018-03-30 00:20:41 +03:00
* tipc_service_delete - purge all publications for a service and delete it
2014-03-06 17:40:20 +04:00
*/
2018-03-30 00:20:41 +03:00
static void tipc_service_delete ( struct net * net , struct tipc_service * sc )
2014-03-06 17:40:20 +04:00
{
2018-03-30 00:20:41 +03:00
struct service_range * sr , * tmpr ;
struct publication * p , * tmpb ;
spin_lock_bh ( & sc - > lock ) ;
rbtree_postorder_for_each_entry_safe ( sr , tmpr , & sc - > ranges , tree_node ) {
list_for_each_entry_safe ( p , tmpb ,
& sr - > all_publ , all_publ ) {
tipc_service_remove_publ ( net , sc , p - > lower , p - > node ,
p - > port , p - > key ) ;
kfree_rcu ( p , rcu ) ;
}
2014-03-06 17:40:20 +04:00
}
2018-03-30 00:20:41 +03:00
hlist_del_init_rcu ( & sc - > service_list ) ;
spin_unlock_bh ( & sc - > lock ) ;
kfree_rcu ( sc , rcu ) ;
2014-03-06 17:40:20 +04:00
}
2015-01-09 10:27:09 +03:00
void tipc_nametbl_stop ( struct net * net )
2006-01-02 21:04:38 +03:00
{
2018-03-30 00:20:41 +03:00
struct name_table * nt = tipc_name_table ( net ) ;
struct tipc_net * tn = tipc_net ( net ) ;
struct hlist_head * service_head ;
struct tipc_service * service ;
2006-01-02 21:04:38 +03:00
u32 i ;
2014-03-06 17:40:20 +04:00
/* Verify name table is empty and purge any lingering
* publications , then release the name table
*/
2015-01-09 10:27:09 +03:00
spin_lock_bh ( & tn - > nametbl_lock ) ;
2012-08-16 16:09:11 +04:00
for ( i = 0 ; i < TIPC_NAMETBL_SIZE ; i + + ) {
2018-03-30 00:20:41 +03:00
if ( hlist_empty ( & nt - > services [ i ] ) )
2012-07-12 01:35:01 +04:00
continue ;
2018-03-30 00:20:41 +03:00
service_head = & nt - > services [ i ] ;
hlist_for_each_entry_rcu ( service , service_head , service_list ) {
tipc_service_delete ( net , service ) ;
2014-03-06 17:40:20 +04:00
}
2006-01-02 21:04:38 +03:00
}
2015-01-09 10:27:09 +03:00
spin_unlock_bh ( & tn - > nametbl_lock ) ;
2014-12-02 10:00:24 +03:00
2014-12-02 10:00:30 +03:00
synchronize_net ( ) ;
2018-03-30 00:20:41 +03:00
kfree ( nt ) ;
2006-01-02 21:04:38 +03:00
}
2014-11-20 12:29:20 +03:00
2014-11-24 13:10:29 +03:00
static int __tipc_nl_add_nametable_publ ( struct tipc_nl_msg * msg ,
2018-03-30 00:20:41 +03:00
struct tipc_service * service ,
struct service_range * sr ,
u32 * last_key )
2014-11-20 12:29:20 +03:00
{
struct publication * p ;
2018-03-30 00:20:41 +03:00
struct nlattr * attrs ;
struct nlattr * b ;
void * hdr ;
2014-11-20 12:29:20 +03:00
2018-03-30 00:20:41 +03:00
if ( * last_key ) {
list_for_each_entry ( p , & sr - > all_publ , all_publ )
if ( p - > key = = * last_key )
2014-11-20 12:29:20 +03:00
break ;
2018-03-30 00:20:41 +03:00
if ( p - > key ! = * last_key )
2014-11-20 12:29:20 +03:00
return - EPIPE ;
} else {
2018-03-30 00:20:41 +03:00
p = list_first_entry ( & sr - > all_publ ,
struct publication ,
2018-03-15 18:48:55 +03:00
all_publ ) ;
2014-11-20 12:29:20 +03:00
}
2018-03-30 00:20:41 +03:00
list_for_each_entry_from ( p , & sr - > all_publ , all_publ ) {
* last_key = p - > key ;
2014-11-20 12:29:20 +03:00
hdr = genlmsg_put ( msg - > skb , msg - > portid , msg - > seq ,
2015-02-09 11:50:03 +03:00
& tipc_genl_family , NLM_F_MULTI ,
2014-11-20 12:29:20 +03:00
TIPC_NL_NAME_TABLE_GET ) ;
if ( ! hdr )
return - EMSGSIZE ;
attrs = nla_nest_start ( msg - > skb , TIPC_NLA_NAME_TABLE ) ;
if ( ! attrs )
goto msg_full ;
2018-03-30 00:20:41 +03:00
b = nla_nest_start ( msg - > skb , TIPC_NLA_NAME_TABLE_PUBL ) ;
if ( ! b )
2014-11-20 12:29:20 +03:00
goto attr_msg_full ;
2018-03-30 00:20:41 +03:00
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_TYPE , service - > type ) )
2014-11-20 12:29:20 +03:00
goto publ_msg_full ;
2018-03-30 00:20:41 +03:00
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_LOWER , sr - > lower ) )
2014-11-20 12:29:20 +03:00
goto publ_msg_full ;
2018-03-30 00:20:41 +03:00
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_UPPER , sr - > upper ) )
2014-11-20 12:29:20 +03:00
goto publ_msg_full ;
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_SCOPE , p - > scope ) )
goto publ_msg_full ;
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_NODE , p - > node ) )
goto publ_msg_full ;
2018-03-15 18:48:55 +03:00
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_REF , p - > port ) )
2014-11-20 12:29:20 +03:00
goto publ_msg_full ;
if ( nla_put_u32 ( msg - > skb , TIPC_NLA_PUBL_KEY , p - > key ) )
goto publ_msg_full ;
2018-03-30 00:20:41 +03:00
nla_nest_end ( msg - > skb , b ) ;
2014-11-20 12:29:20 +03:00
nla_nest_end ( msg - > skb , attrs ) ;
genlmsg_end ( msg - > skb , hdr ) ;
}
2018-03-30 00:20:41 +03:00
* last_key = 0 ;
2014-11-20 12:29:20 +03:00
return 0 ;
publ_msg_full :
2018-03-30 00:20:41 +03:00
nla_nest_cancel ( msg - > skb , b ) ;
2014-11-20 12:29:20 +03:00
attr_msg_full :
nla_nest_cancel ( msg - > skb , attrs ) ;
msg_full :
genlmsg_cancel ( msg - > skb , hdr ) ;
return - EMSGSIZE ;
}
2018-03-30 00:20:41 +03:00
static int __tipc_nl_service_range_list ( struct tipc_nl_msg * msg ,
struct tipc_service * sc ,
u32 * last_lower , u32 * last_key )
2014-11-20 12:29:20 +03:00
{
2018-03-30 00:20:41 +03:00
struct service_range * sr ;
struct rb_node * n ;
2014-11-20 12:29:20 +03:00
int err ;
2018-03-30 00:20:41 +03:00
for ( n = rb_first ( & sc - > ranges ) ; n ; n = rb_next ( n ) ) {
sr = container_of ( n , struct service_range , tree_node ) ;
if ( sr - > lower < * last_lower )
continue ;
err = __tipc_nl_add_nametable_publ ( msg , sc , sr , last_key ) ;
2014-11-20 12:29:20 +03:00
if ( err ) {
2018-03-30 00:20:41 +03:00
* last_lower = sr - > lower ;
2014-11-20 12:29:20 +03:00
return err ;
}
}
* last_lower = 0 ;
return 0 ;
}
2018-03-30 00:20:41 +03:00
static int tipc_nl_service_list ( struct net * net , struct tipc_nl_msg * msg ,
u32 * last_type , u32 * last_lower , u32 * last_key )
2014-11-20 12:29:20 +03:00
{
2018-03-30 00:20:41 +03:00
struct tipc_net * tn = tipc_net ( net ) ;
struct tipc_service * service = NULL ;
struct hlist_head * head ;
2014-11-20 12:29:20 +03:00
int err ;
int i ;
if ( * last_type )
i = hash ( * last_type ) ;
else
i = 0 ;
for ( ; i < TIPC_NAMETBL_SIZE ; i + + ) {
2018-03-30 00:20:41 +03:00
head = & tn - > nametbl - > services [ i ] ;
2014-11-20 12:29:20 +03:00
if ( * last_type ) {
2018-03-30 00:20:41 +03:00
service = tipc_service_find ( net , * last_type ) ;
if ( ! service )
2014-11-20 12:29:20 +03:00
return - EPIPE ;
} else {
2018-03-30 00:20:41 +03:00
hlist_for_each_entry_rcu ( service , head , service_list )
2014-12-02 10:00:30 +03:00
break ;
2018-03-30 00:20:41 +03:00
if ( ! service )
2014-11-20 12:29:20 +03:00
continue ;
}
2018-03-30 00:20:41 +03:00
hlist_for_each_entry_from_rcu ( service , service_list ) {
spin_lock_bh ( & service - > lock ) ;
err = __tipc_nl_service_range_list ( msg , service ,
last_lower ,
last_key ) ;
2014-11-20 12:29:20 +03:00
if ( err ) {
2018-03-30 00:20:41 +03:00
* last_type = service - > type ;
spin_unlock_bh ( & service - > lock ) ;
2014-11-20 12:29:20 +03:00
return err ;
}
2018-03-30 00:20:41 +03:00
spin_unlock_bh ( & service - > lock ) ;
2014-11-20 12:29:20 +03:00
}
* last_type = 0 ;
}
return 0 ;
}
int tipc_nl_name_table_dump ( struct sk_buff * skb , struct netlink_callback * cb )
{
2018-03-30 00:20:41 +03:00
struct net * net = sock_net ( skb - > sk ) ;
2014-11-20 12:29:20 +03:00
u32 last_type = cb - > args [ 0 ] ;
u32 last_lower = cb - > args [ 1 ] ;
2018-03-30 00:20:41 +03:00
u32 last_key = cb - > args [ 2 ] ;
int done = cb - > args [ 3 ] ;
2014-11-20 12:29:20 +03:00
struct tipc_nl_msg msg ;
2018-03-30 00:20:41 +03:00
int err ;
2014-11-20 12:29:20 +03:00
if ( done )
return 0 ;
msg . skb = skb ;
msg . portid = NETLINK_CB ( cb - > skb ) . portid ;
msg . seq = cb - > nlh - > nlmsg_seq ;
2014-12-02 10:00:30 +03:00
rcu_read_lock ( ) ;
2018-03-30 00:20:41 +03:00
err = tipc_nl_service_list ( net , & msg , & last_type ,
& last_lower , & last_key ) ;
2014-11-20 12:29:20 +03:00
if ( ! err ) {
done = 1 ;
} else if ( err ! = - EMSGSIZE ) {
/* We never set seq or call nl_dump_check_consistent() this
* means that setting prev_seq here will cause the consistence
* check to fail in the netlink callback handler . Resulting in
* the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
* we got an error .
*/
cb - > prev_seq = 1 ;
}
2014-12-02 10:00:30 +03:00
rcu_read_unlock ( ) ;
2014-11-20 12:29:20 +03:00
cb - > args [ 0 ] = last_type ;
cb - > args [ 1 ] = last_lower ;
2018-03-30 00:20:41 +03:00
cb - > args [ 2 ] = last_key ;
2014-11-20 12:29:20 +03:00
cb - > args [ 3 ] = done ;
return skb - > len ;
}
2015-02-05 16:36:43 +03:00
2017-10-13 12:04:22 +03:00
struct tipc_dest * tipc_dest_find ( struct list_head * l , u32 node , u32 port )
2015-02-05 16:36:43 +03:00
{
2017-10-13 12:04:22 +03:00
u64 value = ( u64 ) node < < 32 | port ;
struct tipc_dest * dst ;
2015-02-05 16:36:43 +03:00
2017-10-13 12:04:22 +03:00
list_for_each_entry ( dst , l , list ) {
if ( dst - > value ! = value )
continue ;
return dst ;
2015-02-05 16:36:43 +03:00
}
2017-10-13 12:04:22 +03:00
return NULL ;
2017-01-03 18:55:10 +03:00
}
2017-10-13 12:04:22 +03:00
bool tipc_dest_push ( struct list_head * l , u32 node , u32 port )
2017-01-03 18:55:10 +03:00
{
2017-10-13 12:04:22 +03:00
u64 value = ( u64 ) node < < 32 | port ;
struct tipc_dest * dst ;
2017-01-03 18:55:10 +03:00
2017-10-13 12:04:22 +03:00
if ( tipc_dest_find ( l , node , port ) )
2017-01-03 18:55:10 +03:00
return false ;
2017-10-13 12:04:22 +03:00
dst = kmalloc ( sizeof ( * dst ) , GFP_ATOMIC ) ;
if ( unlikely ( ! dst ) )
return false ;
dst - > value = value ;
list_add ( & dst - > list , l ) ;
2017-01-03 18:55:10 +03:00
return true ;
}
2017-10-13 12:04:22 +03:00
bool tipc_dest_pop ( struct list_head * l , u32 * node , u32 * port )
2017-01-03 18:55:10 +03:00
{
2017-10-13 12:04:22 +03:00
struct tipc_dest * dst ;
2017-01-03 18:55:10 +03:00
if ( list_empty ( l ) )
2017-10-13 12:04:22 +03:00
return false ;
dst = list_first_entry ( l , typeof ( * dst ) , list ) ;
if ( port )
* port = dst - > port ;
if ( node )
* node = dst - > node ;
list_del ( & dst - > list ) ;
kfree ( dst ) ;
return true ;
2017-01-03 18:55:10 +03:00
}
2017-10-13 12:04:22 +03:00
bool tipc_dest_del ( struct list_head * l , u32 node , u32 port )
2017-01-03 18:55:10 +03:00
{
2017-10-13 12:04:22 +03:00
struct tipc_dest * dst ;
2017-01-03 18:55:10 +03:00
2017-10-13 12:04:22 +03:00
dst = tipc_dest_find ( l , node , port ) ;
if ( ! dst )
return false ;
list_del ( & dst - > list ) ;
kfree ( dst ) ;
return true ;
2017-01-03 18:55:10 +03:00
}
2017-10-13 12:04:22 +03:00
void tipc_dest_list_purge ( struct list_head * l )
2017-01-03 18:55:10 +03:00
{
2017-10-13 12:04:22 +03:00
struct tipc_dest * dst , * tmp ;
2017-01-03 18:55:10 +03:00
2017-10-13 12:04:22 +03:00
list_for_each_entry_safe ( dst , tmp , l , list ) {
list_del ( & dst - > list ) ;
kfree ( dst ) ;
2015-02-05 16:36:43 +03:00
}
}
2017-10-13 12:04:22 +03:00
int tipc_dest_list_len ( struct list_head * l )
2015-02-05 16:36:43 +03:00
{
2017-10-13 12:04:22 +03:00
struct tipc_dest * dst ;
2017-01-03 18:55:10 +03:00
int i = 0 ;
2015-02-05 16:36:43 +03:00
2017-10-13 12:04:22 +03:00
list_for_each_entry ( dst , l , list ) {
2017-01-03 18:55:10 +03:00
i + + ;
2015-02-05 16:36:43 +03:00
}
2017-01-03 18:55:10 +03:00
return i ;
2015-02-05 16:36:43 +03:00
}