Skip to content

Commit 25b0b9c

Browse files
Jon Maloydavem330
Jon Maloy
authored andcommitted
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 <[email protected]> Signed-off-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d50ccc2 commit 25b0b9c

File tree

11 files changed

+236
-45
lines changed

11 files changed

+236
-45
lines changed

net/tipc/addr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void tipc_set_node_id(struct net *net, u8 *id)
5959

6060
memcpy(tn->node_id, id, NODE_ID_LEN);
6161
tipc_nodeid2string(tn->node_id_string, id);
62-
tn->node_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
62+
tn->trial_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
6363
pr_info("Own node identity %s, cluster identity %u\n",
6464
tipc_own_id_string(net), tn->net_id);
6565
}
@@ -74,6 +74,7 @@ void tipc_set_node_addr(struct net *net, u32 addr)
7474
sprintf(node_id, "%x", addr);
7575
tipc_set_node_id(net, node_id);
7676
}
77+
tn->trial_addr = addr;
7778
pr_info("32-bit node address hash set to %x\n", addr);
7879
}
7980

net/tipc/bearer.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ static int tipc_enable_bearer(struct net *net, const char *name,
235235
{
236236
struct tipc_net *tn = tipc_net(net);
237237
struct tipc_bearer_names b_names;
238-
u32 self = tipc_own_addr(net);
239238
int with_this_prio = 1;
240239
struct tipc_bearer *b;
241240
struct tipc_media *m;
@@ -244,7 +243,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
244243
int res = -EINVAL;
245244
char *errstr = "";
246245

247-
if (!self) {
246+
if (!tipc_own_id(net)) {
248247
errstr = "not supported in standalone mode";
249248
res = -ENOPROTOOPT;
250249
goto rejected;

net/tipc/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ static int __net_init tipc_init_net(struct net *net)
5757

5858
tn->net_id = 4711;
5959
tn->node_addr = 0;
60+
tn->trial_addr = 0;
61+
tn->addr_trial_end = 0;
6062
memset(tn->node_id, 0, sizeof(tn->node_id));
6163
memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
6264
tn->mon_threshold = TIPC_DEF_MON_THRESHOLD;

net/tipc/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ extern int sysctl_tipc_named_timeout __read_mostly;
8282
struct tipc_net {
8383
u8 node_id[NODE_ID_LEN];
8484
u32 node_addr;
85+
u32 trial_addr;
86+
unsigned long addr_trial_end;
8587
char node_id_string[NODE_ID_STR_LEN];
8688
int net_id;
8789
int random;

net/tipc/discover.c

Lines changed: 107 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* net/tipc/discover.c
33
*
4-
* Copyright (c) 2003-2006, 2014-2015, Ericsson AB
4+
* Copyright (c) 2003-2006, 2014-2018, Ericsson AB
55
* Copyright (c) 2005-2006, 2010-2011, Wind River Systems
66
* All rights reserved.
77
*
@@ -78,34 +78,40 @@ struct tipc_discoverer {
7878
* @b: ptr to bearer issuing message
7979
*/
8080
static 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)
8282
{
8383
struct tipc_net *tn = tipc_net(net);
84-
u32 self = tipc_own_addr(net);
8584
u32 dest_domain = b->domain;
8685
struct tipc_msg *hdr;
8786

8887
hdr = buf_msg(skb);
89-
tipc_msg_init(self, hdr, LINK_CONFIG, mtyp,
88+
tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
9089
MAX_H_SIZE, dest_domain);
90+
msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
9191
msg_set_non_seq(hdr, 1);
9292
msg_set_node_sig(hdr, tn->random);
9393
msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
9494
msg_set_dest_domain(hdr, dest_domain);
9595
msg_set_bc_netid(hdr, tn->net_id);
9696
b->media->addr2msg(msg_media_addr(hdr), &b->addr);
97+
msg_set_node_id(hdr, tipc_own_id(net));
9798
}
9899

99-
static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst, u32 src,
100+
static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
101+
u32 src, u32 sugg_addr,
100102
struct tipc_media_addr *maddr,
101103
struct tipc_bearer *b)
102104
{
105+
struct tipc_msg *hdr;
103106
struct sk_buff *skb;
104107

105-
skb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC);
108+
skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
106109
if (!skb)
107110
return;
111+
hdr = buf_msg(skb);
108112
tipc_disc_init_msg(net, skb, mtyp, b);
113+
msg_set_sugg_node_addr(hdr, sugg_addr);
114+
msg_set_dest_domain(hdr, dst);
109115
tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
110116
}
111117

@@ -126,6 +132,52 @@ static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
126132
media_addr_str, b->name);
127133
}
128134

135+
/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
136+
*/
137+
bool 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+
129181
/**
130182
* tipc_disc_rcv - handle incoming discovery message (request or response)
131183
* @net: applicable net namespace
@@ -139,17 +191,27 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
139191
struct tipc_msg *hdr = buf_msg(skb);
140192
u16 caps = msg_node_capabilities(hdr);
141193
bool legacy = tn->legacy_addr_format;
194+
u32 sugg = msg_sugg_node_addr(hdr);
142195
u32 signature = msg_node_sig(hdr);
196+
u8 peer_id[NODE_ID_LEN] = {0,};
143197
u32 dst = msg_dest_domain(hdr);
144198
u32 net_id = msg_bc_netid(hdr);
145-
u32 self = tipc_own_addr(net);
146199
struct tipc_media_addr maddr;
147200
u32 src = msg_prevnode(hdr);
148201
u32 mtyp = msg_type(hdr);
149202
bool dupl_addr = false;
150203
bool respond = false;
204+
u32 self;
151205
int err;
152206

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+
153215
err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
154216
kfree_skb(skb);
155217
if (err || maddr.broadcast) {
@@ -161,6 +223,12 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
161223
return;
162224
if (net_id != tn->net_id)
163225
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 */
164232
if (in_own_node(net, src)) {
165233
disc_dupl_alert(b, self, &maddr);
166234
return;
@@ -169,16 +237,15 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
169237
return;
170238
if (!tipc_in_scope(legacy, b->domain, src))
171239
return;
172-
173-
tipc_node_check_dest(net, src, b, caps, signature,
240+
tipc_node_check_dest(net, src, peer_id, b, caps, signature,
174241
&maddr, &respond, &dupl_addr);
175242
if (dupl_addr)
176243
disc_dupl_alert(b, src, &maddr);
177244
if (!respond)
178245
return;
179246
if (mtyp != DSC_REQ_MSG)
180247
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);
182249
}
183250

184251
/* tipc_disc_add_dest - increment set of discovered nodes
@@ -216,9 +283,11 @@ void tipc_disc_remove_dest(struct tipc_discoverer *d)
216283
static void tipc_disc_timeout(struct timer_list *t)
217284
{
218285
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);
219288
struct tipc_media_addr maddr;
220289
struct sk_buff *skb = NULL;
221-
struct net *net;
290+
struct net *net = d->net;
222291
u32 bearer_id;
223292

224293
spin_lock_bh(&d->lock);
@@ -228,16 +297,29 @@ static void tipc_disc_timeout(struct timer_list *t)
228297
d->timer_intv = TIPC_DISC_INACTIVE;
229298
goto exit;
230299
}
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+
231309
/* Adjust timeout interval according to discovery phase */
232-
d->timer_intv *= 2;
233-
if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
234-
d->timer_intv = TIPC_DISC_SLOW;
235-
else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
236-
d->timer_intv = TIPC_DISC_FAST;
310+
if (time_before(jiffies, tn->addr_trial_end)) {
311+
d->timer_intv = TIPC_DISC_INIT;
312+
} else {
313+
d->timer_intv *= 2;
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+
237320
mod_timer(&d->timer, jiffies + d->timer_intv);
238321
memcpy(&maddr, &d->dest, sizeof(maddr));
239322
skb = skb_clone(d->skb, GFP_ATOMIC);
240-
net = d->net;
241323
bearer_id = d->bearer_id;
242324
exit:
243325
spin_unlock_bh(&d->lock);
@@ -257,18 +339,24 @@ static void tipc_disc_timeout(struct timer_list *t)
257339
int tipc_disc_create(struct net *net, struct tipc_bearer *b,
258340
struct tipc_media_addr *dest, struct sk_buff **skb)
259341
{
342+
struct tipc_net *tn = tipc_net(net);
260343
struct tipc_discoverer *d;
261344

262345
d = kmalloc(sizeof(*d), GFP_ATOMIC);
263346
if (!d)
264347
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);
266349
if (!d->skb) {
267350
kfree(d);
268351
return -ENOMEM;
269352
}
270-
271353
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+
}
272360
memcpy(&d->dest, dest, sizeof(*dest));
273361
d->net = net;
274362
d->bearer_id = b->identity;

net/tipc/link.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -434,15 +434,16 @@ char *tipc_link_name(struct tipc_link *l)
434434
*/
435435
bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
436436
int tolerance, char net_plane, u32 mtu, int priority,
437-
int window, u32 session, u32 self, u32 peer,
438-
u16 peer_caps,
437+
int window, u32 session, u32 self,
438+
u32 peer, u8 *peer_id, u16 peer_caps,
439439
struct tipc_link *bc_sndlink,
440440
struct tipc_link *bc_rcvlink,
441441
struct sk_buff_head *inputq,
442442
struct sk_buff_head *namedq,
443443
struct tipc_link **link)
444444
{
445-
char *self_str = tipc_own_id_string(net);
445+
char peer_str[NODE_ID_STR_LEN] = {0,};
446+
char self_str[NODE_ID_STR_LEN] = {0,};
446447
struct tipc_link *l;
447448

448449
l = kzalloc(sizeof(*l), GFP_ATOMIC);
@@ -451,11 +452,18 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
451452
*link = l;
452453
l->session = session;
453454

454-
/* Note: peer i/f name is completed by reset/activate message */
455-
if (strlen(self_str) > 16)
456-
sprintf(l->name, "%x:%s-%x:unknown", self, if_name, peer);
457-
else
458-
sprintf(l->name, "%s:%s-%x:unknown", self_str, if_name, peer);
455+
/* Set link name for unicast links only */
456+
if (peer_id) {
457+
tipc_nodeid2string(self_str, tipc_own_id(net));
458+
if (strlen(self_str) > 16)
459+
sprintf(self_str, "%x", self);
460+
tipc_nodeid2string(peer_str, peer_id);
461+
if (strlen(peer_str) > 16)
462+
sprintf(peer_str, "%x", peer);
463+
}
464+
/* Peer i/f name will be completed by reset/activate message */
465+
sprintf(l->name, "%s:%s-%s:unknown", self_str, if_name, peer_str);
466+
459467
strcpy(l->if_name, if_name);
460468
l->addr = peer;
461469
l->peer_caps = peer_caps;
@@ -503,7 +511,7 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
503511
struct tipc_link *l;
504512

505513
if (!tipc_link_create(net, "", MAX_BEARERS, 0, 'Z', mtu, 0, window,
506-
0, ownnode, peer, peer_caps, bc_sndlink,
514+
0, ownnode, peer, NULL, peer_caps, bc_sndlink,
507515
NULL, inputq, namedq, link))
508516
return false;
509517

net/tipc/link.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ enum {
7373

7474
bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
7575
int tolerance, char net_plane, u32 mtu, int priority,
76-
int window, u32 session, u32 ownnode, u32 peer,
77-
u16 peer_caps,
76+
int window, u32 session, u32 ownnode,
77+
u32 peer, u8 *peer_id, u16 peer_caps,
7878
struct tipc_link *bc_sndlink,
7979
struct tipc_link *bc_rcvlink,
8080
struct sk_buff_head *inputq,

0 commit comments

Comments
 (0)