aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2017-10-13 05:04:25 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-13 11:46:00 -0400
commitae236fb208a6fbbd2e7a6913385e8fb78ac807f8 (patch)
tree451b5798223b599434923a90243a94372d7c6cf1 /net/tipc/socket.c
parent31c82a2d9d51fccbb85cbd2be983eb115225301c (diff)
tipc: receive group membership events via member socket
Like with any other service, group members' availability can be subscribed for by connecting to be topology server. However, because the events arrive via a different socket than the member socket, there is a real risk that membership events my arrive out of synch with the actual JOIN/LEAVE action. I.e., it is possible to receive the first messages from a new member before the corresponding JOIN event arrives, just as it is possible to receive the last messages from a leaving member after the LEAVE event has already been received. Since each member socket is internally also subscribing for membership events, we now fix this problem by passing those events on to the user via the member socket. We leverage the already present member synch- ronization protocol to guarantee correct message/event order. An event is delivered to the user as an empty message where the two source addresses identify the new/lost member. Furthermore, we set the MSG_OOB bit in the message flags to mark it as an event. If the event is an indication about a member loss we also set the MSG_EOR bit, so it can be distinguished from a member addition event. 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>
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 25ecf1201527..0a2eac309177 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -709,41 +709,43 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
709 poll_table *wait) 709 poll_table *wait)
710{ 710{
711 struct sock *sk = sock->sk; 711 struct sock *sk = sock->sk;
712 struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
712 struct tipc_sock *tsk = tipc_sk(sk); 713 struct tipc_sock *tsk = tipc_sk(sk);
713 struct tipc_group *grp = tsk->group; 714 struct tipc_group *grp = tsk->group;
714 u32 mask = 0; 715 u32 revents = 0;
715 716
716 sock_poll_wait(file, sk_sleep(sk), wait); 717 sock_poll_wait(file, sk_sleep(sk), wait);
717 718
718 if (sk->sk_shutdown & RCV_SHUTDOWN) 719 if (sk->sk_shutdown & RCV_SHUTDOWN)
719 mask |= POLLRDHUP | POLLIN | POLLRDNORM; 720 revents |= POLLRDHUP | POLLIN | POLLRDNORM;
720 if (sk->sk_shutdown == SHUTDOWN_MASK) 721 if (sk->sk_shutdown == SHUTDOWN_MASK)
721 mask |= POLLHUP; 722 revents |= POLLHUP;
722 723
723 switch (sk->sk_state) { 724 switch (sk->sk_state) {
724 case TIPC_ESTABLISHED: 725 case TIPC_ESTABLISHED:
725 if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk)) 726 if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
726 mask |= POLLOUT; 727 revents |= POLLOUT;
727 /* fall thru' */ 728 /* fall thru' */
728 case TIPC_LISTEN: 729 case TIPC_LISTEN:
729 case TIPC_CONNECTING: 730 case TIPC_CONNECTING:
730 if (!skb_queue_empty(&sk->sk_receive_queue)) 731 if (skb)
731 mask |= (POLLIN | POLLRDNORM); 732 revents |= POLLIN | POLLRDNORM;
732 break; 733 break;
733 case TIPC_OPEN: 734 case TIPC_OPEN:
734 if (!grp || tipc_group_size(grp)) 735 if (!grp || tipc_group_size(grp))
735 if (!tsk->cong_link_cnt) 736 if (!tsk->cong_link_cnt)
736 mask |= POLLOUT; 737 revents |= POLLOUT;
737 if (tipc_sk_type_connectionless(sk) && 738 if (!tipc_sk_type_connectionless(sk))
738 (!skb_queue_empty(&sk->sk_receive_queue))) 739 break;
739 mask |= (POLLIN | POLLRDNORM); 740 if (!skb)
741 break;
742 revents |= POLLIN | POLLRDNORM;
740 break; 743 break;
741 case TIPC_DISCONNECTING: 744 case TIPC_DISCONNECTING:
742 mask = (POLLIN | POLLRDNORM | POLLHUP); 745 revents = POLLIN | POLLRDNORM | POLLHUP;
743 break; 746 break;
744 } 747 }
745 748 return revents;
746 return mask;
747} 749}
748 750
749/** 751/**
@@ -1415,11 +1417,12 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
1415 size_t buflen, int flags) 1417 size_t buflen, int flags)
1416{ 1418{
1417 struct sock *sk = sock->sk; 1419 struct sock *sk = sock->sk;
1418 struct tipc_sock *tsk = tipc_sk(sk);
1419 struct sk_buff *skb;
1420 struct tipc_msg *hdr;
1421 bool connected = !tipc_sk_type_connectionless(sk); 1420 bool connected = !tipc_sk_type_connectionless(sk);
1421 struct tipc_sock *tsk = tipc_sk(sk);
1422 int rc, err, hlen, dlen, copy; 1422 int rc, err, hlen, dlen, copy;
1423 struct tipc_msg *hdr;
1424 struct sk_buff *skb;
1425 bool grp_evt;
1423 long timeout; 1426 long timeout;
1424 1427
1425 /* Catch invalid receive requests */ 1428 /* Catch invalid receive requests */
@@ -1443,6 +1446,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
1443 dlen = msg_data_sz(hdr); 1446 dlen = msg_data_sz(hdr);
1444 hlen = msg_hdr_sz(hdr); 1447 hlen = msg_hdr_sz(hdr);
1445 err = msg_errcode(hdr); 1448 err = msg_errcode(hdr);
1449 grp_evt = msg_is_grp_evt(hdr);
1446 if (likely(dlen || err)) 1450 if (likely(dlen || err))
1447 break; 1451 break;
1448 tsk_advance_rx_queue(sk); 1452 tsk_advance_rx_queue(sk);
@@ -1469,11 +1473,20 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
1469 if (unlikely(rc)) 1473 if (unlikely(rc))
1470 goto exit; 1474 goto exit;
1471 1475
1476 /* Mark message as group event if applicable */
1477 if (unlikely(grp_evt)) {
1478 if (msg_grp_evt(hdr) == TIPC_WITHDRAWN)
1479 m->msg_flags |= MSG_EOR;
1480 m->msg_flags |= MSG_OOB;
1481 copy = 0;
1482 }
1483
1472 /* Caption of data or error code/rejected data was successful */ 1484 /* Caption of data or error code/rejected data was successful */
1473 if (unlikely(flags & MSG_PEEK)) 1485 if (unlikely(flags & MSG_PEEK))
1474 goto exit; 1486 goto exit;
1475 1487
1476 tsk_advance_rx_queue(sk); 1488 tsk_advance_rx_queue(sk);
1489
1477 if (likely(!connected)) 1490 if (likely(!connected))
1478 goto exit; 1491 goto exit;
1479 1492
@@ -1648,10 +1661,10 @@ static void tipc_sk_proto_rcv(struct sock *sk,
1648 sk->sk_write_space(sk); 1661 sk->sk_write_space(sk);
1649 break; 1662 break;
1650 case GROUP_PROTOCOL: 1663 case GROUP_PROTOCOL:
1651 tipc_group_proto_rcv(grp, hdr, xmitq); 1664 tipc_group_proto_rcv(grp, hdr, inputq, xmitq);
1652 break; 1665 break;
1653 case TOP_SRV: 1666 case TOP_SRV:
1654 tipc_group_member_evt(tsk->group, skb, xmitq); 1667 tipc_group_member_evt(tsk->group, skb, inputq, xmitq);
1655 skb = NULL; 1668 skb = NULL;
1656 break; 1669 break;
1657 default: 1670 default: