Skip to content

Commit a3bada7

Browse files
Jon Maloydavem330
authored andcommitted
tipc: guarantee delivery of last broadcast before DOWN event
The following scenario is possible: - A user sends a broadcast message, and thereafter immediately leaves the group. - The LEAVE message, following a different path than the broadcast, arrives ahead of the broadcast, and the sending member is removed from the receiver's list. - The broadcast message arrives, but is dropped because the sender now is unknown to the receipient. We fix this by sequence numbering membership events, just like ordinary unicast messages. Currently, when a JOIN is sent to a peer, it contains a synchronization point, - the sequence number of the next sent broadcast, in order to give the receiver a start synchronization point. We now let even LEAVE messages contain such an "end synchronization" point, so that the recipient can delay the removal of the sending member until it knows that all messages have been received. The received synchronization points are added as sequence numbers to the generated membership events, making it possible to handle them almost the same way as regular unicasts in the receiving filter function. In particular, a DOWN event with a too high sequence number will be kept in the reordering queue until the missing broadcast(s) arrive and have been delivered. Signed-off-by: Jon Maloy <[email protected]> Acked-by: Ying Xue <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 399574d commit a3bada7

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

net/tipc/group.c

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct tipc_member {
7171
u16 advertised;
7272
u16 window;
7373
u16 bc_rcv_nxt;
74+
u16 bc_syncpt;
7475
u16 bc_acked;
7576
bool usr_pending;
7677
};
@@ -410,7 +411,7 @@ static void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq)
410411
struct sk_buff *_skb, *tmp;
411412
int mtyp = msg_type(hdr);
412413

413-
/* Bcast may be bypassed by unicast or other bcast, - sort it in */
414+
/* Bcast/mcast may be bypassed by ucast or other bcast, - sort it in */
414415
if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) {
415416
skb_queue_walk_safe(defq, _skb, tmp) {
416417
_hdr = buf_msg(_skb);
@@ -431,7 +432,7 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
431432
struct sk_buff_head *xmitq)
432433
{
433434
struct sk_buff *skb = __skb_dequeue(inputq);
434-
bool ack, deliver, update;
435+
bool ack, deliver, update, leave = false;
435436
struct sk_buff_head *defq;
436437
struct tipc_member *m;
437438
struct tipc_msg *hdr;
@@ -448,13 +449,6 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
448449
if (!msg_in_group(hdr))
449450
goto drop;
450451

451-
if (msg_is_grp_evt(hdr)) {
452-
if (!grp->events)
453-
goto drop;
454-
__skb_queue_tail(inputq, skb);
455-
return;
456-
}
457-
458452
m = tipc_group_find_member(grp, node, port);
459453
if (!tipc_group_is_receiver(m))
460454
goto drop;
@@ -490,6 +484,12 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
490484
break;
491485
case TIPC_GRP_UCAST_MSG:
492486
break;
487+
case TIPC_GRP_MEMBER_EVT:
488+
if (m->state == MBR_LEAVING)
489+
leave = true;
490+
if (!grp->events)
491+
deliver = false;
492+
break;
493493
default:
494494
break;
495495
}
@@ -504,6 +504,11 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
504504
if (ack)
505505
tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq);
506506

507+
if (leave) {
508+
tipc_group_delete_member(grp, m);
509+
__skb_queue_purge(defq);
510+
break;
511+
}
507512
if (!update)
508513
continue;
509514

@@ -561,6 +566,8 @@ static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
561566
msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
562567
msg_set_adv_win(hdr, adv);
563568
m->advertised += adv;
569+
} else if (mtyp == GRP_LEAVE_MSG) {
570+
msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
564571
} else if (mtyp == GRP_ADV_MSG) {
565572
msg_set_adv_win(hdr, adv);
566573
m->advertised += adv;
@@ -577,6 +584,7 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
577584
u32 node = msg_orignode(hdr);
578585
u32 port = msg_origport(hdr);
579586
struct tipc_member *m;
587+
struct tipc_msg *ehdr;
580588

581589
if (!grp)
582590
return;
@@ -590,7 +598,8 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
590598
MBR_QUARANTINED);
591599
if (!m)
592600
return;
593-
m->bc_rcv_nxt = msg_grp_bc_syncpt(hdr);
601+
m->bc_syncpt = msg_grp_bc_syncpt(hdr);
602+
m->bc_rcv_nxt = m->bc_syncpt;
594603
m->window += msg_adv_win(hdr);
595604

596605
/* Wait until PUBLISH event is received */
@@ -601,6 +610,8 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
601610
*usr_wakeup = true;
602611
m->usr_pending = false;
603612
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
613+
ehdr = buf_msg(m->event_msg);
614+
msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
604615
__skb_queue_tail(inputq, m->event_msg);
605616
}
606617
if (m->window < ADV_IDLE)
@@ -611,16 +622,18 @@ void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
611622
case GRP_LEAVE_MSG:
612623
if (!m)
613624
return;
625+
m->bc_syncpt = msg_grp_bc_syncpt(hdr);
614626

615627
/* Wait until WITHDRAW event is received */
616628
if (m->state != MBR_LEAVING) {
617629
m->state = MBR_LEAVING;
618630
return;
619631
}
620632
/* Otherwise deliver already received WITHDRAW event */
633+
ehdr = buf_msg(m->event_msg);
634+
msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
621635
__skb_queue_tail(inputq, m->event_msg);
622636
*usr_wakeup = true;
623-
tipc_group_delete_member(grp, m);
624637
list_del_init(&m->congested);
625638
return;
626639
case GRP_ADV_MSG:
@@ -662,6 +675,7 @@ void tipc_group_member_evt(struct tipc_group *grp,
662675
int event = evt->event;
663676
struct tipc_member *m;
664677
struct net *net;
678+
bool node_up;
665679
u32 self;
666680

667681
if (!grp)
@@ -695,6 +709,7 @@ void tipc_group_member_evt(struct tipc_group *grp,
695709
m->event_msg = skb;
696710
m->state = MBR_PUBLISHED;
697711
} else {
712+
msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
698713
__skb_queue_tail(inputq, skb);
699714
m->state = MBR_JOINED;
700715
*usr_wakeup = true;
@@ -715,14 +730,18 @@ void tipc_group_member_evt(struct tipc_group *grp,
715730

716731
*usr_wakeup = true;
717732
m->usr_pending = false;
733+
node_up = tipc_node_is_up(net, node);
718734

719735
/* Hold back event if more messages might be expected */
720-
if (m->state != MBR_LEAVING && tipc_node_is_up(net, node)) {
736+
if (m->state != MBR_LEAVING && node_up) {
721737
m->event_msg = skb;
722738
m->state = MBR_LEAVING;
723739
} else {
740+
if (node_up)
741+
msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
742+
else
743+
msg_set_grp_bc_seqno(hdr, m->bc_rcv_nxt);
724744
__skb_queue_tail(inputq, skb);
725-
tipc_group_delete_member(grp, m);
726745
}
727746
list_del_init(&m->congested);
728747
}

0 commit comments

Comments
 (0)