xref: /linux/net/tipc/name_distr.c (revision 9fbfb8b120bd4fe89cd70d6c8841e6e1cfab2609)
1b97bf3fdSPer Liden /*
2b97bf3fdSPer Liden  * net/tipc/name_distr.c: TIPC name distribution code
3b97bf3fdSPer Liden  *
4593a5f22SPer Liden  * Copyright (c) 2000-2006, Ericsson AB
5431697ebSAllan Stephens  * Copyright (c) 2005, 2010-2011, Wind River Systems
6b97bf3fdSPer Liden  * All rights reserved.
7b97bf3fdSPer Liden  *
8b97bf3fdSPer Liden  * Redistribution and use in source and binary forms, with or without
9b97bf3fdSPer Liden  * modification, are permitted provided that the following conditions are met:
10b97bf3fdSPer Liden  *
119ea1fd3cSPer Liden  * 1. Redistributions of source code must retain the above copyright
129ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer.
139ea1fd3cSPer Liden  * 2. Redistributions in binary form must reproduce the above copyright
149ea1fd3cSPer Liden  *    notice, this list of conditions and the following disclaimer in the
159ea1fd3cSPer Liden  *    documentation and/or other materials provided with the distribution.
169ea1fd3cSPer Liden  * 3. Neither the names of the copyright holders nor the names of its
179ea1fd3cSPer Liden  *    contributors may be used to endorse or promote products derived from
189ea1fd3cSPer Liden  *    this software without specific prior written permission.
199ea1fd3cSPer Liden  *
209ea1fd3cSPer Liden  * Alternatively, this software may be distributed under the terms of the
219ea1fd3cSPer Liden  * GNU General Public License ("GPL") version 2 as published by the Free
229ea1fd3cSPer Liden  * Software Foundation.
23b97bf3fdSPer Liden  *
24b97bf3fdSPer Liden  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25b97bf3fdSPer Liden  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26b97bf3fdSPer Liden  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27b97bf3fdSPer Liden  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28b97bf3fdSPer Liden  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29b97bf3fdSPer Liden  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30b97bf3fdSPer Liden  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31b97bf3fdSPer Liden  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32b97bf3fdSPer Liden  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33b97bf3fdSPer Liden  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34b97bf3fdSPer Liden  * POSSIBILITY OF SUCH DAMAGE.
35b97bf3fdSPer Liden  */
36b97bf3fdSPer Liden 
37b97bf3fdSPer Liden #include "core.h"
38b97bf3fdSPer Liden #include "link.h"
39b97bf3fdSPer Liden #include "name_distr.h"
40b97bf3fdSPer Liden 
41b97bf3fdSPer Liden /**
423f8375feSAllan Stephens  * struct publ_list - list of publications made by this node
433f8375feSAllan Stephens  * @list: circular list of publications
443f8375feSAllan Stephens  * @list_size: number of entries in list
45b97bf3fdSPer Liden  */
463f8375feSAllan Stephens struct publ_list {
473f8375feSAllan Stephens 	struct list_head list;
483f8375feSAllan Stephens 	u32 size;
493f8375feSAllan Stephens };
50b97bf3fdSPer Liden 
51a909804fSAllan Stephens static struct publ_list publ_zone = {
52a909804fSAllan Stephens 	.list = LIST_HEAD_INIT(publ_zone.list),
53a909804fSAllan Stephens 	.size = 0,
54a909804fSAllan Stephens };
55a909804fSAllan Stephens 
563f8375feSAllan Stephens static struct publ_list publ_cluster = {
573f8375feSAllan Stephens 	.list = LIST_HEAD_INIT(publ_cluster.list),
583f8375feSAllan Stephens 	.size = 0,
593f8375feSAllan Stephens };
60b97bf3fdSPer Liden 
61a909804fSAllan Stephens static struct publ_list publ_node = {
62a909804fSAllan Stephens 	.list = LIST_HEAD_INIT(publ_node.list),
63a909804fSAllan Stephens 	.size = 0,
64a909804fSAllan Stephens };
65a909804fSAllan Stephens 
66a909804fSAllan Stephens static struct publ_list *publ_lists[] = {
67a909804fSAllan Stephens 	NULL,
68a909804fSAllan Stephens 	&publ_zone,	/* publ_lists[TIPC_ZONE_SCOPE]		*/
69a909804fSAllan Stephens 	&publ_cluster,	/* publ_lists[TIPC_CLUSTER_SCOPE]	*/
70a909804fSAllan Stephens 	&publ_node	/* publ_lists[TIPC_NODE_SCOPE]		*/
71a909804fSAllan Stephens };
72a909804fSAllan Stephens 
73a909804fSAllan Stephens 
74b97bf3fdSPer Liden /**
75b97bf3fdSPer Liden  * publ_to_item - add publication info to a publication message
76b97bf3fdSPer Liden  */
77b97bf3fdSPer Liden static void publ_to_item(struct distr_item *i, struct publication *p)
78b97bf3fdSPer Liden {
79b97bf3fdSPer Liden 	i->type = htonl(p->type);
80b97bf3fdSPer Liden 	i->lower = htonl(p->lower);
81b97bf3fdSPer Liden 	i->upper = htonl(p->upper);
82b97bf3fdSPer Liden 	i->ref = htonl(p->ref);
83b97bf3fdSPer Liden 	i->key = htonl(p->key);
84b97bf3fdSPer Liden }
85b97bf3fdSPer Liden 
86b97bf3fdSPer Liden /**
87b97bf3fdSPer Liden  * named_prepare_buf - allocate & initialize a publication message
88b97bf3fdSPer Liden  */
89b97bf3fdSPer Liden static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
90b97bf3fdSPer Liden {
91741d9eb7SAllan Stephens 	struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE + size);
92b97bf3fdSPer Liden 	struct tipc_msg *msg;
93b97bf3fdSPer Liden 
94b97bf3fdSPer Liden 	if (buf != NULL) {
95b97bf3fdSPer Liden 		msg = buf_msg(buf);
96741d9eb7SAllan Stephens 		tipc_msg_init(msg, NAME_DISTRIBUTOR, type, INT_H_SIZE, dest);
97741d9eb7SAllan Stephens 		msg_set_size(msg, INT_H_SIZE + size);
98b97bf3fdSPer Liden 	}
99b97bf3fdSPer Liden 	return buf;
100b97bf3fdSPer Liden }
101b97bf3fdSPer Liden 
102eab8c045SYing Xue void named_cluster_distribute(struct sk_buff *buf)
1038f92df6aSAllan Stephens {
104dbdf6d24SJon Paul Maloy 	struct sk_buff *obuf;
105dbdf6d24SJon Paul Maloy 	struct tipc_node *node;
106dbdf6d24SJon Paul Maloy 	u32 dnode;
1078f92df6aSAllan Stephens 
1086c7a762eSYing Xue 	rcu_read_lock();
109dbdf6d24SJon Paul Maloy 	list_for_each_entry_rcu(node, &tipc_node_list, list) {
110dbdf6d24SJon Paul Maloy 		dnode = node->addr;
111dbdf6d24SJon Paul Maloy 		if (in_own_node(dnode))
112dbdf6d24SJon Paul Maloy 			continue;
113dbdf6d24SJon Paul Maloy 		if (!tipc_node_active_links(node))
114dbdf6d24SJon Paul Maloy 			continue;
115dbdf6d24SJon Paul Maloy 		obuf = skb_copy(buf, GFP_ATOMIC);
116dbdf6d24SJon Paul Maloy 		if (!obuf)
1178f92df6aSAllan Stephens 			break;
118dbdf6d24SJon Paul Maloy 		msg_set_destnode(buf_msg(obuf), dnode);
119*9fbfb8b1SJon Paul Maloy 		tipc_link_xmit(obuf, dnode, dnode);
1208f92df6aSAllan Stephens 	}
1216c7a762eSYing Xue 	rcu_read_unlock();
1228f92df6aSAllan Stephens 
1235f6d9123SAllan Stephens 	kfree_skb(buf);
1248f92df6aSAllan Stephens }
1258f92df6aSAllan Stephens 
126b97bf3fdSPer Liden /**
1274323add6SPer Liden  * tipc_named_publish - tell other nodes about a new publication by this node
128b97bf3fdSPer Liden  */
129eab8c045SYing Xue struct sk_buff *tipc_named_publish(struct publication *publ)
130b97bf3fdSPer Liden {
131b97bf3fdSPer Liden 	struct sk_buff *buf;
132b97bf3fdSPer Liden 	struct distr_item *item;
133b97bf3fdSPer Liden 
134a909804fSAllan Stephens 	list_add_tail(&publ->local_list, &publ_lists[publ->scope]->list);
135a909804fSAllan Stephens 	publ_lists[publ->scope]->size++;
136b97bf3fdSPer Liden 
1371110b8d3SAllan Stephens 	if (publ->scope == TIPC_NODE_SCOPE)
138eab8c045SYing Xue 		return NULL;
1391110b8d3SAllan Stephens 
140b97bf3fdSPer Liden 	buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
141b97bf3fdSPer Liden 	if (!buf) {
1422cf8aa19SErik Hugne 		pr_warn("Publication distribution failure\n");
143eab8c045SYing Xue 		return NULL;
144b97bf3fdSPer Liden 	}
145b97bf3fdSPer Liden 
146b97bf3fdSPer Liden 	item = (struct distr_item *)msg_data(buf_msg(buf));
147b97bf3fdSPer Liden 	publ_to_item(item, publ);
148eab8c045SYing Xue 	return buf;
149b97bf3fdSPer Liden }
150b97bf3fdSPer Liden 
151b97bf3fdSPer Liden /**
1524323add6SPer Liden  * tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
153b97bf3fdSPer Liden  */
154eab8c045SYing Xue struct sk_buff *tipc_named_withdraw(struct publication *publ)
155b97bf3fdSPer Liden {
156b97bf3fdSPer Liden 	struct sk_buff *buf;
157b97bf3fdSPer Liden 	struct distr_item *item;
158b97bf3fdSPer Liden 
159b97bf3fdSPer Liden 	list_del(&publ->local_list);
160a909804fSAllan Stephens 	publ_lists[publ->scope]->size--;
161b97bf3fdSPer Liden 
1621110b8d3SAllan Stephens 	if (publ->scope == TIPC_NODE_SCOPE)
163eab8c045SYing Xue 		return NULL;
1641110b8d3SAllan Stephens 
165b97bf3fdSPer Liden 	buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
166b97bf3fdSPer Liden 	if (!buf) {
1672cf8aa19SErik Hugne 		pr_warn("Withdrawal distribution failure\n");
168eab8c045SYing Xue 		return NULL;
169b97bf3fdSPer Liden 	}
170b97bf3fdSPer Liden 
171b97bf3fdSPer Liden 	item = (struct distr_item *)msg_data(buf_msg(buf));
172b97bf3fdSPer Liden 	publ_to_item(item, publ);
173eab8c045SYing Xue 	return buf;
174b97bf3fdSPer Liden }
175b97bf3fdSPer Liden 
176dbdf6d24SJon Paul Maloy /**
177e11aa059SAllan Stephens  * named_distribute - prepare name info for bulk distribution to another node
178dbdf6d24SJon Paul Maloy  * @msg_list: list of messages (buffers) to be returned from this function
179dbdf6d24SJon Paul Maloy  * @dnode: node to be updated
180dbdf6d24SJon Paul Maloy  * @pls: linked list of publication items to be packed into buffer chain
181e11aa059SAllan Stephens  */
182dbdf6d24SJon Paul Maloy static void named_distribute(struct list_head *msg_list, u32 dnode,
183dbdf6d24SJon Paul Maloy 			     struct publ_list *pls)
184e11aa059SAllan Stephens {
185e11aa059SAllan Stephens 	struct publication *publ;
186e11aa059SAllan Stephens 	struct sk_buff *buf = NULL;
187e11aa059SAllan Stephens 	struct distr_item *item = NULL;
188dbdf6d24SJon Paul Maloy 	uint dsz = pls->size * ITEM_SIZE;
189dbdf6d24SJon Paul Maloy 	uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE;
190dbdf6d24SJon Paul Maloy 	uint rem = dsz;
191dbdf6d24SJon Paul Maloy 	uint msg_rem = 0;
192e11aa059SAllan Stephens 
193e11aa059SAllan Stephens 	list_for_each_entry(publ, &pls->list, local_list) {
194dbdf6d24SJon Paul Maloy 		/* Prepare next buffer: */
195e11aa059SAllan Stephens 		if (!buf) {
196dbdf6d24SJon Paul Maloy 			msg_rem = min_t(uint, rem, msg_dsz);
197dbdf6d24SJon Paul Maloy 			rem -= msg_rem;
198dbdf6d24SJon Paul Maloy 			buf = named_prepare_buf(PUBLICATION, msg_rem, dnode);
199e11aa059SAllan Stephens 			if (!buf) {
2002cf8aa19SErik Hugne 				pr_warn("Bulk publication failure\n");
201e11aa059SAllan Stephens 				return;
202e11aa059SAllan Stephens 			}
203e11aa059SAllan Stephens 			item = (struct distr_item *)msg_data(buf_msg(buf));
204e11aa059SAllan Stephens 		}
205dbdf6d24SJon Paul Maloy 
206dbdf6d24SJon Paul Maloy 		/* Pack publication into message: */
207e11aa059SAllan Stephens 		publ_to_item(item, publ);
208e11aa059SAllan Stephens 		item++;
209dbdf6d24SJon Paul Maloy 		msg_rem -= ITEM_SIZE;
210dbdf6d24SJon Paul Maloy 
211dbdf6d24SJon Paul Maloy 		/* Append full buffer to list: */
212dbdf6d24SJon Paul Maloy 		if (!msg_rem) {
213dbdf6d24SJon Paul Maloy 			list_add_tail((struct list_head *)buf, msg_list);
214e11aa059SAllan Stephens 			buf = NULL;
215e11aa059SAllan Stephens 		}
216e11aa059SAllan Stephens 	}
217e11aa059SAllan Stephens }
218e11aa059SAllan Stephens 
219b97bf3fdSPer Liden /**
2204323add6SPer Liden  * tipc_named_node_up - tell specified node about all publications by this node
221b97bf3fdSPer Liden  */
222dbdf6d24SJon Paul Maloy void tipc_named_node_up(u32 dnode)
223b97bf3fdSPer Liden {
224dbdf6d24SJon Paul Maloy 	LIST_HEAD(msg_list);
225dbdf6d24SJon Paul Maloy 	struct sk_buff *buf_chain;
2269aa88c2aSAllan Stephens 
2274323add6SPer Liden 	read_lock_bh(&tipc_nametbl_lock);
228dbdf6d24SJon Paul Maloy 	named_distribute(&msg_list, dnode, &publ_cluster);
229dbdf6d24SJon Paul Maloy 	named_distribute(&msg_list, dnode, &publ_zone);
2304323add6SPer Liden 	read_unlock_bh(&tipc_nametbl_lock);
2319aa88c2aSAllan Stephens 
232dbdf6d24SJon Paul Maloy 	/* Convert circular list to linear list and send: */
233dbdf6d24SJon Paul Maloy 	buf_chain = (struct sk_buff *)msg_list.next;
234dbdf6d24SJon Paul Maloy 	((struct sk_buff *)msg_list.prev)->next = NULL;
235*9fbfb8b1SJon Paul Maloy 	tipc_link_xmit(buf_chain, dnode, dnode);
236b97bf3fdSPer Liden }
237b97bf3fdSPer Liden 
238b97bf3fdSPer Liden /**
239f1379173SAllan Stephens  * named_purge_publ - remove publication associated with a failed node
240b97bf3fdSPer Liden  *
241b97bf3fdSPer Liden  * Invoked for each publication issued by a newly failed node.
242b97bf3fdSPer Liden  * Removes publication structure from name table & deletes it.
243b97bf3fdSPer Liden  */
244f1379173SAllan Stephens static void named_purge_publ(struct publication *publ)
245b97bf3fdSPer Liden {
246b97bf3fdSPer Liden 	struct publication *p;
247f131072cSAllan Stephens 
2484323add6SPer Liden 	write_lock_bh(&tipc_nametbl_lock);
2494323add6SPer Liden 	p = tipc_nametbl_remove_publ(publ->type, publ->lower,
250b97bf3fdSPer Liden 				     publ->node, publ->ref, publ->key);
251431697ebSAllan Stephens 	if (p)
252431697ebSAllan Stephens 		tipc_nodesub_unsubscribe(&p->subscr);
2534323add6SPer Liden 	write_unlock_bh(&tipc_nametbl_lock);
254f131072cSAllan Stephens 
255f131072cSAllan Stephens 	if (p != publ) {
2562cf8aa19SErik Hugne 		pr_err("Unable to remove publication from failed node\n"
257f131072cSAllan Stephens 		       " (type=%u, lower=%u, node=0x%x, ref=%u, key=%u)\n",
2582cf8aa19SErik Hugne 		       publ->type, publ->lower, publ->node, publ->ref,
2592cf8aa19SErik Hugne 		       publ->key);
260f131072cSAllan Stephens 	}
261f131072cSAllan Stephens 
262f131072cSAllan Stephens 	kfree(p);
263f131072cSAllan Stephens }
264b97bf3fdSPer Liden 
265b97bf3fdSPer Liden /**
266247f0f3cSYing Xue  * tipc_named_rcv - process name table update message sent by another node
267b97bf3fdSPer Liden  */
268247f0f3cSYing Xue void tipc_named_rcv(struct sk_buff *buf)
269b97bf3fdSPer Liden {
270b97bf3fdSPer Liden 	struct publication *publ;
271b97bf3fdSPer Liden 	struct tipc_msg *msg = buf_msg(buf);
272b97bf3fdSPer Liden 	struct distr_item *item = (struct distr_item *)msg_data(msg);
273b97bf3fdSPer Liden 	u32 count = msg_data_sz(msg) / ITEM_SIZE;
274b97bf3fdSPer Liden 
2754323add6SPer Liden 	write_lock_bh(&tipc_nametbl_lock);
276b97bf3fdSPer Liden 	while (count--) {
277b97bf3fdSPer Liden 		if (msg_type(msg) == PUBLICATION) {
2784323add6SPer Liden 			publ = tipc_nametbl_insert_publ(ntohl(item->type),
279b97bf3fdSPer Liden 							ntohl(item->lower),
280b97bf3fdSPer Liden 							ntohl(item->upper),
281b97bf3fdSPer Liden 							TIPC_CLUSTER_SCOPE,
282b97bf3fdSPer Liden 							msg_orignode(msg),
283b97bf3fdSPer Liden 							ntohl(item->ref),
284b97bf3fdSPer Liden 							ntohl(item->key));
285b97bf3fdSPer Liden 			if (publ) {
2864323add6SPer Liden 				tipc_nodesub_subscribe(&publ->subscr,
287b97bf3fdSPer Liden 						       msg_orignode(msg),
288b97bf3fdSPer Liden 						       publ,
289f1379173SAllan Stephens 						       (net_ev_handler)
290f1379173SAllan Stephens 						       named_purge_publ);
291b97bf3fdSPer Liden 			}
292b97bf3fdSPer Liden 		} else if (msg_type(msg) == WITHDRAWAL) {
2934323add6SPer Liden 			publ = tipc_nametbl_remove_publ(ntohl(item->type),
294b97bf3fdSPer Liden 							ntohl(item->lower),
295b97bf3fdSPer Liden 							msg_orignode(msg),
296b97bf3fdSPer Liden 							ntohl(item->ref),
297b97bf3fdSPer Liden 							ntohl(item->key));
298b97bf3fdSPer Liden 
299b97bf3fdSPer Liden 			if (publ) {
3004323add6SPer Liden 				tipc_nodesub_unsubscribe(&publ->subscr);
301b97bf3fdSPer Liden 				kfree(publ);
302f131072cSAllan Stephens 			} else {
3032cf8aa19SErik Hugne 				pr_err("Unable to remove publication by node 0x%x\n"
304f131072cSAllan Stephens 				       " (type=%u, lower=%u, ref=%u, key=%u)\n",
3052cf8aa19SErik Hugne 				       msg_orignode(msg), ntohl(item->type),
3062cf8aa19SErik Hugne 				       ntohl(item->lower), ntohl(item->ref),
3072cf8aa19SErik Hugne 				       ntohl(item->key));
308b97bf3fdSPer Liden 			}
309b97bf3fdSPer Liden 		} else {
3102cf8aa19SErik Hugne 			pr_warn("Unrecognized name table message received\n");
311b97bf3fdSPer Liden 		}
312b97bf3fdSPer Liden 		item++;
313b97bf3fdSPer Liden 	}
3144323add6SPer Liden 	write_unlock_bh(&tipc_nametbl_lock);
3155f6d9123SAllan Stephens 	kfree_skb(buf);
316b97bf3fdSPer Liden }
317b97bf3fdSPer Liden 
318b97bf3fdSPer Liden /**
3191110b8d3SAllan Stephens  * tipc_named_reinit - re-initialize local publications
320b97bf3fdSPer Liden  *
321945af1c3SAllan Stephens  * This routine is called whenever TIPC networking is enabled.
3221110b8d3SAllan Stephens  * All name table entries published by this node are updated to reflect
3231110b8d3SAllan Stephens  * the node's new network address.
324b97bf3fdSPer Liden  */
3254323add6SPer Liden void tipc_named_reinit(void)
326b97bf3fdSPer Liden {
327b97bf3fdSPer Liden 	struct publication *publ;
328a909804fSAllan Stephens 	int scope;
329b97bf3fdSPer Liden 
3304323add6SPer Liden 	write_lock_bh(&tipc_nametbl_lock);
331945af1c3SAllan Stephens 
3321110b8d3SAllan Stephens 	for (scope = TIPC_ZONE_SCOPE; scope <= TIPC_NODE_SCOPE; scope++)
333a909804fSAllan Stephens 		list_for_each_entry(publ, &publ_lists[scope]->list, local_list)
334b97bf3fdSPer Liden 			publ->node = tipc_own_addr;
335945af1c3SAllan Stephens 
3364323add6SPer Liden 	write_unlock_bh(&tipc_nametbl_lock);
337b97bf3fdSPer Liden }
338