aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/discover.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/discover.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/discover.c')
-rw-r--r--net/tipc/discover.c126
1 files changed, 107 insertions, 19 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index b4c4cd176b9b..e7655736abed 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * net/tipc/discover.c 2 * net/tipc/discover.c
3 * 3 *
4 * Copyright (c) 2003-2006, 2014-2015, Ericsson AB 4 * Copyright (c) 2003-2006, 2014-2018, Ericsson AB
5 * Copyright (c) 2005-2006, 2010-2011, Wind River Systems 5 * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
@@ -78,34 +78,40 @@ struct tipc_discoverer {
78 * @b: ptr to bearer issuing message 78 * @b: ptr to bearer issuing message
79 */ 79 */
80static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, 80static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb,
81 u32 mtyp, struct tipc_bearer *b) 81 u32 mtyp, struct tipc_bearer *b)
82{ 82{
83 struct tipc_net *tn = tipc_net(net); 83 struct tipc_net *tn = tipc_net(net);
84 u32 self = tipc_own_addr(net);
85 u32 dest_domain = b->domain; 84 u32 dest_domain = b->domain;
86 struct tipc_msg *hdr; 85 struct tipc_msg *hdr;
87 86
88 hdr = buf_msg(skb); 87 hdr = buf_msg(skb);
89 tipc_msg_init(self, hdr, LINK_CONFIG, mtyp, 88 tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
90 MAX_H_SIZE, dest_domain); 89 MAX_H_SIZE, dest_domain);
90 msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
91 msg_set_non_seq(hdr, 1); 91 msg_set_non_seq(hdr, 1);
92 msg_set_node_sig(hdr, tn->random); 92 msg_set_node_sig(hdr, tn->random);
93 msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES); 93 msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
94 msg_set_dest_domain(hdr, dest_domain); 94 msg_set_dest_domain(hdr, dest_domain);
95 msg_set_bc_netid(hdr, tn->net_id); 95 msg_set_bc_netid(hdr, tn->net_id);
96 b->media->addr2msg(msg_media_addr(hdr), &b->addr); 96 b->media->addr2msg(msg_media_addr(hdr), &b->addr);
97 msg_set_node_id(hdr, tipc_own_id(net));
97} 98}
98 99
99static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, u32 src, 100static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
101 u32 src, u32 sugg_addr,
100 struct tipc_media_addr *maddr, 102 struct tipc_media_addr *maddr,
101 struct tipc_bearer *b) 103 struct tipc_bearer *b)
102{ 104{
105 struct tipc_msg *hdr;
103 struct sk_buff *skb; 106 struct sk_buff *skb;
104 107
105 skb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); 108 skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
106 if (!skb) 109 if (!skb)
107 return; 110 return;
111 hdr = buf_msg(skb);
108 tipc_disc_init_msg(net, skb, mtyp, b); 112 tipc_disc_init_msg(net, skb, mtyp, b);
113 msg_set_sugg_node_addr(hdr, sugg_addr);
114 msg_set_dest_domain(hdr, dst);
109 tipc_bearer_xmit_skb(net, b->identity, skb, maddr); 115 tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
110} 116}
111 117
@@ -126,6 +132,52 @@ static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
126 media_addr_str, b->name); 132 media_addr_str, b->name);
127} 133}
128 134
135/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
136 */
137bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,
138 struct tipc_media_addr *maddr,
139 struct tipc_bearer *b,
140 u32 dst, u32 src,
141 u32 sugg_addr,
142 u8 *peer_id,
143 int mtyp)
144{
145 struct net *net = d->net;
146 struct tipc_net *tn = tipc_net(net);
147 bool trial = time_before(jiffies, tn->addr_trial_end);
148 u32 self = tipc_own_addr(net);
149
150 if (mtyp == DSC_TRIAL_FAIL_MSG) {
151 if (!trial)
152 return true;
153
154 /* Ignore if somebody else already gave new suggestion */
155 if (dst != tn->trial_addr)
156 return true;
157
158 /* Otherwise update trial address and restart trial period */
159 tn->trial_addr = sugg_addr;
160 msg_set_prevnode(buf_msg(d->skb), sugg_addr);
161 tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
162 return true;
163 }
164
165 /* Apply trial address if we just left trial period */
166 if (!trial && !self) {
167 tipc_net_finalize(net, tn->trial_addr);
168 msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
169 }
170
171 if (mtyp != DSC_TRIAL_MSG)
172 return false;
173
174 sugg_addr = tipc_node_try_addr(net, peer_id, src);
175 if (sugg_addr)
176 tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src,
177 self, sugg_addr, maddr, b);
178 return true;
179}
180
129/** 181/**
130 * tipc_disc_rcv - handle incoming discovery message (request or response) 182 * tipc_disc_rcv - handle incoming discovery message (request or response)
131 * @net: applicable net namespace 183 * @net: applicable net namespace
@@ -139,17 +191,27 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
139 struct tipc_msg *hdr = buf_msg(skb); 191 struct tipc_msg *hdr = buf_msg(skb);
140 u16 caps = msg_node_capabilities(hdr); 192 u16 caps = msg_node_capabilities(hdr);
141 bool legacy = tn->legacy_addr_format; 193 bool legacy = tn->legacy_addr_format;
194 u32 sugg = msg_sugg_node_addr(hdr);
142 u32 signature = msg_node_sig(hdr); 195 u32 signature = msg_node_sig(hdr);
196 u8 peer_id[NODE_ID_LEN] = {0,};
143 u32 dst = msg_dest_domain(hdr); 197 u32 dst = msg_dest_domain(hdr);
144 u32 net_id = msg_bc_netid(hdr); 198 u32 net_id = msg_bc_netid(hdr);
145 u32 self = tipc_own_addr(net);
146 struct tipc_media_addr maddr; 199 struct tipc_media_addr maddr;
147 u32 src = msg_prevnode(hdr); 200 u32 src = msg_prevnode(hdr);
148 u32 mtyp = msg_type(hdr); 201 u32 mtyp = msg_type(hdr);
149 bool dupl_addr = false; 202 bool dupl_addr = false;
150 bool respond = false; 203 bool respond = false;
204 u32 self;
151 int err; 205 int err;
152 206
207 skb_linearize(skb);
208 hdr = buf_msg(skb);
209
210 if (caps & TIPC_NODE_ID128)
211 memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
212 else
213 sprintf(peer_id, "%x", src);
214
153 err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr)); 215 err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
154 kfree_skb(skb); 216 kfree_skb(skb);
155 if (err || maddr.broadcast) { 217 if (err || maddr.broadcast) {
@@ -161,6 +223,12 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
161 return; 223 return;
162 if (net_id != tn->net_id) 224 if (net_id != tn->net_id)
163 return; 225 return;
226 if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst,
227 src, sugg, peer_id, mtyp))
228 return;
229 self = tipc_own_addr(net);
230
231 /* Message from somebody using this node's address */
164 if (in_own_node(net, src)) { 232 if (in_own_node(net, src)) {
165 disc_dupl_alert(b, self, &maddr); 233 disc_dupl_alert(b, self, &maddr);
166 return; 234 return;
@@ -169,8 +237,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
169 return; 237 return;
170 if (!tipc_in_scope(legacy, b->domain, src)) 238 if (!tipc_in_scope(legacy, b->domain, src))
171 return; 239 return;
172 240 tipc_node_check_dest(net, src, peer_id, b, caps, signature,
173 tipc_node_check_dest(net, src, b, caps, signature,
174 &maddr, &respond, &dupl_addr); 241 &maddr, &respond, &dupl_addr);
175 if (dupl_addr) 242 if (dupl_addr)
176 disc_dupl_alert(b, src, &maddr); 243 disc_dupl_alert(b, src, &maddr);
@@ -178,7 +245,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
178 return; 245 return;
179 if (mtyp != DSC_REQ_MSG) 246 if (mtyp != DSC_REQ_MSG)
180 return; 247 return;
181 tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, &maddr, b); 248 tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b);
182} 249}
183 250
184/* tipc_disc_add_dest - increment set of discovered nodes 251/* tipc_disc_add_dest - increment set of discovered nodes
@@ -216,9 +283,11 @@ void tipc_disc_remove_dest(struct tipc_discoverer *d)
216static void tipc_disc_timeout(struct timer_list *t) 283static void tipc_disc_timeout(struct timer_list *t)
217{ 284{
218 struct tipc_discoverer *d = from_timer(d, t, timer); 285 struct tipc_discoverer *d = from_timer(d, t, timer);
286 struct tipc_net *tn = tipc_net(d->net);
287 u32 self = tipc_own_addr(d->net);
219 struct tipc_media_addr maddr; 288 struct tipc_media_addr maddr;
220 struct sk_buff *skb = NULL; 289 struct sk_buff *skb = NULL;
221 struct net *net; 290 struct net *net = d->net;
222 u32 bearer_id; 291 u32 bearer_id;
223 292
224 spin_lock_bh(&d->lock); 293 spin_lock_bh(&d->lock);
@@ -228,16 +297,29 @@ static void tipc_disc_timeout(struct timer_list *t)
228 d->timer_intv = TIPC_DISC_INACTIVE; 297 d->timer_intv = TIPC_DISC_INACTIVE;
229 goto exit; 298 goto exit;
230 } 299 }
300
301 /* Did we just leave the address trial period ? */
302 if (!self && !time_before(jiffies, tn->addr_trial_end)) {
303 self = tn->trial_addr;
304 tipc_net_finalize(net, self);
305 msg_set_prevnode(buf_msg(d->skb), self);
306 msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
307 }
308
231 /* Adjust timeout interval according to discovery phase */ 309 /* Adjust timeout interval according to discovery phase */
232 d->timer_intv *= 2; 310 if (time_before(jiffies, tn->addr_trial_end)) {
233 if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW) 311 d->timer_intv = TIPC_DISC_INIT;
234 d->timer_intv = TIPC_DISC_SLOW; 312 } else {
235 else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST) 313 d->timer_intv *= 2;
236 d->timer_intv = TIPC_DISC_FAST; 314 if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
315 d->timer_intv = TIPC_DISC_SLOW;
316 else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
317 d->timer_intv = TIPC_DISC_FAST;
318 }
319
237 mod_timer(&d->timer, jiffies + d->timer_intv); 320 mod_timer(&d->timer, jiffies + d->timer_intv);
238 memcpy(&maddr, &d->dest, sizeof(maddr)); 321 memcpy(&maddr, &d->dest, sizeof(maddr));
239 skb = skb_clone(d->skb, GFP_ATOMIC); 322 skb = skb_clone(d->skb, GFP_ATOMIC);
240 net = d->net;
241 bearer_id = d->bearer_id; 323 bearer_id = d->bearer_id;
242exit: 324exit:
243 spin_unlock_bh(&d->lock); 325 spin_unlock_bh(&d->lock);
@@ -257,18 +339,24 @@ exit:
257int tipc_disc_create(struct net *net, struct tipc_bearer *b, 339int tipc_disc_create(struct net *net, struct tipc_bearer *b,
258 struct tipc_media_addr *dest, struct sk_buff **skb) 340 struct tipc_media_addr *dest, struct sk_buff **skb)
259{ 341{
342 struct tipc_net *tn = tipc_net(net);
260 struct tipc_discoverer *d; 343 struct tipc_discoverer *d;
261 344
262 d = kmalloc(sizeof(*d), GFP_ATOMIC); 345 d = kmalloc(sizeof(*d), GFP_ATOMIC);
263 if (!d) 346 if (!d)
264 return -ENOMEM; 347 return -ENOMEM;
265 d->skb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); 348 d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
266 if (!d->skb) { 349 if (!d->skb) {
267 kfree(d); 350 kfree(d);
268 return -ENOMEM; 351 return -ENOMEM;
269 } 352 }
270
271 tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b); 353 tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
354
355 /* Do we need an address trial period first ? */
356 if (!tipc_own_addr(net)) {
357 tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
358 msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG);
359 }
272 memcpy(&d->dest, dest, sizeof(*dest)); 360 memcpy(&d->dest, dest, sizeof(*dest));
273 d->net = net; 361 d->net = net;
274 d->bearer_id = b->identity; 362 d->bearer_id = b->identity;