3102 lines · 77.1 KB · C
RawDownload
/* * net/tipc/node.c: TIPC node management routines * * Copyright (c) 2000-2006, 2012-2016, Ericsson AB * Copyright (c) 2005-2006, 2010-2014, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its *    contributors may be used to endorse or promote products derived from *    this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "core.h"#include "link.h"#include "node.h"#include "name_distr.h"#include "socket.h"#include "bcast.h"#include "monitor.h"#include "discover.h"#include "netlink.h"#include "trace.h"#include "crypto.h" #define INVALID_NODE_SIG	0x10000#define NODE_CLEANUP_AFTER	300000 /* Flags used to take different actions according to flag type * TIPC_NOTIFY_NODE_DOWN: notify node is down * TIPC_NOTIFY_NODE_UP: notify node is up * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type */enum {	TIPC_NOTIFY_NODE_DOWN		= (1 << 3),	TIPC_NOTIFY_NODE_UP		= (1 << 4),	TIPC_NOTIFY_LINK_UP		= (1 << 6),	TIPC_NOTIFY_LINK_DOWN		= (1 << 7)}; struct tipc_link_entry {	struct tipc_link *link;	spinlock_t lock; /* per link */	u32 mtu;	struct sk_buff_head inputq;	struct tipc_media_addr maddr;}; struct tipc_bclink_entry {	struct tipc_link *link;	struct sk_buff_head inputq1;	struct sk_buff_head arrvq;	struct sk_buff_head inputq2;	struct sk_buff_head namedq;	u16 named_rcv_nxt;	bool named_open;}; /** * struct tipc_node - TIPC node structure * @addr: network address of node * @ref: reference counter to node object * @lock: rwlock governing access to structure * @net: the applicable net namespace * @hash: links to adjacent nodes in unsorted hash chain * @inputq: pointer to input queue containing messages for msg event * @namedq: pointer to name table input queue with name table messages * @active_links: bearer ids of active links, used as index into links[] array * @links: array containing references to all links to node * @action_flags: bit mask of different types of node actions * @state: connectivity state vs peer node * @preliminary: a preliminary node or not * @sync_point: sequence number where synch/failover is finished * @list: links to adjacent nodes in sorted list of cluster's nodes * @working_links: number of working links to node (both active and standby) * @link_cnt: number of links to node * @capabilities: bitmap, indicating peer node's functional capabilities * @signature: node instance identifier * @link_id: local and remote bearer ids of changing link, if any * @publ_list: list of publications * @rcu: rcu struct for tipc_node * @delete_at: indicates the time for deleting a down node * @crypto_rx: RX crypto handler */struct tipc_node {	u32 addr;	struct kref kref;	rwlock_t lock;	struct net *net;	struct hlist_node hash;	int active_links[2];	struct tipc_link_entry links[MAX_BEARERS];	struct tipc_bclink_entry bc_entry;	int action_flags;	struct list_head list;	int state;	bool preliminary;	bool failover_sent;	u16 sync_point;	int link_cnt;	u16 working_links;	u16 capabilities;	u32 signature;	u32 link_id;	u8 peer_id[16];	char peer_id_string[NODE_ID_STR_LEN];	struct list_head publ_list;	struct list_head conn_sks;	unsigned long keepalive_intv;	struct timer_list timer;	struct rcu_head rcu;	unsigned long delete_at;	struct net *peer_net;	u32 peer_hash_mix;#ifdef CONFIG_TIPC_CRYPTO	struct tipc_crypto *crypto_rx;#endif}; /* Node FSM states and events: */enum {	SELF_DOWN_PEER_DOWN    = 0xdd,	SELF_UP_PEER_UP        = 0xaa,	SELF_DOWN_PEER_LEAVING = 0xd1,	SELF_UP_PEER_COMING    = 0xac,	SELF_COMING_PEER_UP    = 0xca,	SELF_LEAVING_PEER_DOWN = 0x1d,	NODE_FAILINGOVER       = 0xf0,	NODE_SYNCHING          = 0xcc}; enum {	SELF_ESTABL_CONTACT_EVT = 0xece,	SELF_LOST_CONTACT_EVT   = 0x1ce,	PEER_ESTABL_CONTACT_EVT = 0x9ece,	PEER_LOST_CONTACT_EVT   = 0x91ce,	NODE_FAILOVER_BEGIN_EVT = 0xfbe,	NODE_FAILOVER_END_EVT   = 0xfee,	NODE_SYNCH_BEGIN_EVT    = 0xcbe,	NODE_SYNCH_END_EVT      = 0xcee}; static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,				  struct sk_buff_head *xmitq,				  struct tipc_media_addr **maddr);static void tipc_node_link_down(struct tipc_node *n, int bearer_id,				bool delete);static void node_lost_contact(struct tipc_node *n, struct sk_buff_head *inputq);static void tipc_node_delete(struct tipc_node *node);static void tipc_node_timeout(struct timer_list *t);static void tipc_node_fsm_evt(struct tipc_node *n, int evt);static struct tipc_node *tipc_node_find(struct net *net, u32 addr);static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id);static bool node_is_up(struct tipc_node *n);static void tipc_node_delete_from_list(struct tipc_node *node); struct tipc_sock_conn {	u32 port;	u32 peer_port;	u32 peer_node;	struct list_head list;}; static struct tipc_link *node_active_link(struct tipc_node *n, int sel){	int bearer_id = n->active_links[sel & 1]; 	if (unlikely(bearer_id == INVALID_BEARER_ID))		return NULL; 	return n->links[bearer_id].link;} int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel, bool connected){	struct tipc_node *n;	int bearer_id;	unsigned int mtu = MAX_MSG_SIZE; 	n = tipc_node_find(net, addr);	if (unlikely(!n))		return mtu; 	/* Allow MAX_MSG_SIZE when building connection oriented message	 * if they are in the same core network	 */	if (n->peer_net && connected) {		tipc_node_put(n);		return mtu;	} 	bearer_id = n->active_links[sel & 1];	if (likely(bearer_id != INVALID_BEARER_ID))		mtu = n->links[bearer_id].mtu;	tipc_node_put(n);	return mtu;} bool tipc_node_get_id(struct net *net, u32 addr, u8 *id){	u8 *own_id = tipc_own_id(net);	struct tipc_node *n; 	if (!own_id)		return true; 	if (addr == tipc_own_addr(net)) {		memcpy(id, own_id, TIPC_NODEID_LEN);		return true;	}	n = tipc_node_find(net, addr);	if (!n)		return false; 	memcpy(id, &n->peer_id, TIPC_NODEID_LEN);	tipc_node_put(n);	return true;} u16 tipc_node_get_capabilities(struct net *net, u32 addr){	struct tipc_node *n;	u16 caps; 	n = tipc_node_find(net, addr);	if (unlikely(!n))		return TIPC_NODE_CAPABILITIES;	caps = n->capabilities;	tipc_node_put(n);	return caps;} u32 tipc_node_get_addr(struct tipc_node *node){	return (node) ? node->addr : 0;} char *tipc_node_get_id_str(struct tipc_node *node){	return node->peer_id_string;} #ifdef CONFIG_TIPC_CRYPTO/** * tipc_node_crypto_rx - Retrieve crypto RX handle from node * Note: node ref counter must be held first! */struct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n){	return (__n) ? __n->crypto_rx : NULL;} struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos){	return container_of(pos, struct tipc_node, list)->crypto_rx;} struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr){	struct tipc_node *n; 	n = tipc_node_find(net, addr);	return (n) ? n->crypto_rx : NULL;}#endif static void tipc_node_free(struct rcu_head *rp){	struct tipc_node *n = container_of(rp, struct tipc_node, rcu); #ifdef CONFIG_TIPC_CRYPTO	tipc_crypto_stop(&n->crypto_rx);#endif	kfree(n);} static void tipc_node_kref_release(struct kref *kref){	struct tipc_node *n = container_of(kref, struct tipc_node, kref); 	kfree(n->bc_entry.link);	call_rcu(&n->rcu, tipc_node_free);} void tipc_node_put(struct tipc_node *node){	kref_put(&node->kref, tipc_node_kref_release);} void tipc_node_get(struct tipc_node *node){	kref_get(&node->kref);} /* * tipc_node_find - locate specified node object, if it exists */static struct tipc_node *tipc_node_find(struct net *net, u32 addr){	struct tipc_net *tn = tipc_net(net);	struct tipc_node *node;	unsigned int thash = tipc_hashfn(addr); 	rcu_read_lock();	hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) {		if (node->addr != addr || node->preliminary)			continue;		if (!kref_get_unless_zero(&node->kref))			node = NULL;		break;	}	rcu_read_unlock();	return node;} /* tipc_node_find_by_id - locate specified node object by its 128-bit id * Note: this function is called only when a discovery request failed * to find the node by its 32-bit id, and is not time critical */static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id){	struct tipc_net *tn = tipc_net(net);	struct tipc_node *n;	bool found = false; 	rcu_read_lock();	list_for_each_entry_rcu(n, &tn->node_list, list) {		read_lock_bh(&n->lock);		if (!memcmp(id, n->peer_id, 16) &&		    kref_get_unless_zero(&n->kref))			found = true;		read_unlock_bh(&n->lock);		if (found)			break;	}	rcu_read_unlock();	return found ? n : NULL;} static void tipc_node_read_lock(struct tipc_node *n){	read_lock_bh(&n->lock);} static void tipc_node_read_unlock(struct tipc_node *n){	read_unlock_bh(&n->lock);} static void tipc_node_write_lock(struct tipc_node *n){	write_lock_bh(&n->lock);} static void tipc_node_write_unlock_fast(struct tipc_node *n){	write_unlock_bh(&n->lock);} static void tipc_node_write_unlock(struct tipc_node *n){	struct net *net = n->net;	u32 addr = 0;	u32 flags = n->action_flags;	u32 link_id = 0;	u32 bearer_id;	struct list_head *publ_list; 	if (likely(!flags)) {		write_unlock_bh(&n->lock);		return;	} 	addr = n->addr;	link_id = n->link_id;	bearer_id = link_id & 0xffff;	publ_list = &n->publ_list; 	n->action_flags &= ~(TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP |			     TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP); 	write_unlock_bh(&n->lock); 	if (flags & TIPC_NOTIFY_NODE_DOWN)		tipc_publ_notify(net, publ_list, addr, n->capabilities); 	if (flags & TIPC_NOTIFY_NODE_UP)		tipc_named_node_up(net, addr, n->capabilities); 	if (flags & TIPC_NOTIFY_LINK_UP) {		tipc_mon_peer_up(net, addr, bearer_id);		tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,				     TIPC_NODE_SCOPE, link_id, link_id);	}	if (flags & TIPC_NOTIFY_LINK_DOWN) {		tipc_mon_peer_down(net, addr, bearer_id);		tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,				      addr, link_id);	}} static void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes){	int net_id = tipc_netid(n->net);	struct tipc_net *tn_peer;	struct net *tmp;	u32 hash_chk; 	if (n->peer_net)		return; 	for_each_net_rcu(tmp) {		tn_peer = tipc_net(tmp);		if (!tn_peer)			continue;		/* Integrity checking whether node exists in namespace or not */		if (tn_peer->net_id != net_id)			continue;		if (memcmp(n->peer_id, tn_peer->node_id, NODE_ID_LEN))			continue;		hash_chk = tipc_net_hash_mixes(tmp, tn_peer->random);		if (hash_mixes ^ hash_chk)			continue;		n->peer_net = tmp;		n->peer_hash_mix = hash_mixes;		break;	}} struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,				   u16 capabilities, u32 hash_mixes,				   bool preliminary){	struct tipc_net *tn = net_generic(net, tipc_net_id);	struct tipc_node *n, *temp_node;	struct tipc_link *l;	unsigned long intv;	int bearer_id;	int i; 	spin_lock_bh(&tn->node_list_lock);	n = tipc_node_find(net, addr) ?:		tipc_node_find_by_id(net, peer_id);	if (n) {		if (!n->preliminary)			goto update;		if (preliminary)			goto exit;		/* A preliminary node becomes "real" now, refresh its data */		tipc_node_write_lock(n);		n->preliminary = false;		n->addr = addr;		hlist_del_rcu(&n->hash);		hlist_add_head_rcu(&n->hash,				   &tn->node_htable[tipc_hashfn(addr)]);		list_del_rcu(&n->list);		list_for_each_entry_rcu(temp_node, &tn->node_list, list) {			if (n->addr < temp_node->addr)				break;		}		list_add_tail_rcu(&n->list, &temp_node->list);		tipc_node_write_unlock_fast(n); update:		if (n->peer_hash_mix ^ hash_mixes)			tipc_node_assign_peer_net(n, hash_mixes);		if (n->capabilities == capabilities)			goto exit;		/* Same node may come back with new capabilities */		tipc_node_write_lock(n);		n->capabilities = capabilities;		for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {			l = n->links[bearer_id].link;			if (l)				tipc_link_update_caps(l, capabilities);		}

Lines 1–500 of 3102.