Skip to content

Commit b87a5ea

Browse files
Jon Maloydavem330
authored andcommitted
tipc: guarantee group unicast doesn't bypass group broadcast
Group unicast messages don't follow the same path as broadcast messages, and there is a high risk that unicasts sent from a socket might bypass previously sent broadcasts from the same socket. We fix this by letting all unicast messages carry the sequence number of the next sent broadcast from the same node, but without updating this number at the receiver. This way, a receiver can check and if necessary re-order such messages before they are added to the socket receive buffer. Signed-off-by: Jon Maloy <[email protected]> Acked-by: Ying Xue <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5b8dddb commit b87a5ea

File tree

2 files changed

+74
-15
lines changed

2 files changed

+74
-15
lines changed

net/tipc/group.c

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct tipc_member {
6262
struct list_head list;
6363
struct list_head congested;
6464
struct sk_buff *event_msg;
65+
struct sk_buff_head deferredq;
6566
struct tipc_group *group;
6667
u32 node;
6768
u32 port;
@@ -253,6 +254,7 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
253254
return NULL;
254255
INIT_LIST_HEAD(&m->list);
255256
INIT_LIST_HEAD(&m->congested);
257+
__skb_queue_head_init(&m->deferredq);
256258
m->group = grp;
257259
m->node = node;
258260
m->port = port;
@@ -380,29 +382,54 @@ bool tipc_group_bc_cong(struct tipc_group *grp, int len)
380382
return tipc_group_cong(grp, m->node, m->port, len, &m);
381383
}
382384

385+
/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number
386+
*/
387+
static void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq)
388+
{
389+
struct tipc_msg *_hdr, *hdr = buf_msg(skb);
390+
u16 bc_seqno = msg_grp_bc_seqno(hdr);
391+
struct sk_buff *_skb, *tmp;
392+
int mtyp = msg_type(hdr);
393+
394+
/* Bcast may be bypassed by unicast, - sort it in */
395+
if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) {
396+
skb_queue_walk_safe(defq, _skb, tmp) {
397+
_hdr = buf_msg(_skb);
398+
if (!less(bc_seqno, msg_grp_bc_seqno(_hdr)))
399+
continue;
400+
__skb_queue_before(defq, _skb, skb);
401+
return;
402+
}
403+
/* Bcast was not bypassed, - add to tail */
404+
}
405+
/* Unicasts are never bypassed, - always add to tail */
406+
__skb_queue_tail(defq, skb);
407+
}
408+
383409
/* tipc_group_filter_msg() - determine if we should accept arriving message
384410
*/
385411
void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
386412
struct sk_buff_head *xmitq)
387413
{
388414
struct sk_buff *skb = __skb_dequeue(inputq);
415+
struct sk_buff_head *defq;
389416
struct tipc_member *m;
390417
struct tipc_msg *hdr;
418+
bool deliver, update;
391419
u32 node, port;
392-
int mtyp;
420+
int mtyp, blks;
393421

394422
if (!skb)
395423
return;
396424

397425
hdr = buf_msg(skb);
398-
mtyp = msg_type(hdr);
399426
node = msg_orignode(hdr);
400427
port = msg_origport(hdr);
401428

402429
if (!msg_in_group(hdr))
403430
goto drop;
404431

405-
if (mtyp == TIPC_GRP_MEMBER_EVT) {
432+
if (msg_is_grp_evt(hdr)) {
406433
if (!grp->events)
407434
goto drop;
408435
__skb_queue_tail(inputq, skb);
@@ -413,22 +440,52 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
413440
if (!tipc_group_is_receiver(m))
414441
goto drop;
415442

416-
m->bc_rcv_nxt = msg_grp_bc_seqno(hdr) + 1;
443+
if (less(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
444+
goto drop;
417445

418-
/* Drop multicast here if not for this member */
419-
if (mtyp == TIPC_GRP_MCAST_MSG) {
420-
if (msg_nameinst(hdr) != grp->instance) {
421-
m->bc_rcv_nxt = msg_grp_bc_seqno(hdr) + 1;
422-
tipc_group_update_rcv_win(grp, msg_blocks(hdr),
423-
node, port, xmitq);
424-
kfree_skb(skb);
425-
return;
446+
TIPC_SKB_CB(skb)->orig_member = m->instance;
447+
defq = &m->deferredq;
448+
tipc_group_sort_msg(skb, defq);
449+
450+
while ((skb = skb_peek(defq))) {
451+
hdr = buf_msg(skb);
452+
mtyp = msg_type(hdr);
453+
deliver = true;
454+
update = false;
455+
456+
if (more(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
457+
break;
458+
459+
/* Decide what to do with message */
460+
switch (mtyp) {
461+
case TIPC_GRP_MCAST_MSG:
462+
if (msg_nameinst(hdr) != grp->instance) {
463+
update = true;
464+
deliver = false;
465+
}
466+
/* Fall thru */
467+
case TIPC_GRP_BCAST_MSG:
468+
m->bc_rcv_nxt++;
469+
break;
470+
case TIPC_GRP_UCAST_MSG:
471+
break;
472+
default:
473+
break;
426474
}
427-
}
428475

429-
TIPC_SKB_CB(skb)->orig_member = m->instance;
430-
__skb_queue_tail(inputq, skb);
476+
/* Execute decisions */
477+
__skb_dequeue(defq);
478+
if (deliver)
479+
__skb_queue_tail(inputq, skb);
480+
else
481+
kfree_skb(skb);
482+
483+
if (!update)
484+
continue;
431485

486+
blks = msg_blocks(hdr);
487+
tipc_group_update_rcv_win(grp, blks, node, port, xmitq);
488+
}
432489
return;
433490
drop:
434491
kfree_skb(skb);

net/tipc/socket.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ static int tipc_send_group_msg(struct net *net, struct tipc_sock *tsk,
830830
struct msghdr *m, struct tipc_member *mb,
831831
u32 dnode, u32 dport, int dlen)
832832
{
833+
u16 bc_snd_nxt = tipc_group_bc_snd_nxt(tsk->group);
833834
int blks = tsk_blocks(GROUP_H_SIZE + dlen);
834835
struct tipc_msg *hdr = &tsk->phdr;
835836
struct sk_buff_head pkts;
@@ -840,6 +841,7 @@ static int tipc_send_group_msg(struct net *net, struct tipc_sock *tsk,
840841
msg_set_hdr_sz(hdr, GROUP_H_SIZE);
841842
msg_set_destport(hdr, dport);
842843
msg_set_destnode(hdr, dnode);
844+
msg_set_grp_bc_seqno(hdr, bc_snd_nxt);
843845

844846
/* Build message as chain of buffers */
845847
skb_queue_head_init(&pkts);

0 commit comments

Comments
 (0)