aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2017-10-13 05:04:30 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-13 11:46:01 -0400
commitb87a5ea31c935a7f7e11ca85df2ec7917921e96d (patch)
tree6d8d1235da6271bea5506b6564205583a4772305
parent5b8dddb63769587badc50725ec9857caaeba4de0 (diff)
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 <jon.maloy@ericsson.com> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/group.c87
-rw-r--r--net/tipc/socket.c2
2 files changed, 74 insertions, 15 deletions
diff --git a/net/tipc/group.c b/net/tipc/group.c
index ffac2f33fce2..985e0ce32e8e 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -62,6 +62,7 @@ struct tipc_member {
62 struct list_head list; 62 struct list_head list;
63 struct list_head congested; 63 struct list_head congested;
64 struct sk_buff *event_msg; 64 struct sk_buff *event_msg;
65 struct sk_buff_head deferredq;
65 struct tipc_group *group; 66 struct tipc_group *group;
66 u32 node; 67 u32 node;
67 u32 port; 68 u32 port;
@@ -253,6 +254,7 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
253 return NULL; 254 return NULL;
254 INIT_LIST_HEAD(&m->list); 255 INIT_LIST_HEAD(&m->list);
255 INIT_LIST_HEAD(&m->congested); 256 INIT_LIST_HEAD(&m->congested);
257 __skb_queue_head_init(&m->deferredq);
256 m->group = grp; 258 m->group = grp;
257 m->node = node; 259 m->node = node;
258 m->port = port; 260 m->port = port;
@@ -380,29 +382,54 @@ bool tipc_group_bc_cong(struct tipc_group *grp, int len)
380 return tipc_group_cong(grp, m->node, m->port, len, &m); 382 return tipc_group_cong(grp, m->node, m->port, len, &m);
381} 383}
382 384
385/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number
386 */
387static 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
383/* tipc_group_filter_msg() - determine if we should accept arriving message 409/* tipc_group_filter_msg() - determine if we should accept arriving message
384 */ 410 */
385void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq, 411void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
386 struct sk_buff_head *xmitq) 412 struct sk_buff_head *xmitq)
387{ 413{
388 struct sk_buff *skb = __skb_dequeue(inputq); 414 struct sk_buff *skb = __skb_dequeue(inputq);
415 struct sk_buff_head *defq;
389 struct tipc_member *m; 416 struct tipc_member *m;
390 struct tipc_msg *hdr; 417 struct tipc_msg *hdr;
418 bool deliver, update;
391 u32 node, port; 419 u32 node, port;
392 int mtyp; 420 int mtyp, blks;
393 421
394 if (!skb) 422 if (!skb)
395 return; 423 return;
396 424
397 hdr = buf_msg(skb); 425 hdr = buf_msg(skb);
398 mtyp = msg_type(hdr);
399 node = msg_orignode(hdr); 426 node = msg_orignode(hdr);
400 port = msg_origport(hdr); 427 port = msg_origport(hdr);
401 428
402 if (!msg_in_group(hdr)) 429 if (!msg_in_group(hdr))
403 goto drop; 430 goto drop;
404 431
405 if (mtyp == TIPC_GRP_MEMBER_EVT) { 432 if (msg_is_grp_evt(hdr)) {
406 if (!grp->events) 433 if (!grp->events)
407 goto drop; 434 goto drop;
408 __skb_queue_tail(inputq, skb); 435 __skb_queue_tail(inputq, skb);
@@ -413,22 +440,52 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
413 if (!tipc_group_is_receiver(m)) 440 if (!tipc_group_is_receiver(m))
414 goto drop; 441 goto drop;
415 442
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;
417 445
418 /* Drop multicast here if not for this member */ 446 TIPC_SKB_CB(skb)->orig_member = m->instance;
419 if (mtyp == TIPC_GRP_MCAST_MSG) { 447 defq = &m->deferredq;
420 if (msg_nameinst(hdr) != grp->instance) { 448 tipc_group_sort_msg(skb, defq);
421 m->bc_rcv_nxt = msg_grp_bc_seqno(hdr) + 1; 449
422 tipc_group_update_rcv_win(grp, msg_blocks(hdr), 450 while ((skb = skb_peek(defq))) {
423 node, port, xmitq); 451 hdr = buf_msg(skb);
424 kfree_skb(skb); 452 mtyp = msg_type(hdr);
425 return; 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;
426 } 474 }
427 }
428 475
429 TIPC_SKB_CB(skb)->orig_member = m->instance; 476 /* Execute decisions */
430 __skb_queue_tail(inputq, skb); 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;
431 485
486 blks = msg_blocks(hdr);
487 tipc_group_update_rcv_win(grp, blks, node, port, xmitq);
488 }
432 return; 489 return;
433drop: 490drop:
434 kfree_skb(skb); 491 kfree_skb(skb);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 8fdd969e12bd..3276b7a0d445 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -830,6 +830,7 @@ static int tipc_send_group_msg(struct net *net, struct tipc_sock *tsk,
830 struct msghdr *m, struct tipc_member *mb, 830 struct msghdr *m, struct tipc_member *mb,
831 u32 dnode, u32 dport, int dlen) 831 u32 dnode, u32 dport, int dlen)
832{ 832{
833 u16 bc_snd_nxt = tipc_group_bc_snd_nxt(tsk->group);
833 int blks = tsk_blocks(GROUP_H_SIZE + dlen); 834 int blks = tsk_blocks(GROUP_H_SIZE + dlen);
834 struct tipc_msg *hdr = &tsk->phdr; 835 struct tipc_msg *hdr = &tsk->phdr;
835 struct sk_buff_head pkts; 836 struct sk_buff_head pkts;
@@ -840,6 +841,7 @@ static int tipc_send_group_msg(struct net *net, struct tipc_sock *tsk,
840 msg_set_hdr_sz(hdr, GROUP_H_SIZE); 841 msg_set_hdr_sz(hdr, GROUP_H_SIZE);
841 msg_set_destport(hdr, dport); 842 msg_set_destport(hdr, dport);
842 msg_set_destnode(hdr, dnode); 843 msg_set_destnode(hdr, dnode);
844 msg_set_grp_bc_seqno(hdr, bc_snd_nxt);
843 845
844 /* Build message as chain of buffers */ 846 /* Build message as chain of buffers */
845 skb_queue_head_init(&pkts); 847 skb_queue_head_init(&pkts);