aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2015-07-30 18:24:21 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-30 20:25:14 -0400
commit662921cd0a53db4504838dfbb7d996f9e6e94001 (patch)
tree22093f4240391972cd6bcf879cbdfe963a73bdb1 /net/tipc
parent5045f7b9009f1455268b98cecbcc271663934c85 (diff)
tipc: merge link->exec_mode and link->state into one FSM
Until now, we have been handling link failover and synchronization by using an additional link state variable, "exec_mode". This variable is not independent of the link FSM state, something causing a risk of inconsistencies, apart from the fact that it clutters the code. The conditions are now in place to define a new link FSM that covers all existing use cases, including failover and synchronization, and eliminate the "exec_mode" field altogether. The FSM must also support non-atomic resetting of links, which will be introduced later. The new link FSM is shown below, with 7 states and 8 events. Only events leading to state change are shown as edges. +------------------------------------+ |RESET_EVT | | | | +--------------+ | +-----------------| SYNCHING |-----------------+ | |FAILURE_EVT +--------------+ PEER_RESET_EVT| | | A | | | | | | | | | | | | | | |SYNCH_ |SYNCH_ | | | |BEGIN_EVT |END_EVT | | | | | | | V | V V | +-------------+ +--------------+ +------------+ | | RESETTING |<---------| ESTABLISHED |--------->| PEER_RESET | | +-------------+ FAILURE_ +--------------+ PEER_ +------------+ | | EVT | A RESET_EVT | | | | | | | | | | | | | +--------------+ | | | RESET_EVT| |RESET_EVT |ESTABLISH_EVT | | | | | | | | | | | | V V | | | +-------------+ +--------------+ RESET_EVT| +--->| RESET |--------->| ESTABLISHING |<----------------+ +-------------+ PEER_ +--------------+ | A RESET_EVT | | | | | | | |FAILOVER_ |FAILOVER_ |FAILOVER_ |BEGIN_EVT |END_EVT |BEGIN_EVT | | | V | | +-------------+ | | FAILINGOVER |<----------------+ +-------------+ These changes are fully backwards compatible. Tested-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')
-rw-r--r--net/tipc/link.c350
-rw-r--r--net/tipc/link.h25
-rw-r--r--net/tipc/node.c31
3 files changed, 226 insertions, 180 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 9a3ccf910c49..9840b03348e1 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -50,7 +50,6 @@
50 */ 50 */
51static const char *link_co_err = "Link tunneling error, "; 51static const char *link_co_err = "Link tunneling error, ";
52static const char *link_rst_msg = "Resetting link "; 52static const char *link_rst_msg = "Resetting link ";
53static const char *link_unk_evt = "Unknown link event ";
54 53
55static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { 54static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
56 [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC }, 55 [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC },
@@ -85,46 +84,23 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
85 */ 84 */
86#define WILDCARD_SESSION 0x10000 85#define WILDCARD_SESSION 0x10000
87 86
88/* State value stored in 'failover_pkts' 87/* Link FSM states:
89 */ 88 */
90#define FIRST_FAILOVER 0xffffu
91
92/* Link FSM states and events:
93 */
94enum {
95 TIPC_LINK_WORKING,
96 TIPC_LINK_PROBING,
97 TIPC_LINK_RESETTING,
98 TIPC_LINK_ESTABLISHING
99};
100
101enum { 89enum {
102 PEER_RESET_EVT = RESET_MSG, 90 LINK_ESTABLISHED = 0xe,
103 ACTIVATE_EVT = ACTIVATE_MSG, 91 LINK_ESTABLISHING = 0xe << 4,
104 TRAFFIC_EVT, /* Any other valid msg from peer */ 92 LINK_RESET = 0x1 << 8,
105 SILENCE_EVT /* Peer was silent during last timer interval*/ 93 LINK_RESETTING = 0x2 << 12,
94 LINK_PEER_RESET = 0xd << 16,
95 LINK_FAILINGOVER = 0xf << 20,
96 LINK_SYNCHING = 0xc << 24
106}; 97};
107 98
108/* Link FSM state checking routines 99/* Link FSM state checking routines
109 */ 100 */
110static int link_working(struct tipc_link *l) 101static int link_is_up(struct tipc_link *l)
111{
112 return l->state == TIPC_LINK_WORKING;
113}
114
115static int link_probing(struct tipc_link *l)
116{
117 return l->state == TIPC_LINK_PROBING;
118}
119
120static int link_resetting(struct tipc_link *l)
121{ 102{
122 return l->state == TIPC_LINK_RESETTING; 103 return l->state & (LINK_ESTABLISHED | LINK_SYNCHING);
123}
124
125static int link_establishing(struct tipc_link *l)
126{
127 return l->state == TIPC_LINK_ESTABLISHING;
128} 104}
129 105
130static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, 106static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
@@ -141,11 +117,29 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb);
141/* 117/*
142 * Simple non-static link routines (i.e. referenced outside this file) 118 * Simple non-static link routines (i.e. referenced outside this file)
143 */ 119 */
144int tipc_link_is_up(struct tipc_link *l_ptr) 120bool tipc_link_is_up(struct tipc_link *l)
145{ 121{
146 if (!l_ptr) 122 return link_is_up(l);
147 return 0; 123}
148 return link_working(l_ptr) || link_probing(l_ptr); 124
125bool tipc_link_is_reset(struct tipc_link *l)
126{
127 return l->state & (LINK_RESET | LINK_FAILINGOVER | LINK_ESTABLISHING);
128}
129
130bool tipc_link_is_synching(struct tipc_link *l)
131{
132 return l->state == LINK_SYNCHING;
133}
134
135bool tipc_link_is_failingover(struct tipc_link *l)
136{
137 return l->state == LINK_FAILINGOVER;
138}
139
140bool tipc_link_is_blocked(struct tipc_link *l)
141{
142 return l->state & (LINK_RESETTING | LINK_PEER_RESET | LINK_FAILINGOVER);
149} 143}
150 144
151int tipc_link_is_active(struct tipc_link *l) 145int tipc_link_is_active(struct tipc_link *l)
@@ -210,7 +204,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
210 l_ptr->tolerance = b_ptr->tolerance; 204 l_ptr->tolerance = b_ptr->tolerance;
211 l_ptr->snd_nxt = 1; 205 l_ptr->snd_nxt = 1;
212 l_ptr->rcv_nxt = 1; 206 l_ptr->rcv_nxt = 1;
213 l_ptr->state = TIPC_LINK_RESETTING; 207 l_ptr->state = LINK_RESET;
214 208
215 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg; 209 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
216 msg = l_ptr->pmsg; 210 msg = l_ptr->pmsg;
@@ -265,120 +259,159 @@ void tipc_link_build_bcast_sync_msg(struct tipc_link *l,
265 * tipc_link_fsm_evt - link finite state machine 259 * tipc_link_fsm_evt - link finite state machine
266 * @l: pointer to link 260 * @l: pointer to link
267 * @evt: state machine event to be processed 261 * @evt: state machine event to be processed
268 * @xmitq: queue to prepend created protocol message, if any
269 */ 262 */
270static int tipc_link_fsm_evt(struct tipc_link *l, int evt, 263int tipc_link_fsm_evt(struct tipc_link *l, int evt)
271 struct sk_buff_head *xmitq)
272{ 264{
273 int rc = 0; 265 int rc = 0;
274 struct tipc_link *pl;
275 enum {
276 LINK_RESET = 1,
277 LINK_ACTIVATE = (1 << 1),
278 SND_PROBE = (1 << 2),
279 SND_STATE = (1 << 3),
280 SND_RESET = (1 << 4),
281 SND_ACTIVATE = (1 << 5),
282 SND_BCAST_SYNC = (1 << 6)
283 } actions = 0;
284
285 if (l->exec_mode == TIPC_LINK_BLOCKED)
286 return rc;
287 266
288 switch (l->state) { 267 switch (l->state) {
289 case TIPC_LINK_WORKING: 268 case LINK_RESETTING:
290 switch (evt) { 269 switch (evt) {
291 case TRAFFIC_EVT: 270 case LINK_PEER_RESET_EVT:
292 case ACTIVATE_EVT: 271 l->state = LINK_PEER_RESET;
293 break; 272 break;
294 case SILENCE_EVT: 273 case LINK_RESET_EVT:
295 l->state = TIPC_LINK_PROBING; 274 l->state = LINK_RESET;
296 actions |= SND_PROBE; 275 break;
276 case LINK_FAILURE_EVT:
277 case LINK_FAILOVER_BEGIN_EVT:
278 case LINK_ESTABLISH_EVT:
279 case LINK_FAILOVER_END_EVT:
280 case LINK_SYNCH_BEGIN_EVT:
281 case LINK_SYNCH_END_EVT:
282 default:
283 goto illegal_evt;
284 }
285 break;
286 case LINK_RESET:
287 switch (evt) {
288 case LINK_PEER_RESET_EVT:
289 l->state = LINK_ESTABLISHING;
297 break; 290 break;
298 case PEER_RESET_EVT: 291 case LINK_FAILOVER_BEGIN_EVT:
299 actions |= LINK_RESET | SND_ACTIVATE; 292 l->state = LINK_FAILINGOVER;
293 case LINK_FAILURE_EVT:
294 case LINK_RESET_EVT:
295 case LINK_ESTABLISH_EVT:
296 case LINK_FAILOVER_END_EVT:
300 break; 297 break;
298 case LINK_SYNCH_BEGIN_EVT:
299 case LINK_SYNCH_END_EVT:
301 default: 300 default:
302 pr_debug("%s%u WORKING\n", link_unk_evt, evt); 301 goto illegal_evt;
303 } 302 }
304 break; 303 break;
305 case TIPC_LINK_PROBING: 304 case LINK_PEER_RESET:
306 switch (evt) { 305 switch (evt) {
307 case TRAFFIC_EVT: 306 case LINK_RESET_EVT:
308 case ACTIVATE_EVT: 307 l->state = LINK_ESTABLISHING;
309 l->state = TIPC_LINK_WORKING;
310 break; 308 break;
311 case PEER_RESET_EVT: 309 case LINK_PEER_RESET_EVT:
312 actions |= LINK_RESET | SND_ACTIVATE; 310 case LINK_ESTABLISH_EVT:
311 case LINK_FAILURE_EVT:
313 break; 312 break;
314 case SILENCE_EVT: 313 case LINK_SYNCH_BEGIN_EVT:
315 if (l->silent_intv_cnt <= l->abort_limit) { 314 case LINK_SYNCH_END_EVT:
316 actions |= SND_PROBE; 315 case LINK_FAILOVER_BEGIN_EVT:
317 break; 316 case LINK_FAILOVER_END_EVT:
318 } 317 default:
319 actions |= LINK_RESET | SND_RESET; 318 goto illegal_evt;
319 }
320 break;
321 case LINK_FAILINGOVER:
322 switch (evt) {
323 case LINK_FAILOVER_END_EVT:
324 l->state = LINK_RESET;
320 break; 325 break;
326 case LINK_PEER_RESET_EVT:
327 case LINK_RESET_EVT:
328 case LINK_ESTABLISH_EVT:
329 case LINK_FAILURE_EVT:
330 break;
331 case LINK_FAILOVER_BEGIN_EVT:
332 case LINK_SYNCH_BEGIN_EVT:
333 case LINK_SYNCH_END_EVT:
321 default: 334 default:
322 pr_err("%s%u PROBING\n", link_unk_evt, evt); 335 goto illegal_evt;
323 } 336 }
324 break; 337 break;
325 case TIPC_LINK_RESETTING: 338 case LINK_ESTABLISHING:
326 switch (evt) { 339 switch (evt) {
327 case TRAFFIC_EVT: 340 case LINK_ESTABLISH_EVT:
341 l->state = LINK_ESTABLISHED;
342 rc |= TIPC_LINK_UP_EVT;
328 break; 343 break;
329 case ACTIVATE_EVT: 344 case LINK_FAILOVER_BEGIN_EVT:
330 pl = node_active_link(l->owner, 0); 345 l->state = LINK_FAILINGOVER;
331 if (pl && link_probing(pl)) 346 break;
332 break; 347 case LINK_PEER_RESET_EVT:
333 l->state = TIPC_LINK_WORKING; 348 case LINK_RESET_EVT:
334 actions |= LINK_ACTIVATE; 349 case LINK_FAILURE_EVT:
335 if (!l->owner->working_links) 350 case LINK_SYNCH_BEGIN_EVT:
336 actions |= SND_BCAST_SYNC; 351 case LINK_FAILOVER_END_EVT:
352 break;
353 case LINK_SYNCH_END_EVT:
354 default:
355 goto illegal_evt;
356 }
357 break;
358 case LINK_ESTABLISHED:
359 switch (evt) {
360 case LINK_PEER_RESET_EVT:
361 l->state = LINK_PEER_RESET;
362 rc |= TIPC_LINK_DOWN_EVT;
363 break;
364 case LINK_FAILURE_EVT:
365 l->state = LINK_RESETTING;
366 rc |= TIPC_LINK_DOWN_EVT;
337 break; 367 break;
338 case PEER_RESET_EVT: 368 case LINK_RESET_EVT:
339 l->state = TIPC_LINK_ESTABLISHING; 369 l->state = LINK_RESET;
340 actions |= SND_ACTIVATE;
341 break; 370 break;
342 case SILENCE_EVT: 371 case LINK_ESTABLISH_EVT:
343 actions |= SND_RESET;
344 break; 372 break;
373 case LINK_SYNCH_BEGIN_EVT:
374 l->state = LINK_SYNCHING;
375 break;
376 case LINK_SYNCH_END_EVT:
377 case LINK_FAILOVER_BEGIN_EVT:
378 case LINK_FAILOVER_END_EVT:
345 default: 379 default:
346 pr_err("%s%u in RESETTING\n", link_unk_evt, evt); 380 goto illegal_evt;
347 } 381 }
348 break; 382 break;
349 case TIPC_LINK_ESTABLISHING: 383 case LINK_SYNCHING:
350 switch (evt) { 384 switch (evt) {
351 case TRAFFIC_EVT: 385 case LINK_PEER_RESET_EVT:
352 case ACTIVATE_EVT: 386 l->state = LINK_PEER_RESET;
353 pl = node_active_link(l->owner, 0); 387 rc |= TIPC_LINK_DOWN_EVT;
354 if (pl && link_probing(pl)) 388 break;
355 break; 389 case LINK_FAILURE_EVT:
356 l->state = TIPC_LINK_WORKING; 390 l->state = LINK_RESETTING;
357 actions |= LINK_ACTIVATE; 391 rc |= TIPC_LINK_DOWN_EVT;
358 if (!l->owner->working_links)
359 actions |= SND_BCAST_SYNC;
360 break; 392 break;
361 case PEER_RESET_EVT: 393 case LINK_RESET_EVT:
394 l->state = LINK_RESET;
362 break; 395 break;
363 case SILENCE_EVT: 396 case LINK_ESTABLISH_EVT:
364 actions |= SND_ACTIVATE; 397 case LINK_SYNCH_BEGIN_EVT:
365 break; 398 break;
399 case LINK_SYNCH_END_EVT:
400 l->state = LINK_ESTABLISHED;
401 break;
402 case LINK_FAILOVER_BEGIN_EVT:
403 case LINK_FAILOVER_END_EVT:
366 default: 404 default:
367 pr_err("%s%u ESTABLISHING\n", link_unk_evt, evt); 405 goto illegal_evt;
368 } 406 }
369 break; 407 break;
370 default: 408 default:
371 pr_err("Unknown link state %u/%u\n", l->state, evt); 409 pr_err("Unknown FSM state %x in %s\n", l->state, l->name);
372 }
373
374 /* Perform actions as decided by FSM */
375 if (actions & LINK_RESET) {
376 l->exec_mode = TIPC_LINK_BLOCKED;
377 rc = TIPC_LINK_DOWN_EVT;
378 } 410 }
379 if (actions & LINK_ACTIVATE) 411 return rc;
380 rc = TIPC_LINK_UP_EVT; 412illegal_evt:
381 413 pr_err("Illegal FSM event %x in state %x on link %s\n",
414 evt, l->state, l->name);
382 return rc; 415 return rc;
383} 416}
384 417
@@ -432,12 +465,11 @@ int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)
432 bool xmit = false; 465 bool xmit = false;
433 bool prb = false; 466 bool prb = false;
434 467
435 if (l->exec_mode == TIPC_LINK_BLOCKED)
436 return rc;
437
438 link_profile_stats(l); 468 link_profile_stats(l);
439 469
440 if (l->state == TIPC_LINK_WORKING) { 470 switch (l->state) {
471 case LINK_ESTABLISHED:
472 case LINK_SYNCHING:
441 if (!l->silent_intv_cnt) { 473 if (!l->silent_intv_cnt) {
442 if (tipc_bclink_acks_missing(l->owner)) 474 if (tipc_bclink_acks_missing(l->owner))
443 xmit = true; 475 xmit = true;
@@ -445,17 +477,26 @@ int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)
445 xmit = true; 477 xmit = true;
446 prb = true; 478 prb = true;
447 } else { 479 } else {
448 l->exec_mode = TIPC_LINK_BLOCKED; 480 rc |= tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
449 rc |= TIPC_LINK_DOWN_EVT;
450 } 481 }
451 l->silent_intv_cnt++; 482 l->silent_intv_cnt++;
452 } else if (l->state == TIPC_LINK_RESETTING) { 483 break;
484 case LINK_RESET:
453 xmit = true; 485 xmit = true;
454 mtyp = RESET_MSG; 486 mtyp = RESET_MSG;
455 } else if (l->state == TIPC_LINK_ESTABLISHING) { 487 break;
488 case LINK_ESTABLISHING:
456 xmit = true; 489 xmit = true;
457 mtyp = ACTIVATE_MSG; 490 mtyp = ACTIVATE_MSG;
491 break;
492 case LINK_RESETTING:
493 case LINK_PEER_RESET:
494 case LINK_FAILINGOVER:
495 break;
496 default:
497 break;
458 } 498 }
499
459 if (xmit) 500 if (xmit)
460 tipc_link_build_proto_msg(l, mtyp, prb, 0, 0, 0, xmitq); 501 tipc_link_build_proto_msg(l, mtyp, prb, 0, 0, 0, xmitq);
461 502
@@ -559,7 +600,7 @@ void tipc_link_reset(struct tipc_link *l)
559{ 600{
560 struct tipc_node *owner = l->owner; 601 struct tipc_node *owner = l->owner;
561 602
562 l->state = TIPC_LINK_RESETTING; 603 tipc_link_fsm_evt(l, LINK_RESET_EVT);
563 604
564 /* Link is down, accept any session */ 605 /* Link is down, accept any session */
565 l->peer_session = WILDCARD_SESSION; 606 l->peer_session = WILDCARD_SESSION;
@@ -902,8 +943,7 @@ static int tipc_link_retransm(struct tipc_link *l, int retransm,
902 l->stale_count = 1; 943 l->stale_count = 1;
903 } else if (++l->stale_count > 100) { 944 } else if (++l->stale_count > 100) {
904 link_retransmit_failure(l, skb); 945 link_retransmit_failure(l, skb);
905 l->exec_mode = TIPC_LINK_BLOCKED; 946 return tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
906 return TIPC_LINK_DOWN_EVT;
907 } 947 }
908 skb_queue_walk(&l->transmq, skb) { 948 skb_queue_walk(&l->transmq, skb) {
909 if (!retransm) 949 if (!retransm)
@@ -1002,25 +1042,23 @@ static int tipc_link_input(struct tipc_link *l, struct sk_buff *skb)
1002 l->stats.recv_bundled += msg_msgcnt(hdr); 1042 l->stats.recv_bundled += msg_msgcnt(hdr);
1003 while (tipc_msg_extract(skb, &iskb, &pos)) 1043 while (tipc_msg_extract(skb, &iskb, &pos))
1004 tipc_data_input(l, iskb); 1044 tipc_data_input(l, iskb);
1005 return rc; 1045 return 0;
1006 } else if (usr == MSG_FRAGMENTER) { 1046 } else if (usr == MSG_FRAGMENTER) {
1007 l->stats.recv_fragments++; 1047 l->stats.recv_fragments++;
1008 if (tipc_buf_append(reasm_skb, &skb)) { 1048 if (tipc_buf_append(reasm_skb, &skb)) {
1009 l->stats.recv_fragmented++; 1049 l->stats.recv_fragmented++;
1010 tipc_data_input(l, skb); 1050 tipc_data_input(l, skb);
1011 } else if (!*reasm_skb) { 1051 } else if (!*reasm_skb) {
1012 l->exec_mode = TIPC_LINK_BLOCKED; 1052 return tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
1013 l->state = TIPC_LINK_RESETTING;
1014 rc = TIPC_LINK_DOWN_EVT;
1015 } 1053 }
1016 return rc; 1054 return 0;
1017 } else if (usr == BCAST_PROTOCOL) { 1055 } else if (usr == BCAST_PROTOCOL) {
1018 tipc_link_sync_rcv(node, skb); 1056 tipc_link_sync_rcv(node, skb);
1019 return rc; 1057 return 0;
1020 } 1058 }
1021drop: 1059drop:
1022 kfree_skb(skb); 1060 kfree_skb(skb);
1023 return rc; 1061 return 0;
1024} 1062}
1025 1063
1026static bool tipc_link_release_pkts(struct tipc_link *l, u16 acked) 1064static bool tipc_link_release_pkts(struct tipc_link *l, u16 acked)
@@ -1068,9 +1106,9 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
1068 continue; 1106 continue;
1069 } 1107 }
1070 1108
1071 if (unlikely(!link_working(l))) { 1109 if (unlikely(!link_is_up(l))) {
1072 rc = tipc_link_fsm_evt(l, TRAFFIC_EVT, xmitq); 1110 rc = tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
1073 if (!link_working(l)) { 1111 if (!link_is_up(l)) {
1074 kfree_skb(__skb_dequeue(arrvq)); 1112 kfree_skb(__skb_dequeue(arrvq));
1075 return rc; 1113 return rc;
1076 } 1114 }
@@ -1192,7 +1230,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
1192 int node_up = l->owner->bclink.recv_permitted; 1230 int node_up = l->owner->bclink.recv_permitted;
1193 1231
1194 /* Don't send protocol message during reset or link failover */ 1232 /* Don't send protocol message during reset or link failover */
1195 if (l->exec_mode == TIPC_LINK_BLOCKED) 1233 if (tipc_link_is_blocked(l))
1196 return; 1234 return;
1197 1235
1198 msg_set_type(hdr, mtyp); 1236 msg_set_type(hdr, mtyp);
@@ -1302,7 +1340,6 @@ tnl:
1302 tnl->drop_point = l->rcv_nxt; 1340 tnl->drop_point = l->rcv_nxt;
1303 tnl->failover_reasm_skb = l->reasm_buf; 1341 tnl->failover_reasm_skb = l->reasm_buf;
1304 l->reasm_buf = NULL; 1342 l->reasm_buf = NULL;
1305 l->exec_mode = TIPC_LINK_BLOCKED;
1306 } 1343 }
1307} 1344}
1308 1345
@@ -1323,7 +1360,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
1323 char *if_name; 1360 char *if_name;
1324 int rc = 0; 1361 int rc = 0;
1325 1362
1326 if (l->exec_mode == TIPC_LINK_BLOCKED) 1363 if (tipc_link_is_blocked(l))
1327 goto exit; 1364 goto exit;
1328 1365
1329 if (link_own_addr(l) > msg_prevnode(hdr)) 1366 if (link_own_addr(l) > msg_prevnode(hdr))
@@ -1337,6 +1374,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
1337 (l->peer_session != WILDCARD_SESSION)) 1374 (l->peer_session != WILDCARD_SESSION))
1338 break; 1375 break;
1339 /* fall thru' */ 1376 /* fall thru' */
1377
1340 case ACTIVATE_MSG: 1378 case ACTIVATE_MSG:
1341 1379
1342 /* Complete own link name with peer's interface name */ 1380 /* Complete own link name with peer's interface name */
@@ -1355,13 +1393,20 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
1355 if (in_range(peers_prio, l->priority + 1, TIPC_MAX_LINK_PRI)) 1393 if (in_range(peers_prio, l->priority + 1, TIPC_MAX_LINK_PRI))
1356 l->priority = peers_prio; 1394 l->priority = peers_prio;
1357 1395
1396 if (msg_type(hdr) == RESET_MSG) {
1397 rc |= tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT);
1398 } else if (!link_is_up(l)) {
1399 tipc_link_fsm_evt(l, LINK_PEER_RESET_EVT);
1400 rc |= tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
1401 }
1358 l->peer_session = msg_session(hdr); 1402 l->peer_session = msg_session(hdr);
1359 l->peer_bearer_id = msg_bearer_id(hdr); 1403 l->peer_bearer_id = msg_bearer_id(hdr);
1360 rc = tipc_link_fsm_evt(l, msg_type(hdr), xmitq);
1361 if (l->mtu > msg_max_pkt(hdr)) 1404 if (l->mtu > msg_max_pkt(hdr))
1362 l->mtu = msg_max_pkt(hdr); 1405 l->mtu = msg_max_pkt(hdr);
1363 break; 1406 break;
1407
1364 case STATE_MSG: 1408 case STATE_MSG:
1409
1365 /* Update own tolerance if peer indicates a non-zero value */ 1410 /* Update own tolerance if peer indicates a non-zero value */
1366 if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL)) 1411 if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
1367 l->tolerance = peers_tol; 1412 l->tolerance = peers_tol;
@@ -1370,11 +1415,11 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
1370 l->stats.recv_states++; 1415 l->stats.recv_states++;
1371 if (msg_probe(hdr)) 1416 if (msg_probe(hdr))
1372 l->stats.recv_probes++; 1417 l->stats.recv_probes++;
1373 rc = tipc_link_fsm_evt(l, TRAFFIC_EVT, xmitq); 1418 rc = tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
1374 if (!tipc_link_is_up(l)) 1419 if (!link_is_up(l))
1375 break; 1420 break;
1376 1421
1377 /* Has peer sent packets we haven't received yet ? */ 1422 /* Send NACK if peer has sent pkts we haven't received yet */
1378 if (more(peers_snd_nxt, l->rcv_nxt)) 1423 if (more(peers_snd_nxt, l->rcv_nxt))
1379 rcvgap = peers_snd_nxt - l->rcv_nxt; 1424 rcvgap = peers_snd_nxt - l->rcv_nxt;
1380 if (rcvgap || (msg_probe(hdr))) 1425 if (rcvgap || (msg_probe(hdr)))
@@ -1387,6 +1432,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
1387 rc = tipc_link_retransm(l, nacked_gap, xmitq); 1432 rc = tipc_link_retransm(l, nacked_gap, xmitq);
1388 l->stats.recv_nacks++; 1433 l->stats.recv_nacks++;
1389 } 1434 }
1435
1390 tipc_link_advance_backlog(l, xmitq); 1436 tipc_link_advance_backlog(l, xmitq);
1391 if (unlikely(!skb_queue_empty(&l->wakeupq))) 1437 if (unlikely(!skb_queue_empty(&l->wakeupq)))
1392 link_prepare_wakeup(l); 1438 link_prepare_wakeup(l);
@@ -1463,19 +1509,7 @@ static void link_print(struct tipc_link *l, const char *str)
1463 u16 head = hskb ? msg_seqno(buf_msg(hskb)) : l->snd_nxt; 1509 u16 head = hskb ? msg_seqno(buf_msg(hskb)) : l->snd_nxt;
1464 u16 tail = l->snd_nxt - 1; 1510 u16 tail = l->snd_nxt - 1;
1465 1511
1466 pr_info("%s Link <%s>:", str, l->name); 1512 pr_info("%s Link <%s> state %x\n", str, l->name, l->state);
1467
1468 if (link_probing(l))
1469 pr_cont(":P\n");
1470 else if (link_establishing(l))
1471 pr_cont(":E\n");
1472 else if (link_resetting(l))
1473 pr_cont(":R\n");
1474 else if (link_working(l))
1475 pr_cont(":W\n");
1476 else
1477 pr_cont("\n");
1478
1479 pr_info("XMTQ: %u [%u-%u], BKLGQ: %u, SNDNX: %u, RCVNX: %u\n", 1513 pr_info("XMTQ: %u [%u-%u], BKLGQ: %u, SNDNX: %u, RCVNX: %u\n",
1480 skb_queue_len(&l->transmq), head, tail, 1514 skb_queue_len(&l->transmq), head, tail,
1481 skb_queue_len(&l->backlogq), l->snd_nxt, l->rcv_nxt); 1515 skb_queue_len(&l->backlogq), l->snd_nxt, l->rcv_nxt);
diff --git a/net/tipc/link.h b/net/tipc/link.h
index b317c4df9079..39b8c4c5121e 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -49,13 +49,17 @@
49 */ 49 */
50#define INVALID_LINK_SEQ 0x10000 50#define INVALID_LINK_SEQ 0x10000
51 51
52 52/* Link FSM events:
53/* Link endpoint receive states
54 */ 53 */
55enum { 54enum {
56 TIPC_LINK_OPEN, 55 LINK_ESTABLISH_EVT = 0xec1ab1e,
57 TIPC_LINK_BLOCKED, 56 LINK_PEER_RESET_EVT = 0x9eed0e,
58 TIPC_LINK_TUNNEL 57 LINK_FAILURE_EVT = 0xfa110e,
58 LINK_RESET_EVT = 0x10ca1d0e,
59 LINK_FAILOVER_BEGIN_EVT = 0xfa110bee,
60 LINK_FAILOVER_END_EVT = 0xfa110ede,
61 LINK_SYNCH_BEGIN_EVT = 0xc1ccbee,
62 LINK_SYNCH_END_EVT = 0xc1ccede
59}; 63};
60 64
61/* Events returned from link at packet reception or at timeout 65/* Events returned from link at packet reception or at timeout
@@ -120,7 +124,6 @@ struct tipc_stats {
120 * @pmsg: convenience pointer to "proto_msg" field 124 * @pmsg: convenience pointer to "proto_msg" field
121 * @priority: current link priority 125 * @priority: current link priority
122 * @net_plane: current link network plane ('A' through 'H') 126 * @net_plane: current link network plane ('A' through 'H')
123 * @exec_mode: transmit/receive mode for link endpoint instance
124 * @backlog_limit: backlog queue congestion thresholds (indexed by importance) 127 * @backlog_limit: backlog queue congestion thresholds (indexed by importance)
125 * @exp_msg_count: # of tunnelled messages expected during link changeover 128 * @exp_msg_count: # of tunnelled messages expected during link changeover
126 * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset 129 * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset
@@ -155,7 +158,7 @@ struct tipc_link {
155 u32 tolerance; 158 u32 tolerance;
156 unsigned long keepalive_intv; 159 unsigned long keepalive_intv;
157 u32 abort_limit; 160 u32 abort_limit;
158 int state; 161 u32 state;
159 u32 silent_intv_cnt; 162 u32 silent_intv_cnt;
160 struct { 163 struct {
161 unchar hdr[INT_H_SIZE]; 164 unchar hdr[INT_H_SIZE];
@@ -166,7 +169,6 @@ struct tipc_link {
166 char net_plane; 169 char net_plane;
167 170
168 /* Failover/synch */ 171 /* Failover/synch */
169 u8 exec_mode;
170 u16 drop_point; 172 u16 drop_point;
171 struct sk_buff *failover_reasm_skb; 173 struct sk_buff *failover_reasm_skb;
172 174
@@ -214,8 +216,13 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
214 int mtyp, struct sk_buff_head *xmitq); 216 int mtyp, struct sk_buff_head *xmitq);
215void tipc_link_build_bcast_sync_msg(struct tipc_link *l, 217void tipc_link_build_bcast_sync_msg(struct tipc_link *l,
216 struct sk_buff_head *xmitq); 218 struct sk_buff_head *xmitq);
219int tipc_link_fsm_evt(struct tipc_link *l, int evt);
217void tipc_link_reset_fragments(struct tipc_link *l_ptr); 220void tipc_link_reset_fragments(struct tipc_link *l_ptr);
218int tipc_link_is_up(struct tipc_link *l_ptr); 221bool tipc_link_is_up(struct tipc_link *l);
222bool tipc_link_is_reset(struct tipc_link *l);
223bool tipc_link_is_synching(struct tipc_link *l);
224bool tipc_link_is_failingover(struct tipc_link *l);
225bool tipc_link_is_blocked(struct tipc_link *l);
219int tipc_link_is_active(struct tipc_link *l_ptr); 226int tipc_link_is_active(struct tipc_link *l_ptr);
220void tipc_link_purge_queues(struct tipc_link *l_ptr); 227void tipc_link_purge_queues(struct tipc_link *l_ptr);
221void tipc_link_purge_backlog(struct tipc_link *l); 228void tipc_link_purge_backlog(struct tipc_link *l);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 9e20acffb3d4..a3ceeda2a80a 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -334,7 +334,6 @@ static void tipc_node_link_up(struct tipc_node *n, int bearer_id,
334 if (!ol) { 334 if (!ol) {
335 *slot0 = bearer_id; 335 *slot0 = bearer_id;
336 *slot1 = bearer_id; 336 *slot1 = bearer_id;
337 nl->exec_mode = TIPC_LINK_OPEN;
338 tipc_link_build_bcast_sync_msg(nl, xmitq); 337 tipc_link_build_bcast_sync_msg(nl, xmitq);
339 node_established_contact(n); 338 node_established_contact(n);
340 return; 339 return;
@@ -368,7 +367,7 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id)
368 struct sk_buff_head xmitq; 367 struct sk_buff_head xmitq;
369 368
370 l = n->links[bearer_id].link; 369 l = n->links[bearer_id].link;
371 if (!l || !tipc_link_is_up(l)) 370 if (!l || tipc_link_is_reset(l))
372 return; 371 return;
373 372
374 __skb_queue_head_init(&xmitq); 373 __skb_queue_head_init(&xmitq);
@@ -414,6 +413,7 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id)
414 n->sync_point = tnl->rcv_nxt + (U16_MAX / 2 - 1); 413 n->sync_point = tnl->rcv_nxt + (U16_MAX / 2 - 1);
415 tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, &xmitq); 414 tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, &xmitq);
416 tipc_link_reset(l); 415 tipc_link_reset(l);
416 tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT);
417 tipc_bearer_xmit(n->net, tnl->bearer_id, &xmitq, maddr); 417 tipc_bearer_xmit(n->net, tnl->bearer_id, &xmitq, maddr);
418} 418}
419 419
@@ -749,7 +749,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
749 struct tipc_link *l_ptr = n_ptr->links[i].link; 749 struct tipc_link *l_ptr = n_ptr->links[i].link;
750 if (!l_ptr) 750 if (!l_ptr)
751 continue; 751 continue;
752 l_ptr->exec_mode = TIPC_LINK_OPEN; 752 tipc_link_fsm_evt(l_ptr, LINK_FAILOVER_END_EVT);
753 kfree_skb(l_ptr->failover_reasm_skb); 753 kfree_skb(l_ptr->failover_reasm_skb);
754 l_ptr->failover_reasm_skb = NULL; 754 l_ptr->failover_reasm_skb = NULL;
755 tipc_link_reset_fragments(l_ptr); 755 tipc_link_reset_fragments(l_ptr);
@@ -989,7 +989,7 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
989 * Returns true if state is ok, otherwise consumes buffer and returns false 989 * Returns true if state is ok, otherwise consumes buffer and returns false
990 */ 990 */
991static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, 991static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
992 int bearer_id) 992 int bearer_id, struct sk_buff_head *xmitq)
993{ 993{
994 struct tipc_msg *hdr = buf_msg(skb); 994 struct tipc_msg *hdr = buf_msg(skb);
995 int usr = msg_user(hdr); 995 int usr = msg_user(hdr);
@@ -1042,42 +1042,47 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
1042 /* Initiate or update failover mode if applicable */ 1042 /* Initiate or update failover mode if applicable */
1043 if ((usr == TUNNEL_PROTOCOL) && (mtyp == FAILOVER_MSG)) { 1043 if ((usr == TUNNEL_PROTOCOL) && (mtyp == FAILOVER_MSG)) {
1044 syncpt = oseqno + exp_pkts - 1; 1044 syncpt = oseqno + exp_pkts - 1;
1045 if (pl && tipc_link_is_up(pl)) { 1045 if (pl && tipc_link_is_up(pl))
1046 tipc_node_link_down(n, pl->bearer_id); 1046 tipc_node_link_down(n, pl->bearer_id);
1047 pl->exec_mode = TIPC_LINK_BLOCKED; 1047
1048 }
1049 /* If pkts arrive out of order, use lowest calculated syncpt */ 1048 /* If pkts arrive out of order, use lowest calculated syncpt */
1050 if (less(syncpt, n->sync_point)) 1049 if (less(syncpt, n->sync_point))
1051 n->sync_point = syncpt; 1050 n->sync_point = syncpt;
1052 } 1051 }
1053 1052
1054 /* Open parallel link when tunnel link reaches synch point */ 1053 /* Open parallel link when tunnel link reaches synch point */
1055 if ((n->state == NODE_FAILINGOVER) && (more(rcv_nxt, n->sync_point))) { 1054 if ((n->state == NODE_FAILINGOVER) && !tipc_link_is_failingover(l)) {
1055 if (!more(rcv_nxt, n->sync_point))
1056 return true;
1056 tipc_node_fsm_evt(n, NODE_FAILOVER_END_EVT); 1057 tipc_node_fsm_evt(n, NODE_FAILOVER_END_EVT);
1057 if (pl) 1058 if (pl)
1058 pl->exec_mode = TIPC_LINK_OPEN; 1059 tipc_link_fsm_evt(pl, LINK_FAILOVER_END_EVT);
1059 return true; 1060 return true;
1060 } 1061 }
1061 1062
1062 /* Initiate or update synch mode if applicable */ 1063 /* Initiate or update synch mode if applicable */
1063 if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) { 1064 if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) {
1064 syncpt = iseqno + exp_pkts - 1; 1065 syncpt = iseqno + exp_pkts - 1;
1066 if (!tipc_link_is_up(l)) {
1067 tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
1068 tipc_node_link_up(n, bearer_id, xmitq);
1069 }
1065 if (n->state == SELF_UP_PEER_UP) { 1070 if (n->state == SELF_UP_PEER_UP) {
1066 n->sync_point = syncpt; 1071 n->sync_point = syncpt;
1072 tipc_link_fsm_evt(l, LINK_SYNCH_BEGIN_EVT);
1067 tipc_node_fsm_evt(n, NODE_SYNCH_BEGIN_EVT); 1073 tipc_node_fsm_evt(n, NODE_SYNCH_BEGIN_EVT);
1068 } 1074 }
1069 l->exec_mode = TIPC_LINK_TUNNEL;
1070 if (less(syncpt, n->sync_point)) 1075 if (less(syncpt, n->sync_point))
1071 n->sync_point = syncpt; 1076 n->sync_point = syncpt;
1072 } 1077 }
1073 1078
1074 /* Open tunnel link when parallel link reaches synch point */ 1079 /* Open tunnel link when parallel link reaches synch point */
1075 if ((n->state == NODE_SYNCHING) && (l->exec_mode == TIPC_LINK_TUNNEL)) { 1080 if ((n->state == NODE_SYNCHING) && tipc_link_is_synching(l)) {
1076 if (pl) 1081 if (pl)
1077 dlv_nxt = mod(pl->rcv_nxt - skb_queue_len(pl->inputq)); 1082 dlv_nxt = mod(pl->rcv_nxt - skb_queue_len(pl->inputq));
1078 if (!pl || more(dlv_nxt, n->sync_point)) { 1083 if (!pl || more(dlv_nxt, n->sync_point)) {
1084 tipc_link_fsm_evt(l, LINK_SYNCH_END_EVT);
1079 tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); 1085 tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT);
1080 l->exec_mode = TIPC_LINK_OPEN;
1081 return true; 1086 return true;
1082 } 1087 }
1083 if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) 1088 if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG))
@@ -1143,7 +1148,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
1143 tipc_bclink_acknowledge(n, msg_bcast_ack(hdr)); 1148 tipc_bclink_acknowledge(n, msg_bcast_ack(hdr));
1144 1149
1145 /* Check and if necessary update node state */ 1150 /* Check and if necessary update node state */
1146 if (likely(tipc_node_check_state(n, skb, bearer_id))) { 1151 if (likely(tipc_node_check_state(n, skb, bearer_id, &xmitq))) {
1147 rc = tipc_link_rcv(le->link, skb, &xmitq); 1152 rc = tipc_link_rcv(le->link, skb, &xmitq);
1148 skb = NULL; 1153 skb = NULL;
1149 } 1154 }