Skip to content

Commit ae236fb

Browse files
Jon Maloydavem330
authored andcommitted
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>
1 parent 31c82a2 commit ae236fb

5 files changed

Lines changed: 101 additions & 33 deletions

File tree

include/uapi/linux/tipc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ struct sockaddr_tipc {
238238
* Flag values
239239
*/
240240
#define TIPC_GROUP_LOOPBACK 0x1 /* Receive copy of sent msg when match */
241+
#define TIPC_GROUP_MEMBER_EVTS 0x2 /* Receive membership events in socket */
241242

242243
struct tipc_group_req {
243244
__u32 type; /* group id */

net/tipc/group.c

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ enum mbr_state {
5959
struct tipc_member {
6060
struct rb_node tree_node;
6161
struct list_head list;
62+
struct sk_buff *event_msg;
6263
u32 node;
6364
u32 port;
6465
u32 instance;
@@ -79,6 +80,7 @@ struct tipc_group {
7980
u16 member_cnt;
8081
u16 bc_snd_nxt;
8182
bool loopback;
83+
bool events;
8284
};
8385

8486
static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
@@ -117,6 +119,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid,
117119
grp->instance = mreq->instance;
118120
grp->scope = mreq->scope;
119121
grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
122+
grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
120123
if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, &grp->subid))
121124
return grp;
122125
kfree(grp);
@@ -279,6 +282,13 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
279282
if (!msg_in_group(hdr))
280283
goto drop;
281284

285+
if (mtyp == TIPC_GRP_MEMBER_EVT) {
286+
if (!grp->events)
287+
goto drop;
288+
__skb_queue_tail(inputq, skb);
289+
return;
290+
}
291+
282292
m = tipc_group_find_member(grp, node, port);
283293
if (!tipc_group_is_receiver(m))
284294
goto drop;
@@ -311,6 +321,7 @@ static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
311321
}
312322

313323
void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
324+
struct sk_buff_head *inputq,
314325
struct sk_buff_head *xmitq)
315326
{
316327
u32 node = msg_orignode(hdr);
@@ -332,10 +343,12 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
332343
m->bc_rcv_nxt = msg_grp_bc_syncpt(hdr);
333344

334345
/* Wait until PUBLISH event is received */
335-
if (m->state == MBR_DISCOVERED)
346+
if (m->state == MBR_DISCOVERED) {
336347
m->state = MBR_JOINING;
337-
else if (m->state == MBR_PUBLISHED)
348+
} else if (m->state == MBR_PUBLISHED) {
338349
m->state = MBR_JOINED;
350+
__skb_queue_tail(inputq, m->event_msg);
351+
}
339352
return;
340353
case GRP_LEAVE_MSG:
341354
if (!m)
@@ -347,23 +360,25 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
347360
return;
348361
}
349362
/* Otherwise deliver already received WITHDRAW event */
363+
__skb_queue_tail(inputq, m->event_msg);
350364
tipc_group_delete_member(grp, m);
351365
return;
352366
default:
353367
pr_warn("Received unknown GROUP_PROTO message\n");
354368
}
355369
}
356370

