aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/node.c
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2018-03-22 15:42:51 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-23 13:12:18 -0400
commit25b0b9c4e835ffaa65b61c3efe2e28acf84d0259 (patch)
tree39474fca13a7ecde0c1c30cf4530254062d0cbda /net/tipc/node.c
parentd50ccc2d3909fc1b4d40e4af16b026f05dc68707 (diff)
tipc: handle collisions of 32-bit node address hash values
When a 32-bit node address is generated from a 128-bit identifier, there is a risk of collisions which must be discovered and handled. We do this as follows: - We don't apply the generated address immediately to the node, but do instead initiate a 1 sec trial period to allow other cluster members to discover and handle such collisions. - During the trial period the node periodically sends out a new type of message, DSC_TRIAL_MSG, using broadcast or emulated broadcast, to all the other nodes in the cluster. - When a node is receiving such a message, it must check that the presented 32-bit identifier either is unused, or was used by the very same peer in a previous session. In both cases it accepts the request by not responding to it. - If it finds that the same node has been up before using a different address, it responds with a DSC_TRIAL_FAIL_MSG containing that address. - If it finds that the address has already been taken by some other node, it generates a new, unused address and returns it to the requester. - During the trial period the requesting node must always be prepared to accept a failure message, i.e., a message where a peer suggests a different (or equal) address to the one tried. In those cases it must apply the suggested value as trial address and restart the trial period. This algorithm ensures that in the vast majority of cases a node will have the same address before and after a reboot. If a legacy user configures the address explicitly, there will be no trial period and messages, so this protocol addition is completely backwards compatible. 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>
Diffstat (limited to 'net/tipc/node.c')
-rw-r--r--net/tipc/node.c85
1 files changed, 78 insertions, 7 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 7b0c99347406..4a95c8c155c6 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -115,6 +115,7 @@ struct tipc_node {
115 u16 capabilities; 115 u16 capabilities;
116 u32 signature; 116 u32 signature;
117 u32 link_id; 117 u32 link_id;
118 u8 peer_id[16];
118 struct list_head publ_list; 119 struct list_head publ_list;
119 struct list_head conn_sks; 120 struct list_head conn_sks;
120 unsigned long keepalive_intv; 121 unsigned long keepalive_intv;
@@ -156,6 +157,7 @@ static void tipc_node_delete(struct tipc_node *node);
156static void tipc_node_timeout(struct timer_list *t); 157static void tipc_node_timeout(struct timer_list *t);
157static void tipc_node_fsm_evt(struct tipc_node *n, int evt); 158static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
158static struct tipc_node *tipc_node_find(struct net *net, u32 addr); 159static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
160static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id);
159static void tipc_node_put(struct tipc_node *node); 161static void tipc_node_put(struct tipc_node *node);
160static bool node_is_up(struct tipc_node *n); 162static bool node_is_up(struct tipc_node *n);
161 163
@@ -245,6 +247,30 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
245 return node; 247 return node;
246} 248}
247 249
250/* tipc_node_find_by_id - locate specified node object by its 128-bit id
251 * Note: this function is called only when a discovery request failed
252 * to find the node by its 32-bit id, and is not time critical
253 */
254static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id)
255{
256 struct tipc_net *tn = tipc_net(net);
257 struct tipc_node *n;
258 bool found = false;
259
260 rcu_read_lock();
261 list_for_each_entry_rcu(n, &tn->node_list, list) {
262 read_lock_bh(&n->lock);
263 if (!memcmp(id, n->peer_id, 16) &&
264 kref_get_unless_zero(&n->kref))
265 found = true;
266 read_unlock_bh(&n->lock);
267 if (found)
268 break;
269 }
270 rcu_read_unlock();
271 return found ? n : NULL;
272}
273
248static void tipc_node_read_lock(struct tipc_node *n) 274static void tipc_node_read_lock(struct tipc_node *n)
249{ 275{
250 read_lock_bh(&n->lock); 276 read_lock_bh(&n->lock);
@@ -307,7 +333,8 @@ static void tipc_node_write_unlock(struct tipc_node *n)
307 } 333 }
308} 334}
309 335
310struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) 336struct tipc_node *tipc_node_create(struct net *net, u32 addr,
337 u8 *peer_id, u16 capabilities)
311{ 338{
312 struct tipc_net *tn = net_generic(net, tipc_net_id); 339 struct tipc_net *tn = net_generic(net, tipc_net_id);
313 struct tipc_node *n, *temp_node; 340 struct tipc_node *n, *temp_node;
@@ -326,6 +353,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
326 goto exit; 353 goto exit;
327 } 354 }
328 n->addr = addr; 355 n->addr = addr;
356 memcpy(&n->peer_id, peer_id, 16);
329 n->net = net; 357 n->net = net;
330 n->capabilities = capabilities; 358 n->capabilities = capabilities;
331 kref_init(&n->kref); 359 kref_init(&n->kref);
@@ -344,8 +372,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
344 n->signature = INVALID_NODE_SIG; 372 n->signature = INVALID_NODE_SIG;
345 n->active_links[0] = INVALID_BEARER_ID; 373 n->active_links[0] = INVALID_BEARER_ID;
346 n->active_links[1] = INVALID_BEARER_ID; 374 n->active_links[1] = INVALID_BEARER_ID;
347 if (!tipc_link_bc_create(net, tipc_own_addr(net), n->addr, 375 if (!tipc_link_bc_create(net, tipc_own_addr(net),
348 U16_MAX, 376 addr, U16_MAX,
349 tipc_link_window(tipc_bc_sndlink(net)), 377 tipc_link_window(tipc_bc_sndlink(net)),
350 n->capabilities, 378 n->capabilities,
351 &n->bc_entry.inputq1, 379 &n->bc_entry.inputq1,
@@ -735,8 +763,51 @@ bool tipc_node_is_up(struct net *net, u32 addr)
735 return retval; 763 return retval;
736} 764}
737 765
738void tipc_node_check_dest(struct net *net, u32 onode, 766static u32 tipc_node_suggest_addr(struct net *net, u32 addr)
739 struct tipc_bearer *b, 767{
768 struct tipc_node *n;
769
770 addr ^= tipc_net(net)->random;
771 while ((n = tipc_node_find(net, addr))) {
772 tipc_node_put(n);
773 addr++;
774 }
775 return addr;
776}
777
778/* tipc_node_try_addr(): Check if addr can be used by peer, suggest other if not
779 */
780u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr)
781{
782 struct tipc_net *tn = tipc_net(net);
783 struct tipc_node *n;
784
785 /* Suggest new address if some other peer is using this one */
786 n = tipc_node_find(net, addr);
787 if (n) {
788 if (!memcmp(n->peer_id, id, NODE_ID_LEN))
789 addr = 0;
790 tipc_node_put(n);
791 if (!addr)
792 return 0;
793 return tipc_node_suggest_addr(net, addr);
794 }
795
796 /* Suggest previously used address if peer is known */
797 n = tipc_node_find_by_id(net, id);
798 if (n) {
799 addr = n->addr;
800 tipc_node_put(n);
801 }
802 /* Even this node may be in trial phase */
803 if (tn->trial_addr == addr)
804 return tipc_node_suggest_addr(net, addr);
805
806 return addr;
807}
808
809void tipc_node_check_dest(struct net *net, u32 addr,
810 u8 *peer_id, struct tipc_bearer *b,
740 u16 capabilities, u32 signature, 811 u16 capabilities, u32 signature,
741 struct tipc_media_addr *maddr, 812 struct tipc_media_addr *maddr,
742 bool *respond, bool *dupl_addr) 813 bool *respond, bool *dupl_addr)
@@ -755,7 +826,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
755 *dupl_addr = false; 826 *dupl_addr = false;
756 *respond = false; 827 *respond = false;
757 828
758 n = tipc_node_create(net, onode, capabilities); 829 n = tipc_node_create(net, addr, peer_id, capabilities);
759 if (!n) 830 if (!n)
760 return; 831 return;
761 832
@@ -840,7 +911,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
840 if (!tipc_link_create(net, if_name, b->identity, b->tolerance, 911 if (!tipc_link_create(net, if_name, b->identity, b->tolerance,
841 b->net_plane, b->mtu, b->priority, 912 b->net_plane, b->mtu, b->priority,
842 b->window, mod(tipc_net(net)->random), 913 b->window, mod(tipc_net(net)->random),
843 tipc_own_addr(net), onode, 914 tipc_own_addr(net), addr, peer_id,
844 n->capabilities, 915 n->capabilities,
845 tipc_bc_sndlink(n->net), n->bc_entry.link, 916 tipc_bc_sndlink(n->net), n->bc_entry.link,
846 &le->inputq, 917 &le->inputq,