357-
/* tipc_group_member_evt() - receive and handle a member up/down event
358-
*/
359371
void tipc_group_member_evt(struct tipc_group *grp,
360372
struct sk_buff *skb,
373+
struct sk_buff_head *inputq,
361374
struct sk_buff_head *xmitq)
362375
{
363376
struct tipc_msg *hdr = buf_msg(skb);
364377
struct tipc_event *evt = (void *)msg_data(hdr);
378+
u32 instance = evt->found_lower;
365379
u32 node = evt->port.node;
366380
u32 port = evt->port.ref;
381+
int event = evt->event;
367382
struct tipc_member *m;
368383
struct net *net;
369384
u32 self;
@@ -376,32 +391,51 @@ void tipc_group_member_evt(struct tipc_group *grp,
376391
if (!grp->loopback && node == self && port == grp->portid)
377392
goto drop;
378393

394+
/* Convert message before delivery to user */
395+
msg_set_hdr_sz(hdr, GROUP_H_SIZE);
396+
msg_set_user(hdr, TIPC_CRITICAL_IMPORTANCE);
397+
msg_set_type(hdr, TIPC_GRP_MEMBER_EVT);
398+
msg_set_origport(hdr, port);
399+
msg_set_orignode(hdr, node);
400+
msg_set_nametype(hdr, grp->type);
401+
msg_set_grp_evt(hdr, event);
402+
379403
m = tipc_group_find_member(grp, node, port);
380404

381-
if (evt->event == TIPC_PUBLISHED) {
405+
if (event == TIPC_PUBLISHED) {
382406
if (!m)
383407
m = tipc_group_create_member(grp, node, port,
384408
MBR_DISCOVERED);
385409
if (!m)
386410
goto drop;
387411

388-
/* Wait if JOIN message not yet received */
389-
if (m->state == MBR_DISCOVERED)
412+
/* Hold back event if JOIN message not yet received */
413+
if (m->state == MBR_DISCOVERED) {
414+
m->event_msg = skb;
390415
m->state = MBR_PUBLISHED;
391-
else
416+
} else {
417+
__skb_queue_tail(inputq, skb);
392418
m->state = MBR_JOINED;
393-
m->instance = evt->found_lower;
419+
}
420+
m->instance = instance;
421+
TIPC_SKB_CB(skb)->orig_member = m->instance;
394422
tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
395-
} else if (evt->event == TIPC_WITHDRAWN) {
423+
} else if (event == TIPC_WITHDRAWN) {
396424
if (!m)
397425
goto drop;
398426

399-
/* Keep back event if more messages might be expected */
400-
if (m->state != MBR_LEAVING && tipc_node_is_up(net, node))
427+
TIPC_SKB_CB(skb)->orig_member = m->instance;
428+
429+
/* Hold back event if more messages might be expected */
430+
if (m->state != MBR_LEAVING && tipc_node_is_up(net, node)) {
431+
m->event_msg = skb;
401432
m->state = MBR_LEAVING;
402-
else
433+
} else {
434+
__skb_queue_tail(inputq, skb);
403435
tipc_group_delete_member(grp, m);
436+
}
404437
}
438+
return;
405439
drop:
406440
kfree_skb(skb);
407441
}

net/tipc/group.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ void tipc_group_filter_msg(struct tipc_group *grp,
5454
struct sk_buff_head *xmitq);
5555
void tipc_group_member_evt(struct tipc_group *grp,
5656
struct sk_buff *skb,
57+
struct sk_buff_head *inputq,
5758
struct sk_buff_head *xmitq);
5859
void tipc_group_proto_rcv(struct tipc_group *grp,
5960
struct tipc_msg *hdr,
61+
struct sk_buff_head *inputq,
6062
struct sk_buff_head *xmitq);
6163
void tipc_group_update_bc_members(struct tipc_group *grp);
6264
u16 tipc_group_bc_snd_nxt(struct tipc_group *grp);

net/tipc/msg.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ struct plist;
6565
#define TIPC_MCAST_MSG 1
6666
#define TIPC_NAMED_MSG 2
6767
#define TIPC_DIRECT_MSG 3
68-
#define TIPC_GRP_BCAST_MSG 4
68+
#define TIPC_GRP_MEMBER_EVT 4
69+
#define TIPC_GRP_BCAST_MSG 5
6970

7071
/*
7172
* Internal message users
@@ -258,7 +259,14 @@ static inline void msg_set_type(struct tipc_msg *m, u32 n)
258259

259260
static inline int msg_in_group(struct tipc_msg *m)
260261
{
261-
return (msg_type(m) == TIPC_GRP_BCAST_MSG);
262+
int mtyp = msg_type(m);
263+
264+
return (mtyp == TIPC_GRP_BCAST_MSG) || (mtyp == TIPC_GRP_MEMBER_EVT);
265+
}
266+
267+
static inline bool msg_is_grp_evt(struct tipc_msg *m)
268+
{
269+
return msg_type(m) == TIPC_GRP_MEMBER_EVT;
262270
}
263271

264272
static inline u32 msg_named(struct tipc_msg *m)
@@ -824,6 +832,16 @@ static inline void msg_set_grp_bc_syncpt(struct tipc_msg *m, u16 n)
824832

825833
/* Word 10
826834
*/
835+
static inline u16 msg_grp_evt(struct tipc_msg *m)
836+
{
837+
return msg_bits(m, 10, 0, 0x3);
838+
}
839+
840+
static inline void msg_set_grp_evt(struct tipc_msg *m, int n)
841+
{
842+
msg_set_bits(m, 10, 0, 0x3, n);
843+
}
844+
827845
static inline u16 msg_grp_bc_seqno(struct tipc_msg *m)
828846
{
829847
return msg_bits(m, 10, 16, 0xffff);

net/tipc/socket.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -709,41 +709,43 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
709709
poll_table *wait)
710710
{
711711
struct sock *sk = sock->sk;
712+
struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
712713
struct tipc_sock *tsk = tipc_sk(sk);
713714
struct tipc_group *grp = tsk->group;
714-
u32 mask = 0;
715+
u32 revents = 0;
715716

716717
sock_poll_wait(file, sk_sleep(sk), wait);
717718

718719
if (sk->sk_shutdown & RCV_SHUTDOWN)
719-
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
720+
revents |= POLLRDHUP | POLLIN | POLLRDNORM;
720721
if (sk->sk_shutdown == SHUTDOWN_MASK)
721-
mask |= POLLHUP;
722+
revents |= POLLHUP;
722723

723724
switch (sk->sk_state) {
724725
case TIPC_ESTABLISHED:
725726
if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
726-
mask |= POLLOUT;
727+
revents |= POLLOUT;
727728
/* fall thru' */
728729
case TIPC_LISTEN:
729730
case TIPC_CONNECTING:
730-
if (!skb_queue_empty(&sk->sk_receive_queue))
731-
mask |= (POLLIN | POLLRDNORM);
731+
if (skb)
732+
revents |= POLLIN | POLLRDNORM;
732733
break;
733734
case TIPC_OPEN:
734735
if (!grp || tipc_group_size(grp))
735736
if (!tsk->cong_link_cnt)
736-
mask |= POLLOUT;
737-
if (tipc_sk_type_connectionless(sk) &&
738-
(!skb_queue_empty(&sk->sk_receive_queue)))
739-
mask |= (POLLIN | POLLRDNORM);
737+
revents |= POLLOUT;
738+
if (!tipc_sk_type_connectionless(sk))
739+
break;
740+
if (!skb)
741+
break;
742+
revents |= POLLIN | POLLRDNORM;
740743
break;
741744
case TIPC_DISCONNECTING:
742-
mask = (POLLIN | POLLRDNORM | POLLHUP);
745+
revents = POLLIN | POLLRDNORM | POLLHUP;
743746
break;
744747
}
745-
746-
return mask;
748+
return revents;
747749
}
748750

749751
/**
@@ -1415,11 +1417,12 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
14151417
size_t buflen, int flags)
14161418
{
14171419
struct sock *sk = sock->sk;
1418-
struct tipc_sock *tsk = tipc_sk(sk);
1419-
struct sk_buff *skb;
1420-
struct tipc_msg *hdr;
14211420
bool connected = !tipc_sk_type_connectionless(sk);
1421+
struct tipc_sock *tsk = tipc_sk(sk);
14221422
int rc, err, hlen, dlen, copy;
1423+
struct tipc_msg *hdr;
1424+
struct sk_buff *skb;
1425+
bool grp_evt;
14231426
long timeout;
14241427

14251428
/* Catch invalid receive requests */
@@ -1443,6 +1446,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
14431446
dlen = msg_data_sz(hdr);
14441447
hlen = msg_hdr_sz(hdr);
14451448
err = msg_errcode(hdr);
1449+
grp_evt = msg_is_grp_evt(hdr);
14461450
if (likely(dlen || err))
14471451
break;
14481452
tsk_advance_rx_queue(sk);
@@ -1469,11 +1473,20 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
14691473
if (unlikely(rc))
14701474
goto exit;
14711475

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+
14721484
/* Caption of data or error code/rejected data was successful */
14731485
if (unlikely(flags & MSG_PEEK))
14741486
goto exit;
14751487

14761488
tsk_advance_rx_queue(sk);
1489+
14771490
if (likely(!connected))
14781491
goto exit;
14791492

@@ -1648,10 +1661,10 @@ static void tipc_sk_proto_rcv(struct sock *sk,
16481661
sk->sk_write_space(sk);
16491662
break;
16501663
case GROUP_PROTOCOL:
1651-
tipc_group_proto_rcv(grp, hdr, xmitq);
1664+
tipc_group_proto_rcv(grp, hdr, inputq, xmitq);
16521665
break;
16531666
case TOP_SRV:
1654-
tipc_group_member_evt(tsk->group, skb, xmitq);
1667+
tipc_group_member_evt(tsk->group, skb, inputq, xmitq);
16551668
skb = NULL;
16561669
break;
16571670
default:

0 commit comments

Comments
 (0)